亚马逊AWS官方博客

Codepipeline跨账号访问Codecommit

背景

大型企业中代码仓库通常存放在各部门开发账户中,而流水线则位于独立DevOps账户中。

本文我们将介绍如何创建跨账号访问Codecommit代码仓库的Codepipeline流水线,即CodePipeline调用另一个账号中的Codecommit代码仓库。

部署架构图

权限配置

  1. CodePipeline 执行role – CodePipelineServiceRole,关键IAM Policy:允许CodePipeline assume account B中的角色“AssumeAdminRole”。
  2. AssumeAdminRole – CodePipeline-SourceStage实际执行role, 添加policy以具有以下权限
    • 允许被Account A中CodePipeline Assume
    • 允许访问本账户中的CodeCommit
    • 允许访问Account A中的S3桶(存放sourceArtifact)
    • 允许访问Account A中的KMS
  3. 配置KMS Policy, 允许CodePipelineServiceRole和AssumeAdminRole访问kms中相应的key
  4. 配置S3 Bucket Policy,允许AssumeAdminRole访问S3中相应的bucket
  5. CodeBuild执行role,可配置为自动生成,不是本文重点

流水线执行过程

  1. 触发流水线
  2. SourceStage中首先assume AssumeAdminRole,获得访问CodeCommit权限
  3. 从AccountB CodeCommit代码仓库拉取代码
  4. 将放sourceArtifact存入S3桶
  5. S3服务端加密
  6. 执行Build Stage: CodeBuild

账号准备

选择您所在的region,本文以北京Region为例。

准备两个AWS主账号:

  • 代码仓库账号B:提供Codecommit服务,源代码放在这里。
  • pipeline账号A:提供Codepipeline服务,以及相关联的codebuild、kms密钥和s3桶

代码仓库账号B

一、创建跨账号IAM Role

该Role命名为assume-admin-role,使用权限如下:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "kms:Decrypt",
                "kms:Encrypt",
                "kms:DescribeKey",
                "s3:GetObject*",
                "s3:PutObjectAcl",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*"
            ],
            "Resource": [
                " arn:aws-cn:kms:cn-north-1:<Account_A_ID>:key/XXX-XXX-XXX-XXX ",
                "arn:aws-cn:s3:::codecommit-sdv-cross-account/*"
            ]
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": [
                "codecommit:List*"
            ],
            "Resource": "arn:aws-cn:s3:::codecommit-sdv-cross-account/*"
        }
    ]
}

该Role的信任关系如下:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws-cn:iam::<Account_A_ID>:root"
                ]
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

二、创建CodeCommit Repository

该Repo命名为:cros-account-b-repo,并在该Repo中创建文件demo.txt。

 

流水线账号A

三、创建Codepipeline IAM Role

创建IAM Role,名为:AWSCodePipelineServiceRole-cn-north-1-sdv-pipeline-cros,为Codepipeline的创建做准备。

该role关联Codepipeline默认Role的权限策略,具体如下:

{
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "iam:PassRole"
            ],
            "Resource": "*",
            "Condition": {
                "StringEqualsIfExists": {
                    "iam:PassedToService": [
                        "cloudformation.amazonaws.com",
                        "elasticbeanstalk.amazonaws.com",
                        "ec2.amazonaws.com",
                        "ecs-tasks.amazonaws.com"
                    ]
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": [
                "codecommit:CancelUploadArchive",
                "codecommit:GetBranch",
                "codecommit:GetCommit",
                "codecommit:GetRepository",
                "codecommit:GetUploadArchiveStatus",
                "codecommit:UploadArchive"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "codedeploy:CreateDeployment",
                "codedeploy:GetApplication",
                "codedeploy:GetApplicationRevision",
                "codedeploy:GetDeployment",
                "codedeploy:GetDeploymentConfig",
                "codedeploy:RegisterApplicationRevision"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "elasticbeanstalk:*",
                "ec2:*",
                "elasticloadbalancing:*",
                "autoscaling:*",
                "cloudwatch:*",
                "s3:*",
                "sns:*",
                "cloudformation:*",
                "rds:*",
                "sqs:*",
                "ecs:*"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "lambda:InvokeFunction",
                "lambda:ListFunctions"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "cloudformation:CreateStack",
                "cloudformation:DeleteStack",
                "cloudformation:DescribeStacks",
                "cloudformation:UpdateStack",
                "cloudformation:CreateChangeSet",
                "cloudformation:DeleteChangeSet",
                "cloudformation:DescribeChangeSet",
                "cloudformation:ExecuteChangeSet",
                "cloudformation:SetStackPolicy",
                "cloudformation:ValidateTemplate"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "codebuild:BatchGetBuilds",
                "codebuild:StartBuild",
                "codebuild:BatchGetBuildBatches",
                "codebuild:StartBuildBatch"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "servicecatalog:ListProvisioningArtifacts",
                "servicecatalog:CreateProvisioningArtifact",
                "servicecatalog:DescribeProvisioningArtifact",
                "servicecatalog:DeleteProvisioningArtifact",
                "servicecatalog:UpdateProduct"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "cloudformation:ValidateTemplate"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "ecr:DescribeImages"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "states:DescribeExecution",
                "states:DescribeStateMachine",
                "states:StartExecution"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "appconfig:StartDeployment",
                "appconfig:StopDeployment",
                "appconfig:GetDeployment"
            ],
            "Resource": "*"
        }
    ],
    "Version": "2012-10-17"
}

除了默认权限策略,为了提供跨账号调用,该Role还需要加入如下权限策略:

{
    "Version": "2012-10-17",
    "Statement": {
        "Effect": "Allow",
        "Action": "sts:AssumeRole",
        "Resource": [
            "arn:aws-cn:iam::<Account_B_ID>:role/*"
        ]
    }
}

四、创建KMS秘钥

创建名为:account_a_cros_kms的KMS秘钥。

在定义秘钥使用权限时,需要加入Codepipeline所关联的Role(上一步创建名为:AWSCodePipelineServiceRole-cn-north-1-sdv-pipeline-cros的IAM Role)和Account B的账号ID。记录KMS ARN为:arn:aws-cn:kms:cn-north-1:<Account_A_ID>:key/XXX-XXX-XXX-XXX

五、创建S3桶

这里创建名为:codecommit-sdv-cross-account的S3桶。

这里S3桶命名为 codecommit-sdv-cross-account。然后编辑存储桶权限,即权限->存储通权限,点击编辑按钮,添加如下policy json:

{
"Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Statement1",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws-cn:iam::<Account_B_ID>:root"
            },
            "Action": [
                "s3:Get*",
                "s3:Put*"
            ],
            "Resource": "arn:aws-cn:s3:::codecommit-sdv-cross-account/*"
        },
        {
            "Sid": "Statement2",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws-cn:iam:: <Account_B_ID>:root"
            },
            "Action": "s3:ListBucket",
            "Resource": "arn:aws-cn:s3:::codecommit-sdv-cross-account"
        }
    ]
}

六、创建CodeBuild

创建名为:sdv-build的codebuild项目,供codepipeline调用。

在Buildspec中添加命令如下:

七、创建Codepipeline

对于跨账号调用Codecommit的Codepipeline只能通过AWS CLI创建,准备如下pipeline.json文件,

{
    "pipeline": {
        "roleArn": "arn:aws-cn:iam::<Account_A_ID>:role/service-role/AWSCodePipelineServiceRole-cn-north-1-sdv-pipeline-cros", 
        "stages": [
            {
                "name": "Source", 
                "actions": [
                    {
                        "inputArtifacts": [], 
                        "name": "Source", 
                        "region": "cn-north-1", 
                        "namespace": "SourceVariables", 
                        "actionTypeId": {
                            "category": "Source", 
                            "owner": "AWS", 
                            "version": "1", 
                            "provider": "CodeCommit"
                        }, 
                        "outputArtifacts": [
                            {
                                "name": "SourceArtifact"
                            }
                        ], 
                        "roleArn":"arn:aws-cn:iam::<Account_B_ID>:role/assume-admin-role",
                        "configuration": {
                            "BranchName": "master", 
                            "PollForSourceChanges": "false", 
                            "RepositoryName": "cros-account-b-repo"
                        }, 
                        "runOrder": 1
                    }
                ]
            }, 
            {
                "name": "Build", 
                "actions": [
                    {
                        "inputArtifacts": [
                            {
                                "name": "SourceArtifact"
                            }
                        ], 
                        "name": "Build", 
                        "region": "cn-north-1", 
                        "namespace": "BuildVariables", 
                        "actionTypeId": {
                            "category": "Build", 
                            "owner": "AWS", 
                            "version": "1", 
                            "provider": "CodeBuild"
                        }, 
                        "outputArtifacts": [
                            {
                                "name": "BuildArtifact"
                            }
                        ], 
                        "configuration": {
                            "ProjectName": "sdv-build"
                        }, 
                        "runOrder": 1
                    }
                ]
            }
        ], 
        "artifactStore": {
            "type": "S3", 
            "location": "codecommit-sdv-cross-account",
            "encryptionKey": {
               "id": " arn:aws-cn:kms:cn-north-1:<Account_A_ID>:key/XXX-XXX-XXX-XXX ",
               "type": "KMS"
            }
       },
        "name": "pipeline-cros", 
        "version": 1
    }
}

这里计划在Account A创建名为pipeline-cros的codepipeline,该pipeline以Account B的codecommit repo: cros-account-b-repo (master branch)作为源,并利用预先准备好的位于Account A的codebuild进行流水线的执行。

使用如上Json,并利用AWS cli执行命令如下:

aws codepipeline create-pipeline –cli-input-json file://pipeline.json # 创建pipeline

同时codebuild会打印日志如下:

……
[Container] 2022/07/18 03:23:11 Entering phase BUILD
[Container] 2022/07/18 03:23:11 Running command ls
demo.txt
[Container] 2022/07/18 03:23:11 Phase complete: BUILD State: SUCCEEDED
……

本篇作者

王帅

AWS专业服务团队Devops顾问。提倡融合文化,实践和工具的Devops理念,致力于帮助客户使组织能够以更高的速度和可靠性交付产品并获得业务价值。擅长平台规划,迁移和工具链设计。对新鲜事物充满热情

冯霄鹏

AWS专业服务团队高级DevOps顾问。主要负责DevOps咨询和技术实施。在DevSecOps加速企业数字化转型方面领域拥有多年经验,对公有云、DevOps、基于云原生的微服务架构、敏捷加速研发效能等有深入的研究和热情。