AWS — Cross Account Deployment using Jenkins
Lately, I have been getting involved in many DevOps work as part of my projects. The most recent work I have been involved in was to set up a cross-account deployment using Jenkins in AWS. The infrastructure architecture put together was very simple and reasonable, and the solution to enable cross-account deployment was way simpler. Initially, we struggled to get an alignment on what to use especially there are plugins like Jenkins EC2 etc. available in the market.
We have a Tomcat container along with MySQL RDS to deploy to Dev, QA, UAT, Pre-Prod, and Prod, all of these are running on different AWS accounts, for convenience, I am calling these are Dev-VPC, QA-VPC and so on. We want to do every actions to these environments from one Jenkins instance using multiple jobs. We do have an additional AWS account, say, CI-VPC where our Jenkins up and running.
STS (Secure Token Service)
AWS has an amazing capability called STS (Secure Token Service) to create temporary access credentials using an IAM role. We figured out that using STS is the best solution to solve the cross-account deployment problem.
The Solution
IAM Role
Create an IAM Role in the target accounts like Dev-VPC and QA-VPC. Add the CI-VPC account id in Trusted Relationships, this will ensure that this role can be assumed by CI-VPC
Jenkins Global Configuration
Once you have created a role with correct permissions, you have already solved the problem of cross-account deployments, the remaining piece is to how you configure and use this in your Jenkins account. The best way is to leverage global variables in Jenkins to hold the Role Arn. For example,
- DEV_ROLE_ARN — Provide the full role Arn of the role which you have created in the Dev-VPC
- QA_ROLE_ARN — Provide the full role Arn of the role which you have created in the QA-VPC
For every role, you have created to support cross-account, ensure that you have mapped that to a global variable in Jenkins.
Jobs Configuration in Jenkins
In the Bash Shell of Jenkins, I have added a piece of code to assume the role, for example, if I am deploying to Dev-VPC, I would use the DEV_ROLE_ARN (Global Variable) to assume the role, refer the sample code below,
set +x
unset AWS_ACCESS_KEY_ID
unset AWS_SECRET_ACCESS_KEY
unset AWS_SESSION_TOKEN
aws_credentials_json=$(aws sts assume-role — role-arn ${DEV_ROLE_ARN} — role-session-name devSession — region us-west-2)
export AWS_ACCESS_KEY_ID=$(echo “$aws_credentials_json” | jq — exit-status — raw-output .Credentials.AccessKeyId)
export AWS_SECRET_ACCESS_KEY=$(echo “$aws_credentials_json” | jq — exit-status — raw-output .Credentials.SecretAccessKey)
export AWS_SESSION_TOKEN=$(echo “$aws_credentials_json” | jq — exit-status — raw-output .Credentials.SessionToken)
set -x
// All your AWS commands which you need to execute for Dev-VPC goes here, like accessing S3 bucket, create-stack etc.
In the above code snippet, I am using jq for processing the JSON output from AWS, you could use any other tool as you prefer.
Finally, our design looks like below,