Build a CI/CD Pipeline to Improve Your IaC with AWS CloudFormation
A walk-through of how to create a CI/CD pipeline from scratch using Amazon CodeCatalyst, to deploy your Infrastructure as Code (IaC) with AWS CloudFormation.
About | |
---|---|
✅ AWS experience | 200 - Intermediate |
⏱ Time to complete | 30 minutes |
💰 Cost to complete | Free tier eligible |
🧩 Prerequisites | - AWS Account - CodeCatalyst Account - AWS CloudFormation basic understanding |
💻 Code Sample | Code sample used in tutorial on GitHub |
📢 Feedback | Any feedback, issues, or just a 👍 / 👎 ? |
⏰ Last Updated | 2023-03-22 |
- Stack name
CodeCatalyst-IAM-roles
- Region: any (preferred
us-west-2
) - Download the template provided here and upload this in CloudFormation console -> Create new stack -> Template -> Upload a template.
main_branch_IAM_role
and pr_branch_IAM_role
in your AWS account.Please note, themain_branch_IAM_role
provides full access to AWS resources in EC2 and CloudFormation services, as those will be used by sample CloudFormation template mentioned in this blog. Please use this role carefully and delete it when not required.

Create Space
on the CodeCatalyst Dashboard, add a name (we will use CloudFormation CodeCatalyst
), and add the AWS Account ID to link for billing. Follow the prompts to link your AWS Account with CodeCatalyst.012345678901
is a placeholder; replace it with your own account ID. You can find your account ID in the top right of your AWS Console. Before you can create the space, follow the Verify in the AWS console
link and complete the verification. You should get green tick to proceed!
AWS Accounts
tab, click on your account ID, and then click on Manage roles from the AWS Management Console
.Add IAM role to Amazon CodeCatalyst space
. In the dialog, select the option Add an existing role you have created in IAM
and select the main_branch_IAM_role
from the dropdown. Click Add role
. Follow the same steps for the pr_branch_IAM_role
.
Create Project
button, select Start from scratch
, and give your project a name - we will use ThreeTierApp
.
Code
in the left-side navigation menu, then select Source repositories
, Add repository
, and choose Create repository
. Set a repository name ( we will use 3-tier-app
in this tutorial), add a description and none
for the .gitignore file:
CI/CD
, Environments
, and click on Create Environment
. In the Environment details enter following:- Environment name:
PreProdEnv
- Environment type:
Non-production
- Description:
Pre-production environment to learn, test and experiment with CloudFormation
- AWS account connection
Connection
: Select the AWS account ID that will be used in the workflows to deploy this environment

- AWS Cloud9
- Visual Studio Code
- JetBrains IDEs
- IntelliJ IDEA Ultimate
- GoLand
- PyCharm Professional
AWS Cloud9
for our development environment.Code
, Dev Environments
, and click on Create Dev Environment
. In the Create dev environment and open with AWS Cloud9
dialog box select following:- Repository:
Clone a repository
- Repository: Select the repo that you want to clone. We created a repo
3-tier-app1
above, so select same. - Branch:
Work in existing branch
- Alias:
bootstrap

Create
and it will open a new Cloud9 dev environment. It will take a minute or two, so grab a coffee before we start the CloudFormation magic.
3-tier-app
, with a readme.md
, devfile.yaml
, and some hidden folders. The devfile.yaml
, contains the definition to build your application libraries and toolchain. You can ignore it for the purpose of this tutorial.In the real world, you would deploy the networking infrastructure and application deployment in separate CloudFormation nested stacks. Nested stacks allow more regularly needed changes to the application stack to be applied without running the networking stack every time, which saves time. Likewise, the networking team can make changes independently without running the application stack. This approach also keeps the template body size within CloudFormation Quotas. Since this deployment with CodeCatalyst is smaller and simpler -- and we don't have to worry about long-term operations -- let's deploy everything in a single template.
Code
in the left-side navigation menu, then select Source repositories
. A new file VPC_AutoScaling_With_Public_IPs.json
should be added to the repo.- Create Workflow using Code Catalyst Console in Visual drag-drop method [navigate to CI/CD -> Workflows]
- Create Workflow using the dev environment using yaml [the method we are following in the blog]
main_branch.yaml
file:.codecatalyst/workflows/main_branch.yaml
in your IDE, and add the following. Remember to:- replace the placeholder AWS account ID
123456789012
with the value of your account, and the IAM role namemain_branch_IAM_role
, if you changed it - if you are using your own CloudFormation template, replace the CloudFormation filename in
template
- main_branch.yaml
CI/CD
-> Workflows
page. You should see the workflow running:

Variables
tab.

It might happen that the run fails due to errors. Read through the logs to understand any issue and remediate it. If you get internal error, at this point it is good to check the stack deployment in the CloudFormation dashboard of AWS Management Console. If the CloudFormation stack has rolled back, then delete the stack manually, fix the issues, and run the workflow again. You can find help in Documentation for Troubleshooting, Premium Support center or AWS re:Post.
main_workflow
that we created earlier will automatically merge the code and deploy changes to PreProdEnv
, my non-prod environment (step7). You might have different branching strategies and more tests for your production environment deployment.
pr_branch.yaml
in the hidden .codecatalyst/workflows/
directory and paste the following.- replace the placeholder AWS account ID
123456789012
with the value of your account, and the IAM role namemain_branch_IAM_role
, if you changed it - if you are using your own CloudFormation template, replace the CloudFormation filename in
template
- pr_branch.yaml
- In the
Super-Linter_0d
action, we are definingVALIDATE_CLOUDFORMATION: "true"
environment variable. This ensures that our CloudFormation template is validated using thecfn-lint
github action. cfn-lint is an open source tool that helps validate AWS CloudFormation yaml/json templates against the AWS CloudFormation Resource Specification and additional checks. This includes checking valid values for resource properties and best practices. - In the
CreateChangeSet
action, theno-execute-changeset: "1"
option in the workflow below, it indicates whether to run the change set or have it reviewed. Default is'0'
, which means it will run the change set. We don't want it to execute the changes; we just want to see the changes that will happen if PR is merged, hence we set it to'1'
which means we do not execute the ChangeSet. - In the
CreateChangeSet
action, we have added a new propertyDependsOn: - Super-Linter_0d
. This tells the workflow to first runSuper-Linter_0d
action, and if it is successful, only then run theCreateChangeSet
action.
PR_Branch_Workflow
is created but it has not run.
PR_Branch_Workflow
, you can see the workflow. As defined in the workflow yaml above, the workflow will run the action Super-Linter_0d
first and if it is successful, only then it will run action CreateChangeSet
.
- If you are using your own CloudFormation template, make any changes to the template to create a change set.
- For the sample CloudFormation template used in this blog, you have 2 options :
- simply replace its content with this already modified template. Make sure the name of template file is same(
VPC_AutoScaling_With_Public_IPs.json
), as workflow has filename mentioned in it,OR - you can make the following changes manually to add a third subnet and its resources to the template:Add following JSON code to the sample CloudFormation template under
Resources
section.In the Mappings, LoadBalancer and AutoScaling resources, add thePublicSubnet3
like following :
test-pr-workflow
branch, using the following commands:Code
-> Repository
. You can see the 2 branches: main
and test-pr-workflow
.
test-pr-workflow
, you can ask others to review the changes by creating a pull request.Create pull request
and enter following details:- Source repository:
3-tier-app
- Source branch:
test-pr-workflow
- Destination branch:
main
- Pull request title:
Merge new third subnet
- Pull request description:
New third subnet created and added to VPC, RouteTable, NACL, LoadBalancer, ASG

test-pr-workflow
and our destination for merge is the main
branch. Once this PR is created, it will trigger the PR_Branch_Workflow
that will create a CloudFormation change set (and not make any deployments!).To see the active run forPR_Branch_Workflow
, in the CodeCatalyst console, navigate to theCI/CD
->Workflows
page and ensure you select thetest-pr-workflow
branch. By default, the Workflows page always shows themain
branch. You have to switch branches to see the active workflow in other branches.
PR_Branch_Workflow
has failed
.
test-pr-workflow
.test-pr-workflow
branch. As this is a revision to the branch, it should automatically trigger the workflow to run again.CI/CD
-> Workflows
page. Make sure you select the test-pr-workflow
branch. A new run should now be active.
CreateChangeSet
.

Code
-> Pull Requests
, and then click on Merge
.If there are conflicts, or if the merge can't be completed, the merge button is inactive, and aNot mergeable
label is displayed. In that case, you must obtain approval from any required approvers, resolve conflicts locally if necessary, and push those changes to thetest-pr-workflow
before you can merge.

- Fast forward merge - Merges the branches and moves the destination branch pointer to the tip of the source branch. This is the default merge strategy in Git. Select this option for this blog.
- Squash and merge - Combines all commits from the source branch into single merge commit in the destination branch.
In our case, the source branch is
test-pr-workflow
, and I am deleting this branch to keep my branching structure clean and simple.
test-pr-workflow
to main
branch. This will trigger the Main_Branch_Workflow
and deploy the updated CloudFormation code to the PreProdEnv
.
PreProdEnvStack
and CodeCatalyst-IAM-roles
.Project settings
, click on Delete project
, and follow the instructions to delete the project.Space settings
tab and click on Delete space
.Any opinions in this post are those of the individual author and may not reflect the opinions of AWS.