Multicomptes AWS CodePipeline ne peut pas accéder à CloudFormation déployer des artefacts

voix
0

J'ai un pipeline transcanadien compte en cours d' exécution dans un CI compte des ressources via le déploiement CloudFormation dans un autre compte DEV . Après avoir déployé je sauvegarde les sorties d'artefact en tant que fichier JSON et que vous souhaitez y accéder dans une autre action de pipeline via CodeBuild. CodeBuild échoue dans la DOWNLOAD_SOURCE de phase avec le messsage suivant:

CLIENT_ERROR: AccessDenied: Accès refusé Code d'état: 403, id demande: 123456789, ID d'hôte: xxxxx / aaaa / zzzz / xxxx = pour la source primaire et la version source arn: aws: s3 ::: mon seau / ma-pipeline / DeployArti / XcUNqOP

Le problème est probable que le CloudFormation, lorsqu'il est exécuté dans un autre compte, cryptez les objets avec une clé différente de celle du pipeline lui-même.

Est-il possible de donner la CloudFormation une clé KMS explicite pour chiffrer les artefacts avec, ou de toute autre manière comment accéder à ces artefacts en arrière dans le pipeline?

Tout fonctionne lorsqu'il est exécuté à partir d'un seul compte.

Voici mon extrait de code (déployé dans le compte de 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
Créé 19/12/2018 à 14:21
source utilisateur
Dans d'autres langues...                            


3 réponses

voix
2

CloudFormation génère l'artefact de sortie, il zips et télécharge le fichier à S3. Il n'ajoute pas ACL, qui donne accès au propriétaire du seau. Ainsi, vous obtenez 403 lorsque vous essayez d'utiliser l'artefact sortie CloudFormation en aval de la canalisation.

solution de contournement est d'avoir une action supplémentaire dans votre pipeline immédiatement après l'action CloudFormation par ex: fonction Lambda qui peut assumer le rôle de compte cible et mettre à jour l'objet acl ex: seau propriétaire-plein contrôle.

Créé 20/12/2018 à 00:34
source utilisateur

voix
0

La réponse de mockora est correcte. Voici un exemple fonction Lambda en Python qui résout le problème, que vous pouvez configurer comme une action Invoke immédiatement après votre déploiement croix compte CloudFormation.

Dans cet exemple, vous configurez le paramètre de paramètres utilisateur d'action Invoke Lambda comme du rôle ARN que vous voulez que la fonction Lambda à assumer compte à distance pour fixer l'objet S3 ACL. De toute évidence , votre fonction Lambda aura besoin d' sts:AssumeRoleautorisations pour ce rôle, et le rôle de compte à distance aura besoin d' s3:PutObjectAclautorisations sur l'artefact du godet de pipeline (s).

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))}
    )
Créé 17/06/2019 à 11:31
source utilisateur

voix
-1

CloudFormation doit utiliser la clé de chiffrement KMS fourni dans la définition du magasin d'artefact de votre pipeline: https://docs.aws.amazon.com/codepipeline/latest/APIReference/API_ArtifactStore.html#CodePipeline-Type-ArtifactStore-encryptionKey

Par conséquent, tant que vous lui donnez une clé personnalisée il et permettre à l'autre compte utiliser cette clé aussi, il devrait fonctionner.

Cela est principalement couvert dans ce document: https://docs.aws.amazon.com/codepipeline/latest/userguide/pipelines-create-cross-account.html

Créé 15/01/2019 à 00:24
source utilisateur

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