CodePipeline Deploy Cross Account

tuimac
6 min readSep 5, 2021

You develop a small application much faster than ever before on AWS, you will possibly choose CodeStar. CodeStar creates an environment to develop applications with few clicks, that was so faster than any other way. If you create CodeStar on your AWS, CodeStar creates a code repository, pipeline, artifact repository, and so on. Then the pipeline is created by CodeStar is a single simple template CodePipeline so you need to customize that if your development environment, staging, and production one are separated by each AWS account.

At this time, I write down here how you customize the CodePipeline to deploy on other AWS account by Cloudformation.
To be a simple explanation, consider a simple environment like below

  • Need three AWS accounts, development, staging, and production
  • Clone pipeline from the pipeline generated by CodeStar
  • Deploy to AWS Lambda by Cloudformation

An entire architecture diagram is below.

#1 Create CodeStar

First things first, you create CodeStar’s project. In this case, I create a Java project to be deployed by Cloudformation.

#2 Create Customer Managed Key(CMK)

You need to create a Customer Managed Key on development AWS account to share with staging and production AWS account. When CodeDeploy within Cloudformation deploys the Java program to AWS Lambda, CodeDeploy on staging and production AWS account pull an artifact of the Java program from the S3 bucket for artifact then CodeDeploy uses the CMK to decode the artifact.

#3 Clone CodePipeline for other AWS account

You clone CodePipeline on the development AWS account for staging and production AWS account. Before doing that, you should set up the branch for each account on CodeCommit. There is a single pipeline for the development account that was created by CodeStar, so clone from that.
The ‘Branch name’ in the Source of pipeline generated by CodeStar is master by default. You need to change that to the development branch.

You can clone the pipeline to choose ‘Clone Pipeline’ like below.

Next, you fill in the pipeline name. You select ‘New service role’ because you add the policy to that role later.
You can create other S3 buckets for artifacts but now I choose the bucket generated by CodeStar. If you want to separate each environment artifact, you create other S3 buckets.
Finally, you choose ‘Customer Managed Key’ then set the key you created on #2.

#4 Change S3 bucket policy for build artifact

CodeStar creates an S3 bucket for artifacts that contain Jar files, Cloudformation templates, and so on. To share those artifacts with other AWS account, you set up the S3 bucket policy.
You insert the below policy into the ‘statement’ section in the policy of artifact bucket.
You change the bold and italic letter in the below policy to your own resource name.

{
"Sid": "",
"Action": [
"s3:Get*",
"s3:Put*"
],
"Effect": "Allow",
"Resource": "arn:aws:s3:::codepipeline-source-artifact/*",
"Principal": {
"AWS": [
"arn:aws:iam::STAGING_ACCOUNT_NO:root",
"arn:aws:iam::PROD_ACCOUNT_NO:root"
]
}
},
{
"Sid": "",
"Action": [
"s3:ListBucket"
],
"Effect": "Allow",
"Resource": "arn:aws:s3:::codepipeline-source-artifact",
"Principal": {
"AWS": [
"arn:aws:iam::STAGING_ACCOUNT_NO:root",
"arn:aws:iam::PROD_ACCOUNT_NO:root"
]
}
}

#5 Create Cross-Account IAM Role

Next step, you need to change the AWS account to staging or production. You create a Cross-Account IAM Role on each AWS account to pass the creation of Cloudformation stack and the using Customer Management Key authority to other AWS account like staging and production.
This link is how you create a Cross-Account IAM role.

When you set the IAM policy on the Cross-Account role on the staging AWS account, that policy is below.
You change the bold and italic letter in the below policy to your own resource name.

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"cloudformation:*",
"iam:PassRole"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"s3:Get*",
"s3:Put*",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::codepipeline-source-artifact/*"
]
},
{
"Effect": "Allow",
"Action": [
"kms:DescribeKey",
"kms:GenerateDataKey*",
"kms:Encrypt",
"kms:ReEncrypt*",
"kms:Decrypt"
],
"Resource": [
"arn:aws:kms:REGION:DEVELOPMENT_ACCOUNT_NO:key/key-id"
]
}
]
}

#6 Create IAM Role for deployment

You need to create Cloudformation and CodeDeploy roles on staging and production AWS account to deploy AWS Lambda to each account.
In this time, I attached an AdministratorAccess policy is AWS managed policy to Cloudformation role and attached an AWSCodeDeployRoleForLambda is also AWS managed policy to the role for CodeDeploy.

#7 Modify Code Pipeline’s service role

To use the Cross-Account IAM role you create on staging and production AWS account, you add some IAM policy to the CodePipeline service role you create when you cloned the pipeline.
You can create the inline policy to use this IAM policy below. This example is for staging so you also modify the production one.

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

#8 Modify Code Pipeline

The pipeline has to use the Cross-Account IAM role on staging and production. And you have to change GenerateChangeSet’s configuration on staging and production pipeline’s Cloudformation to use Cloudformation role and Codedeploy role on each AWS account.
First, you dump the pipeline configuration to execute this command below.

aws codepipeline get-pipeline --name [Pipeline Name] > pipeline.json

Then you edit ‘pipeline.json’. You change the bold and italic letters below to your own resource name. This example is for the staging pipeline so you also modify the production one.

・・・・
{
"name": "Deploy",
"actions": [
{
"name": "GenerateChangeSet",
"actionTypeId": {
"category": "Deploy",
"owner": "AWS",
"provider": "CloudFormation",
"version": "1"
},
"runOrder": 1,
"configuration": {
"ActionMode": "CHANGE_SET_REPLACE",
"Capabilities": "CAPABILITY_NAMED_IAM",
"ChangeSetName": "pipeline-changeset",
"ParameterOverrides": "{\"ProjectId\":\"test-project\", \"CodeDeployRole\":\"arn:aws:iam::STAGING_ACCOUNT_NO:role/CodeDeployRole\"}",
"RoleArn": "arn:aws:iam::STAGING_ACCOUNT_NO:role/CloudformationRole",
"StackName": "awscodestar-test-project-infrastructure",
"TemplateConfiguration": "test-project-BuildArtifact::template-configuration.json",
"TemplatePath": "test-project-BuildArtifact::template-export.yml"
},
"roleArn": "ARN_FOR_CROSS_ACCOUNT_ROLE",
"outputArtifacts": [],
"inputArtifacts": [
{
"name": "test-project-BuildArtifact"
}
]
},
{
"name": "ExecuteChangeSet",
"actionTypeId": {
"category": "Deploy",
"owner": "AWS",
"provider": "CloudFormation",
"version": "1"
},
"runOrder": 2,
"configuration": {
"ActionMode": "CHANGE_SET_EXECUTE",
"ChangeSetName": "pipeline-changeset",
"StackName": "awscodestar-test-project-infrastructure"
},
"roleArn": "ARN_FOR_CROSS_ACCOUNT_ROLE",
"outputArtifacts": [],
"inputArtifacts": []
}
]
}
・・・・

Then you need to delete the metadata section.

"metadata": {
"pipelineArn": "arn:aws:codepipeline:REGION:ACC:my_test",
"updated": 1551216777.183,
"created": 1551207202.964
}

After that, you import ‘pipeline.json’ to each pipeline to execute the command below.

aws codepipeline update-pipeline --cli-input-json file://pipeline.json

#9 Modify template.yml

By default, template.yml in CodeCommit generated by CodeStar include CodeStar macro. That macro doesn’t need so you have to delete that. You delete a bold and italic line in the below template.

AWSTemplateFormatVersion: 2010-09-09
Transform:
- AWS::Serverless-2016-10-31
- AWS::CodeStar
Parameters:
ProjectId:
Type: String
Description: AWS CodeStar projectID used to associate new resources to team members
CodeDeployRole:
Type: String
Description: IAM role to allow AWS CodeDeploy to manage deployment of AWS Lambda functions

Finally, you finish the configuration! Then you go to the pipeline console, click ‘Release Change’ to rerun the pipeline for staging and production.

--

--