Tags: aws cdk cloudformation typescript python
Cloudformation service in AWS allows you to describe an entire set of resources required to make a pipeline. The cloudformation template can be described in JSON or YAML format. Updating the cloudformation template was not a pleasant experience. I wanted to discover alternative ways to generate cloudformation template programmatically.
The CDK library provides you a way to declare the resources in your favorite languages like Java, Javascript, Typescript, and Python. In this tutorial, we will use typescript and python to generate our cloudformation template.
Just a quick referesher to few concepts before we delve into AWS CDK
Cloudformation template describes AWS resources. A running instance of cloudformation is called a stack.
Constructs are the basic building blocks of AWS CDK apps.
L1 construct are named CfnXyz, where Xyz is name of the resource. They are low-level construct which directly represent cloudformation resources.
L2 construct provide common boilerplates and glue logic. These will come with convenient defaults and reduces the amount of knowledge you need to know about them.
L3 construct are called high-level patterns. These constructs are designed to help you complete common tasks in AWS, often involving multiple kinds of resources.
For this tutorial, we will use L1 construct. However same concept can be used for L2 construct.
First, install the AWS CDK CLI from command line using
$ npm i -g aws-cdk@latest
Let’s create a project
$ mkdir test-cdk | |
$ cd test-cdk | |
$ cdk init sample-app --language=typescript |
Then you can verify
$ cdk doctor | |
- CDK Version: 2.3.0 (build beaa5b2) | |
- AWS environment variables: | |
- AWS_NODEJS_CONNECTION_REUSE_ENABLED = 1 | |
- AWS_SDK_LOAD_CONFIG = 1 | |
- AWS_STS_REGIONAL_ENDPOINTS = regional | |
- No CDK environment variables |
For our first use case, will add Parameters to our cloudformation. We need to edit file lib\test-cdk-stack.ts
for typescript or lib\test_cdk_stack.py
for python.
import { Aws, CfnMapping, CfnParameter, Duration, Stack, StackProps } from 'aws-cdk-lib'; | |
import { Construct } from 'constructs'; | |
export class TestCdkStack extends Stack { | |
constructor(scope: Construct, id: string, props?: StackProps) { | |
super(scope, id, props); | |
// create parameters | |
new CfnParameter(this, | |
"Application", { | |
type: "String", | |
default: "Cdk Tutorial" | |
}) | |
new CfnParameter(this, | |
"Environment", { | |
type: "String", | |
default: "development", | |
allowedValues: ["development", "production"] | |
}) | |
} | |
} |
We can see the output of the cloudformation template by using the following command
$ cdk synth
If you want to generate cloudformation template without metadata
$ cdk synth --version-reporting false --path-metadata false
The output is
Parameters: | |
Application: | |
Type: String | |
Default: CDK Tutorial | |
Environment: | |
Type: String | |
Default: development | |
AllowedValues: | |
- development | |
- production | |
BootstrapVersion: | |
Type: AWS::SSM::Parameter::Value<String> | |
Default: /cdk-bootstrap/hnb659fds/version | |
Description: Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip] | |
Rules: | |
CheckBootstrapVersion: | |
Assertions: | |
- Assert: | |
Fn::Not: | |
- Fn::Contains: | |
- - "1" | |
- "2" | |
- "3" | |
- "4" | |
- "5" | |
- Ref: BootstrapVersion | |
AssertDescription: CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI. |
For CDK v2, CheckBootstrapVersion rule is added to the Stack's template as a safety check, to verify that the bootstrap stack in the target environment meets the minimum requirements of the current stack1.
The cloudformation template needs at least one resource to validate. We will add a stepfunction
to our cloudformation. We will define our stepfunction inside a json file, helloworld.asl.json
{
"Comment" : "A very very simple StepFunction",
"StartAt": "Hello",
"States": {
"Hello": {
"Type": "Wait",
"Seconds": 10,
"Next": "World"
},
"World": {
"Type": "Pass",
"End": true
}
}
}
If you are not familiar with Stepfunction, AWS Stepfunction console has a nice visualization
Next we need to upload the helloworld.asl.json
to s3 bucket. We also need to define a mapping to access this json
file.
import { Aws, CfnMapping, CfnParameter, Duration, Stack, StackProps } from 'aws-cdk-lib'; | |
import { CfnMap } from 'aws-cdk-lib/aws-location'; | |
import { Construct } from 'constructs'; | |
export class TestCdkStack extends Stack { | |
constructor(scope: Construct, id: string, props?: StackProps) { | |
super(scope, id, props); | |
// create parameters | |
new CfnParameter(this, | |
"Application", { | |
type: "String", | |
default: "Cdk Tutorial" | |
}) | |
new CfnParameter(this, | |
"Environment", { | |
type: "String", | |
default: "development", | |
allowedValues: ["development", "production"] | |
}) | |
// create mapping | |
const myMap = new CfnMapping(this, | |
"MyMapping", { | |
lazy: true, | |
mapping: { | |
"development": { | |
S3Bucket: "development-s3-bucket", | |
S3Key: "development-s3-prefix" | |
}, | |
"production": { | |
S3Bucket: "development-s3-bucket", | |
S3Key: "development-s3-prefix" | |
} | |
} | |
}) | |
} | |
} |
Our output will still be the same since our mapping is lazy. Next, we will add stepfunction to our resources
import { Aws, CfnMapping, CfnParameter, Duration, Fn, Stack, StackProps } from 'aws-cdk-lib'; | |
import { CfnMap } from 'aws-cdk-lib/aws-location'; | |
import { CfnStateMachine } from 'aws-cdk-lib/aws-stepfunctions'; | |
import { Construct } from 'constructs'; | |
export class TestCdkStack extends Stack { | |
constructor(scope: Construct, id: string, props?: StackProps) { | |
super(scope, id, props); | |
// create parameters | |
new CfnParameter(this, | |
"Application", { | |
type: "String", | |
default: "Cdk Tutorial" | |
}) | |
new CfnParameter(this, | |
"Environment", { | |
type: "String", | |
default: "development", | |
allowedValues: ["development", "production"] | |
}) | |
const stepfunctionRole = new CfnParameter(this, | |
"StepFunctionRole", { | |
type: "String", | |
default: "put-your-stepfunction-execution-role" | |
}) | |
// create mapping | |
const myMap = new CfnMapping(this, | |
"MyMapping", { | |
lazy: true, | |
mapping: { | |
"development": { | |
S3Bucket: "development-s3-bucket", | |
S3Key: "development-s3-prefix" | |
}, | |
"production": { | |
S3Bucket: "development-s3-bucket", | |
S3Key: "development-s3-prefix" | |
} | |
} | |
}) | |
// create stepfunction | |
new CfnStateMachine(this, | |
"DemoStepFunction", { | |
definitionS3Location: { | |
"bucket": myMap.findInMap("development", "S3Bucket"), | |
"key": myMap.findInMap("development", "S3Key") | |
}, | |
roleArn: "arn:aws:iam::" + Aws.ACCOUNT_ID + ":role/" + stepfunctionRole.valueAsString, | |
stateMachineType: "STANDARD", | |
tags: [{ | |
"key": "environment", | |
"value": "development" | |
}] | |
}) | |
} | |
} |
The final cloudformation template is
Parameters: | |
Application: | |
Type: String | |
Default: CDK Tutorial | |
Environment: | |
Type: String | |
Default: development | |
AllowedValues: | |
- development | |
- production | |
StepFunctionRole: | |
Type: String | |
Default: put-your-stepfunction-execution-role | |
BootstrapVersion: | |
Type: AWS::SSM::Parameter::Value<String> | |
Default: /cdk-bootstrap/hnb659fds/version | |
Description: Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip] | |
Resources: | |
DemoStepFunction: | |
Type: AWS::StepFunctions::StateMachine | |
Properties: | |
RoleArn: | |
Fn::Join: | |
- "" | |
- - "arn:aws:iam::" | |
- Ref: AWS::AccountId | |
- :role/ | |
- Ref: StepFunctionRole | |
DefinitionS3Location: | |
Bucket: development-s3-bucket | |
Key: development-s3-prefix | |
StateMachineType: STANDARD | |
Tags: | |
- Key: environment | |
Value: development | |
Rules: | |
CheckBootstrapVersion: | |
Assertions: | |
- Assert: | |
Fn::Not: | |
- Fn::Contains: | |
- - "1" | |
- "2" | |
- "3" | |
- "4" | |
- "5" | |
- Ref: BootstrapVersion | |
AssertDescription: CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI. |
The cloudformation template is generated under
# for typescript
cdk.out\TestCdkStack.template.json
# for python
cdk.out\test_cdk.template.json
Or you can simply deploy it using
$ cdk deploy