Customizing the CDK bootstrap stack

Amazon’s CDK creates a helper Cloudformation stack (by default named CDKToolkit) with a few resources to assist with deployment. The most familiar to regular users are the S3 asset bucket and the ECR repository.

A source of mild frustration for my colleagues and me is that this default stack doesn’t set lifecycle policies on either, which then trips up Amazon’s security controls (S3 10 and ECR 3, respectively).

Fortunately, there is a relatively straightforward solution, and that’s customizing the Cloudformation template that manages the CDKToolkit stack. I hadn’t realized before now that you can do this but it’s well-documented. First, use cdk bootstrap to output the contents of the template. You’ll want to ensure that you’re using the same version of CDK that you’ll use to deploy the stack:

1
2
cdk --version
cdk bootstrap --show-template > bootstrap-template.yaml

This writes out the bootstrap template to a YAML file. I made two changes, adding lifecycle policies to the resources:

1
2
3
4
5
6
7
8
  StagingBucket:
Type: AWS::S3::Bucket
Properties:
...
LifecycleConfiguration:
Rules:
- ExpirationInDays: 365
Status: Enabled
1
2
3
4
5
6
ContainerAssetsRepository:
Type: AWS::ECR::Repository
Properties:
...
LifecyclePolicy:
LifecyclePolicyText: '{"rules":[{"rulePriority":1,"selection":{"tagStatus":"any","countType":"imageCountMoreThan","countNumber":10},"action":{"type":"expire"}}]}'

As policies go these are anodyne: keep the last ten ECR images (which I don’t even use), and keep the last year’s worth of artifacts.

The final step is telling cdk bootstrap to use this template instead of generating one:

1
cdk bootstrap --template bootstrap-template.yaml

That’s it. The next time you bootstrap, it will modify the resources. Going forward, I think the major gotcha is ensuring that you keep your template up-to-date with any upstream changes.

Update: here’s one technique to catch upstream changes. In addition to bootstrap-template.yaml, save and version an unmodified copy at bootstrap-template.yaml.dist, then use yq to diff it:

1
2
cdk bootstrap --show-template > bootstrap-template.yaml.test
diff <(yq -P 'sort_keys(..)' bootstrap-template.yaml.dist) <(yq -P 'sort_keys(..)' bootstrap-template.yaml.test)