Cross Account Infra Provisioning Pipeline

Kiran Bakale
8 min readFeb 8, 2024
Cross Account Infra Provisioning Pipeline — Architecture
Architecture-Workflow

Hello DevOps Enthusiasts ☁️♾️, welcome to comprehensive guide of setting-up Cross Account Infra Provisioning Pipeline

Firstly a big thanks to the contributors without them this project seemed next to impossible.
- Farhan Sayed
- Ashish Sarawad
- Phanindra Sangers

In the world of cloud infrastructure orchestration, the Cross-Account Infrastructure Provisioning Pipeline emerges as a cornerstone for modern development workflows. Leveraging Terraform, Terragrunt, and AWS CI/CD, this pipeline becomes pivotal, enabling the seamless deployment of resources across diverse AWS accounts, fostering agility, security, and scalability.

Introduction:

Embarking on the journey of Cross-Account Infrastructure Provisioning, this article delves into the implementation of a robust CI/CD pipeline utilizing Terraform, Terragrunt, and various AWS services. The goal is to seamlessly provision infrastructure across different environments housed in distinct AWS accounts — a process that involves smooth orchestration and secure communication between accounts.

Tech Stack
- Terraform — Install here
- Terragrunt — Install here
- AWS CLI — Install here
- AWS Services: CodePipeline, CodeCommit, CodeBuild, IAM, S3
- Git

Overview:

Our infrastructure provisioning pipeline spans three AWS accounts —
1.DEV Account (Primary-AWS-Account)
2.UAT Account,
3.Prod Account.

  • The primary AWS account houses the CI/CD pipeline along with the necessary Terraform scripts and Terragrunt configuration files. The secondary and third accounts, UAT and Prod respectively, contain their dedicated DynamoDB and S3 resources for the infrastructure provisioned within each account.

Workflow:

  • The heart of the operation lies in the DEV Account, where the CodeRepository and CI/CD pipeline reside. With two crucial tags, namely ‘uattag’ and ‘prodtag,’ changes made to the code trigger the pipeline. Upon committing and pushing to these tags, the pipeline kicks into action, seeking approval before provisioning the respective environment’s infrastructure i.e if the uattag is pushed the pipeline will have an aws-service provisioned in the UAT-Account same goes for the Prod-tag. It’s noteworthy that this entire process is cross-account, with on-the-fly authentication and authorization for the target accounts, ensuring a secure and efficient workflow.
  • Additionally, the pipeline incorporates two CodeBuild projects, each with a specific purpose. One is dedicated to the planning stage, generating a comprehensive plan of the infrastructure changes. The other is tailored for the apply stage, executing the changes only after manual approval, ensuring precise control over the deployment process.

Implementation Steps — walkthrough

1. Provisioning CI/CD Pipeline:
Begin by utilizing Terraform to provision the CI/CD pipeline and its related resources. Ensure necessary adjustments are made to the configuration files for smooth deployment.

2. IAM Role Creation in UAT & PROD:
Establish IAM roles in the UAT and Prod accounts, pivotal for authenticating and authorizing access during the cross-account provisioning process. This step ensures the secure communication needed for smooth operations.

3. CodeCommit Repository Setup:
In the DEV Account, create a CodeCommit repository, and initiate the necessary modifications to the code. Push the cloned code into the repository, laying the groundwork for the subsequent pipeline execution.

  • With the implemented CI/CD pipeline, IAM roles, and CodeCommit repository, the orchestrated cross-account infrastructure provisioning is set to work seamlessly. This robust approach ensures efficiency, security, and agility in deploying infrastructure changes across diverse AWS environments.

UNDERSTANDING THE CROSS-ACCOUNT WORKFLOW

cross-account-communication

In the world of Infrastructure as Code (IaC), managing and provisioning resources across multiple AWS accounts can be a complex yet crucial task we will delve into the details of Cross-Account Infra Provisioning Pipelines, focusing on the flow that enables seamless access from a source account to a destination account.

Understanding the Flow:

  1. Source Account Setup (Dev):

- Within the Source Account (Dev), a dedicated `codebuildinstance` role has been established.

- This role is granted the necessary permissions to assume a role in the Destination Account (UAT/PROD), achieved through the inclusion of `sts:assumeRole` permissions.

- The specified resource in this permission is the role in the UAT/PROD Account, facilitating a controlled and secure access mechanism.

2. Destination Account Configuration (UAT/PROD)

- The Destination Account (UAT/PROD) is configured to trust the Source Account (Dev).

- This trust relationship is established by defining a trust policy where the principal is set to the ARN (Amazon Resource Name) of the `codebuildinstance` role in the Source Account.

- Essentially, the Destination Account acknowledges the Source Account as a trusted entity, allowing the specified role to access its resources.

Authentication:

- The Source Account (Dev) initiates the process by assuming the `codebuildinstance` role in the Destination Account (UAT/PROD).

- This is achieved through the AWS Security Token Service (STS) using the `sts:assumeRole` permission, proving the identity and legitimacy of the requesting Source Account.

Authorization:

- In terms of authorization, the Destination Account is configured to trust the Source Account.

- By defining a trust relationship, the Destination Account authorizes the specified `codebuildinstance` role from the Source Account to access its resources.

This step ensures that only authenticated requests from the specified role are granted access, maintaining a secure and controlled cross-account interaction.

PREP-WORK: IMPLEMENTATION STARTS HERE🚀

1. Since this setup uses remote state backend. as per the best practices first we will manually provision the following resources which will help us manage the state remotely.
— S3 Bucket : For storing the terraform.tfstate in the bucket
— DynamoDB: For locking the state and to actively avoid the conflicts that may occur in case of multiple requests received by terraform state.

2. Now login to the DEV-ACCOUNT AWS Management Console, navigate to AWS S3 service, provide a unique name and leave the rest of options as default, and create the bucket

3. Navigate to AWS Dynamo DB, Create a Table , give it a name, type in LockID (S), as the partition key and leave the rest of the options as default and create the table.

4. Follow the above steps in UAT & PROD account and copy its names, which will be used later.

5. Now Create a Codecommit repository in DEV-Account with the name cross-account-infra-repo and also generate the credentials for accessing this repository.

6. Now login to UAT account, Create a role with custom-trust policy and paste the following json in the policy section, and attach admin-level permissions to this role, repeat the same steps of role creation for the PROD account — copy the ARN of both the roles in UAT & PROD and paste it somewhere as we will require it later.

Note : the AWS :[] section in json snippet is intentionally left blank we will come back to this role later.

{
"Version": "2012–10–17",
"Statement": [
{
"Sid": "Statement1",
"Effect": "Allow",
"Principal": {
"AWS": [
**PASTE THE ARN OF CODEBUILDINSTANCEARN HERE**
""
]
},
"Action": "sts:AssumeRole"
}
]
}

IMPLEMENTATION STEPS

  1. Clone the following repository https://github.com/kiranbakale/Cross-AC-Infra-Provisioning-Pipeline in your local system.
  2. Navigate to CI/CD folder Make all the specified changes in the terraform code to match your requirements.
  3. The main infra provisioning pipeline will be created in the Primary-Account i.e Dev Account and pipeline will operate from this account.
  4. Firstly, Navigate to the `CI/CD` folder & make changes in TF_scripts accordingly to Provision the necessary infrastructure resources that will be used to create the CI/CD Pipeline.
  5. Once completed with TF_scripts now move to templates folder and accordingly replace the DEV-ACCOUNT-ID,UAT-ACCOUNT-ID,PROD-ACCOUNT-ID with respective IDs
  6. After completing the above steps make changes to buildspec-tf-apply.yml available in CI/CD folder.
  7. Now move to the codebuild.tf , in here there are two codebuild projects , don’t forget to paste the ARN’s of roles in both the projects that we previously created in destination account — in PREP-WORK- 6th point.
  8. And also essentially to check the
  9. Setup the environments configs — aws credentials — DEV ACCOUNT.
  10. `backend.tf` — includes the configuration for storing the backend in remote-state & state locking using i.e S3 Bucket — make the necessary changes mentioned in the file.
  11. `terraform.tfvars` — The terraform.tfvars file is a Terraform-specific configuration file used to assign values to variables defined in the project. it allows users to set values for variables, such as AWS region, instance types, or any other configurable parameters. By maintaining a separate terraform.tfvars file, users can easily update or modify variable values without altering the main Terraform configuration files by typing the following commands — make the necessary changes mentioned in the file.
  12. Now type in the following commands this will apply TF scripts to provision all the necessary resources in the DEV-ACCOUNT and you will see the Pipeline is ready for the action.

Your Infra-provisioning pipeline should look something similar to this. [Mine build project has failed, yours should necessarily not! 😜]

  1. Now you can come out of the CI/CD folder, next we will make changes in environment folder in /prod, /uat files . copy-paste the respective service-names [S3 Bucket & Dynamo DB which were created manually 4th step in Prep-work] names in each environment folder.
  2. Jump to TF-files directory make specified changes in the templates-prod & templates-uat directory and also I have used an ECR with a policy attached to it for the demonstration, you can provision any resources and variablise the same
  3. Since we are differentiating the infra-provisioning using git tags follow the steps below to create and push tags from your local machine.
git tag prodtag
git tag uattag
git add .
git commit -m "message"
git push origin branchname tagname(can be prodtag for prodenvironment, can be uattag for uatenvironment)

4. After Pushing the tag to the repo you will see that codepipeline is triggered and the Pipeline is working once the build stage is completed after confirming the terragrunt plan you will have to go to the pipeline.

5. Once the build has completed successfully as we have setup a manual approval stage , you will be asked for providing the approval ,once you approve the request you will be moved to the next step that is TF_APPLY and this is where the pipeline will start provisioning the resources in the Respective UAT/PROD Account.

After pushing the tags to the repo, Terraform-terragrunt will provision all the necessary resources in the accounts to and you will see the Pipeline in Action.

IMPORTANT : Dont forget to deprovision the setup and also delete the created roles in UAT & PROD ACCCOUNT

Do let me know if you encounter any issues, happy to help!
Check out my other blogs here.

--

--