AWS CodePipeline для нескольких учетных записей не может получить доступ к артефактам развертывания CloudFormation - PullRequest
0 голосов
/ 19 декабря 2018

У меня есть конвейер кросс-учетной записи, работающий в учетной записи CI , развертывание ресурсов через CloudFormation в другой учетной записи DEV .После развертывания я сохраняю выходные данные артефакта в виде файла JSON и хочу получить к нему доступ в другом действии конвейера через CodeBuild.CodeBuild завершается с ошибкой в ​​фазе DOWNLOAD_SOURCE со следующим сообщением:

CLIENT_ERROR: AccessDenied: код статуса доступа запрещен: 403, идентификатор запроса: 123456789, идентификатор хоста: xxxxx / yyyy / zzzz / xxxx = для основного источникаи исходная версия arn: aws: s3 ::: my-bucket / my-pipeline / DeployArti / XcUNqOP

Вероятно, проблема в том, что CloudFormation при выполнении в другой учетной записи шифрует артефакты с помощьюключ, отличный от самого конвейера.

Можно ли дать CloudFormation явный ключ KMS для шифрования артефактов или каким-либо другим способом получить доступ к этим артефактам обратно в конвейер?

Все работает, когда выполняется из одной учетной записи.

Вот мой фрагмент кода (развернут в учетной записи 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

Ответы [ 3 ]

0 голосов
/ 15 января 2019

CloudFormation должен использовать ключ шифрования KMS, указанный в определении хранилища артефактов вашего конвейера: https://docs.aws.amazon.com/codepipeline/latest/APIReference/API_ArtifactStore.html#CodePipeline-Type-ArtifactStore-encryptionKey

Следовательно, до тех пор, пока вы предоставляете ему собственный ключ и разрешаете другой учетной записи использовать этот ключтоже должно работать.

В основном это рассматривается в этом документе: https://docs.aws.amazon.com/codepipeline/latest/userguide/pipelines-create-cross-account.html

0 голосов
/ 17 июня 2019

mockora ответ правильный.Ниже приведен пример лямбда-функции в Python, которая устраняет проблему, которую можно настроить как действие Invoke сразу после развертывания CloudFormation на нескольких учетных записях.

В этом примере вы настраиваете параметры пользователя действия вызова Lambda в качестве параметраARN роли, которую вы хотите, чтобы лямбда-функция выполняла в удаленной учетной записи для исправления ACL-объекта S3.Очевидно, что вашей лямбда-функции потребуются разрешения sts:AssumeRole для этой роли, а роли удаленной учетной записи понадобятся разрешения s3:PutObjectAcl для артефактов сегмента конвейера.

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))}
    )
0 голосов
/ 20 декабря 2018

CloudFormation генерирует выходной артефакт, архивирует его и затем загружает файл в S3.Он не добавляет ACL, который предоставляет доступ владельцу корзины.Таким образом, вы получаете 403, когда пытаетесь использовать выходной артефакт CloudFormation дальше по конвейеру.

Обходной путь - это иметь еще одно действие в вашем конвейере сразу после действия CLoudFormation для функции ex: Lambda, которая может принять цельроль учетной записи и обновите объект acl ex: bucket-owner-full-control.

...