背景
大型企业中代码仓库通常存放在各部门开发账户中,而流水线则位于独立DevOps账户中。
本文我们将介绍如何创建跨账号访问Codecommit代码仓库的Codepipeline流水线,即CodePipeline调用另一个账号中的Codecommit代码仓库。
部署架构图
权限配置
- CodePipeline 执行role – CodePipelineServiceRole,关键IAM Policy:允许CodePipeline assume account B中的角色“AssumeAdminRole”。
- AssumeAdminRole – CodePipeline-SourceStage实际执行role, 添加policy以具有以下权限
- 允许被Account A中CodePipeline Assume
- 允许访问本账户中的CodeCommit
- 允许访问Account A中的S3桶(存放sourceArtifact)
- 允许访问Account A中的KMS
- 配置KMS Policy, 允许CodePipelineServiceRole和AssumeAdminRole访问kms中相应的key
- 配置S3 Bucket Policy,允许AssumeAdminRole访问S3中相应的bucket
- CodeBuild执行role,可配置为自动生成,不是本文重点
流水线执行过程
- 触发流水线
- SourceStage中首先assume AssumeAdminRole,获得访问CodeCommit权限
- 从AccountB CodeCommit代码仓库拉取代码
- 将放sourceArtifact存入S3桶
- S3服务端加密
- 执行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
……
本篇作者