以跨账户 CodeCommit 存储库作为源的 AWS 管道

AWS pipeline with cross-account CodeCommit repo as Source

我需要使用 CDK 创建一个管道,该管道将基于 CodeCommit 存储库中的分支触发 CloudFormation 中的部署。如果 CodeCommit 存储库与管道在同一个帐户中,我会使用如下内容:

const codecommitRepo = codecommit.Repository.fromRepositoryName(
  this,
  'AppRepository',
  'REPO_NAME'
);

pipeline.addStage({
  stageName: 'Source',
  actions: [
    new codepipeline_actions.CodeCommitSourceAction({
      actionName: 'Source',
      repository: codecommitRepo,
      branch: 'BRANCH_NAME',
      output: sourceArtifact,
    }),
  ],
});

但是,如果 CodeCommit 存储库在不同的帐户中怎么办?

我尝试重新创建的架构类似于 this article(下图)中显示的架构,但使用了 CDK 和 CloudFormation。

我该如何创建它?

CodePipeline (CP) 由 CC 通过 CloudWatch 事件规则 触发,当两者都在同一帐户中时:

CC ---> CW Event rule ---> CP

要跨帐户执行此操作,您必须调整 CW 事件。即,CC 账户中的 CW 事件规则必须将事件转发到 CP 账户中的 CW 事件:

CP ---> CW Event rule ---> CW Event bus in CP acc ---> CW rule --> CP 

我没有适合您的代码,但应该这样做。您提供的 link 提供了此架构的更多具体细节。

我想当使用 CDK 时,您将不得不“手动”创建所有 CW 事件规则,因为这不是通常开箱即用的事情。

如果有人有同样的问题,我设法用CDK和this example. It's outdated but I applied the same logic. Probably some of the steps mentioned in this answer are not necesary because of recent changes. I found a more recent example here解决了,但我还没有尝试过。

重要提示:确保两个账户中的资源在同一地区。

让我们调用 ID_ACC_WITH_REPO 到带有 CodeCommit 存储库的 AWS 账户 ID 和 ID_ACC_WITH_PIPELINE 到带有管道的账户 ID 以及我们想要部署架构的位置。

流水线的 CDK 代码

ACC_WITH_REPO

  1. 在 ID_ACC_WITH_REPO 中创建堆栈。必须指定区域 ,因为 cross-account 管道需要它。
const repoAccStack = new cdk.Stack(app, 'RepoAccStack', {
    env: {
        account: ID_ACC_WITH_REPO,
        region: REPO_REGION
    }
});
  1. 在 ACC_WITH_REPO 中创建一个 cross-account 角色并附加 S3(用于存储工件)、CodeCommit 和 KMS(加密)的完整访问策略。该角色将由 ACC_WITH_PIPELINE 中的管道和源阶段中的 CodeCommit 源操作使用。我想您可以对它们进行更多限制以更加安全。
// Create role
const crossAccRole = new iam.Role(repoAccStack, 'OtherAccRole', {
    roleName: 'CrossAccountRole',
    assumedBy: new iam.AccountPrincipal(pipelineAcc),
});

// Attach policies
const policy = new iam.PolicyStatement();
policy.addAllResources();
policy.addActions('s3:*', 'codecommit:*', 'kms:*');
crossAccRole.addToPolicy(policy);
  1. 导入存储库。
const repo = codecommit.Repository.fromRepositoryArn(
  repoAccStack,
  'AppRepository',
  `arn:aws:codecommit:${REPO_REGION}:${ID_ACC_WITH_REPO}:${REPO_NAME}`
);

ACC_WITH_PIPELINE

  1. 为 ID_ACC_WITH_PIPELINE 中的管道创建堆栈。
const pipelineAccStack = new cdk.Stack(app, 'PipelineAccStack', {
    env: {
        account: ID_ACC_WITH_PIPELINE,
        region: REGION_WITH_PIPELINE
    }
});
  1. 创建 KMS 密钥。示例中使用的方法 EncryptionKey 已弃用,请改用 Key
const key = new kms.Key(pipelineAccStack, 'CrossAccountKmsKey');

实际上我在尝试创建密钥时遇到了 kms.model.MalformedPolicyDocumentException 错误,所以我从 AWS 控制台手动完成,然后使用 kms.Key.fromKeyArn 导入它。我的帐户可能有问题(在使用此解决方案之前我遇到了很多错误),但如果您遇到相同的错误,这是一种解决方法。只需确保为管道角色分配使用权限即可。

  1. 使用之前创建的 KMS 在 ACC_WITH_PIPELINE 中创建 S3 存储桶。需要存储桶名称。示例中使用的 HackyIdentity 不是必需的,class 实现中使用的几种方法现已弃用。
const artifactsBucket = new s3.Bucket(pipelineAccStack, "ArtifactsBucket", {
    bucketName: BUCKET_NAME,
    encryptionKey: key,
    encryption: s3.BucketEncryption.KMS
});

artifactsBucket.grantReadWrite(new iam.ArnPrincipal(crossAccRole.roleArn));
  1. 创建管道并添加在步骤 5 中创建的 cross-account 角色。
// Create pipeline
const pipeline = new codepipeline.Pipeline(pipelineAccStack, 'Pipeline', {
    pipelineName: 'CrossAccountPipeline',
    artifactBucket: artifactsBucket
});

// Add cross-account role
const policy = new iam.PolicyStatement();
policy.addResources(crossAccRole.roleArn)
policy.addActions('s3:*', 'codecommit:*', 'kms:*');
pipeline.addToRolePolicy(policy);
  1. 使用步骤 3 中导入的 CodeCommit 存储库将源阶段添加到管道。
// Create artifact for source code
const sourceArtifact = new codepipeline.Artifact();

// Create source stage with role
pipeline.addStage({
  stageName: 'Source',
  actions: [
    new codepipeline_actions.CodeCommitSourceAction({
      actionName: 'CodeCommit_Source',
      repository: repo,
      output: sourceArtifact,
      branch: 'dev',
      role: crossAccRole
    })
  ]
});
  1. 最后添加构建阶段
// Create CodeBuild project
const buildProject = new codebuild.PipelineProject(this, 'Build', {
  environment: { buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_2 }
});

// Create artifact for build
const buildArtifact = new codepipeline.Artifact();

// Add build stage
pipeline.addStage({
  stageName: 'Build',
  actions: [
    new codepipeline_actions.CodeBuildAction({
      actionName: 'Build',
      project: buildProject,
      input: sourceArtifact,
      outputs: [buildArtifact],
    }),
  ],
});

部署

当 CDK 应用程序包含多个堆栈时,您不能只 cdk deployhere 中对此进行了解释。但是,如果您尝试 cdk deploy '*',则会出现另一个错误:Need to perform AWS calls for account ACCOUNT_ID, but the current credentials are for ACCOUNT_ID.

我设法使用 cdk deploy -e 部署堆栈并使用 aws configure 切换帐户。 有三个堆栈,而不是两个。 EventBusPolicy 堆栈由 CDK 自动生成以创建事件总线。另外两个事件由 CDK 添加(也自动)在 PipelineAccStack 和 RepoAccStack 中。 Marcin 的回答解释了 cross-account 事件是如何配置的。 EventBusPolicy 堆栈应在 ACC_WITH_PIPELINE 中创建。要获取堆栈的确切名称,请使用 cdk list.

考虑到所有这些,在这个例子中我将部署:

# with aws configure in ACC_WITH_PIPELINE
cdk deploy -e "PipelineAccStack"
cdk deploy -e "EventBusPolicy-$ID_ACC_WITH_REPO-$REGION-$ID_ACC_WITH_PIPELINE"

# switch aws configure to ACC_WITH_REPO
cdk deploy -e "RepoAccStack"