Cruz-cuenta de AWS CodePipeline no puede acceder CloudFormation desplegar artefactos

votos
0

Tengo una tubería de varias cuentas que se ejecuta en un CI cuenta el despliegue de recursos a través de CloudFormation en otra cuenta DEV . Después de desplegar puedo guardar las salidas de artefactos como un archivo JSON y quiero acceder a él en otra acción a través de la tubería CodeBuild. CodeBuild falla en el DOWNLOAD_SOURCE fase con la siguiente messsage:

CLIENT_ERROR: AccessDenied: código de estado de acceso denegado: 403, petición ID: 123456789, identificador de host: xxxxx / aaaa / zzzz / xxxx = para la fuente principal y la versión fuente de ARN: AWS: S3 ::: mi-cubo / mi-ducto / DeployArti / XcUNqOP

El problema es probable que el CloudFormation, cuando se ejecuta en una cuenta diferente, cifrar los artefactos con una clave diferente a la propia tubería.

¿Es posible dar a la CloudFormation una clave KMS explícitas para cifrar los artefactos con, o cualquier otra forma de cómo acceder a esos artefactos de vuelta en la tubería?

Todo funciona cuando se ejecuta desde dentro de una sola cuenta.

Aquí está mi fragmento de código (desplegado en la cuenta CI):

  MyCodeBuild:
    Type: AWS::CodeBuild::Project
    Properties:
      Artifacts:
        Type: CODEPIPELINE
      Environment: ...
      Name: !Sub my-codebuild
      ServiceRole: !Ref CodeBuildRole
      EncryptionKey: !GetAtt KMSKey.Arn
      Source:
        Type: CODEPIPELINE
        BuildSpec: ...

  CrossAccountCodePipeline:
    Type: AWS::CodePipeline::Pipeline
    Properties:
      Name: my-pipeline
      RoleArn: !GetAtt CodePipelineRole.Arn
      Stages:
      - Name: Source
        ...
      - Name: StagingDev
        Actions:
        - Name: create-stack-in-DEV-account
          InputArtifacts:
          - Name: SourceArtifact
          OutputArtifacts:
          - Name: DeployArtifact
          ActionTypeId:
            Category: Deploy
            Owner: AWS
            Version: 1
            Provider: CloudFormation
          Configuration:
            StackName: my-dev-stack
            ChangeSetName: !Sub my-changeset
            ActionMode: CREATE_UPDATE
            Capabilities: CAPABILITY_NAMED_IAM
            # this is the artifact I want to access from the next action 
            # within this CI account pipeline
            OutputFileName: my-DEV-output.json   
            TemplatePath: !Sub SourceArtifact::stack/my-stack.yml
            RoleArn: !Sub arn:aws:iam::${DevAccountId}:role/dev-cloudformation-role
          RoleArn: !Sub arn:aws:iam::${DevAccountId}:role/dev-cross-account-role
          RunOrder: 1
        - Name: process-DEV-outputs
          InputArtifacts:
          - Name: DeployArtifact
          ActionTypeId:
            Category: Build
            Owner: AWS
            Version: 1
            Provider: CodeBuild
          Configuration:
            ProjectName: !Ref MyCodeBuild
          RunOrder: 2
      ArtifactStore:
        Type: S3
        Location: !Ref S3ArtifactBucket
        EncryptionKey:
          Id: !GetAtt KMSKey.Arn
          Type: KMS
Publicado el 19/12/2018 a las 14:21
fuente por usuario
En otros idiomas...                            


3 respuestas

votos
2

CloudFormation genera artefacto de salida, cremalleras y luego sube el archivo a S3. No añade ACL, que otorga acceso al propietario del depósito. Así, se obtiene un 403 cuando intenta utilizar la salida CloudFormation artefacto más abajo en la tubería.

solución es tener una acción más en su tubería inmediatamente después de la acción CloudFormation por ejemplo: la función lambda que puede asumir el papel de cuenta de destino y actualizar el objeto ACL por ejemplo: control total--cubo-propietario.

Respondida el 20/12/2018 a las 00:34
fuente por usuario

votos
0

La respuesta de mockora es correcta. Este es un ejemplo de función Lambda en Python que corrige el problema, que se puede configurar como una acción de invocación inmediatamente después de la implementación de la cuenta CloudFormation cruz.

En este ejemplo, se configura la acción de invocación ajuste de parámetros de usuario Lambda como el ARN de la función que desea la función de Lambda para asumir en cuenta remota para fijar el objeto ACL S3. Obviamente su función Lambda tendrá sts:AssumeRolepermisos para ese papel, y el papel de cuenta remoto necesitará s3:PutObjectAclpermisos en el artefacto (s) tubería de cubo.

import os
import logging, datetime, json
import boto3
from aws_xray_sdk.core import xray_recorder
from aws_xray_sdk.core import patch_all

# X-Ray
patch_all()

# Configure logging
logging.basicConfig()
log = logging.getLogger()
log.setLevel(os.environ.get('LOG_LEVEL','INFO'))
def format_json(data):
  return json.dumps(data, default=lambda d: d.isoformat() if isinstance(d, datetime.datetime) else str(d))

# Boto3 Client
client = boto3.client
codepipeline = client('codepipeline')
sts = client('sts')

# S3 Object ACLs Handler
def s3_acl_handler(event, context):
  log.info(f'Received event: {format_json(event)}')
  # Get Job
  jobId = event['CodePipeline.job']['id']
  jobData = event['CodePipeline.job']['data']
  # Ensure we return a success or failure result
  try:
    # Assume IAM role from user parameters
    credentials = sts.assume_role(
      RoleArn=jobData['actionConfiguration']['configuration']['UserParameters'],
      RoleSessionName='codepipeline',
      DurationSeconds=900
    )['Credentials']
    # Create S3 client from assumed role credentials
    s3 = client('s3',
      aws_access_key_id=credentials['AccessKeyId'],
      aws_secret_access_key=credentials['SecretAccessKey'],
      aws_session_token=credentials['SessionToken']
    )
    # Set S3 object ACL for each input artifact
    for inputArtifact in jobData['inputArtifacts']:
      s3.put_object_acl(
        ACL='bucket-owner-full-control',
        Bucket=inputArtifact['location']['s3Location']['bucketName'],
        Key=inputArtifact['location']['s3Location']['objectKey']
      )
    codepipeline.put_job_success_result(jobId=jobId)
  except Exception as e:
    logging.exception('An exception occurred')
    codepipeline.put_job_failure_result(
      jobId=jobId,
      failureDetails={'type': 'JobFailed','message': getattr(e, 'message', repr(e))}
    )
Respondida el 17/06/2019 a las 11:31
fuente por usuario

votos
-1

CloudFormation debe utilizar la clave de cifrado KMS proporcionado en la tienda definición artefacto de su tubería: https://docs.aws.amazon.com/codepipeline/latest/APIReference/API_ArtifactStore.html#CodePipeline-Type-ArtifactStore-encryptionKey

Por lo tanto, siempre y cuando se le da una clave personalizada allí y permitir que la otra cuenta para utilizar esa clave también debería funcionar.

Esto se trata en su mayoría en este documento: https://docs.aws.amazon.com/codepipeline/latest/userguide/pipelines-create-cross-account.html

Respondida el 15/01/2019 a las 00:24
fuente por usuario

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more