AWS Continuous Infrastructure Delivery with CodePipeline and CloudFormation: How to pass Stack Parameters

When deploying CloudFormation stacks in a “Continuous Delivery” manner with CodePipeline, one might encounter the challenge to pass many parameters from the CloudFormation stack describing the pipeline to another stack describing the infrastructure to be deployed (in this example a stack named application).

Consider a CloudFormation snippet describing CodePipeline which deploys another CloudFormation stack:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# pipeline.yaml
...
Resources:
Pipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
...
Stages:
...
- Name: Application
Actions:
- Name: DeployApplication
ActionTypeId:
Category: Deploy
Owner: AWS
Provider: CloudFormation
Version: 1
Configuration:
ActionMode: CREATE_UPDATE
StackName: application
TemplatePath: Source::application.yaml

Now when you want to pass parameters from the pipeline stack to the application stack, you could use the ParameterOverrides option offered by the CodePipeline CloudFormation integration, which might look like this:

1
2
3
4
5
6
7
8
# pipeline.yaml
...
- Name: DeployApplication
...
Configuration:
StackName: application
TemplatePath: Source::application.yaml
ParameterOverrides: '{"ApplicationParameterA": "foo", "ApplicationParameterB": "bar"}'

This would pass the parameters ApplicationParameterA and ApplicationParameterB to the application CloudFormation stack. For reference this is how the application stack could look like:

1
2
3
4
5
6
7
8
9
10
11
12
# application.yaml
---
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
ApplicationParameterA:
Type: String
ApplicationParameterB:
Type: String
Resources:
...

Alternative way of parameter passing with Template Configurations

Injecting parameters from the pipeline stack to the application stack can become awkward with the ParametersOverrides method. Especially when there are many parameters and they are passed into the pipeline stack as parameters as well, the pipeline template could look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# pipeline.yaml
---
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
ApplicationParameterA:
Type: String
ApplicationParameterB:
Type: String
Resources:
Pipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
Stages:
...
Actions:
- Name: DeployApplication
...
Configuration:
...
TemplatePath: Source::application.yaml
ParameterOverrides: !Sub '{"ApplicationParameterA": "${ApplicationParameterA}", "ApplicationParameterB": "${ApplicationParameterB}"}'

An alternative way is to place a so called template configuration into the same artifact which contains the application.yaml template, and reference it via the TemplateConfiguration:

1
2
3
4
5
6
7
8
9
# pipeline.yaml
...
- Name: DeployApplication
...
Configuration:
...
TemplatePath: Source::application.yaml
ParameterOverrides: '{"ApplicationParameterA": "foo", "ApplicationParameterB": "bar"}'
TemplateConfiguration: Source::template_configuration.json

In our case, the template_configuration.json file would look like this:

1
2
3
4
5
6
{
"Parameters" : {
"ApplicationParameterA" : "foo",
"ApplicationParameterB" : "bar"
}
}

This might be much nicer to handle and maintain depending on your setup.

Btw you can also use the TemplateConfiguration to protect your resources from being deleted or replaces with Stack policies.