Tests and tags in CDK

I manage a bunch of redirected subdomains. We use these with third-party applications, where the application lives at some non-Lafayette URL and we want a clean, simple Lafayette URL for our users. We call these vanity plates, and at the architectural level they’re pretty simple: a Cloudfront distribution with a certificate and LambdaEdge function to handle the redirection. We monitor the state of the redirection with a Synthetic Canary.

A small challenge is that we like to have lifecycle rules on all our S3 buckets. With the above stack we actually have three buckets:

  1. The logging bucket for the Cloudfront distribution
  2. An empty S3 bucket that serves as the unused target for the Cloudfront distribution
  3. The artifacts bucket for the Synthetic Canary.

The first of these should have a retention rule; the second one is empty and it doesn’t matter. For the last of these, CDK creates a bucket if you don’t specify one, and you can’t (as of October 2022) pass lifecycle rules to it after the fact.

Who’s who?

Here’s a test for an S3 bucket in CDK:

1
2
3
template.hasResourceProperties("AWS::S3::Bucket", {
"LifecycleConfiguration": Match.absent(),
}

Nothing about that test tells me which of the three buckets, none of which had a lifecycle rule, is matching. All three can and do match. We need to differentiate them, and we’ll use tags. Here’s a code block to add a tag to the Cloudfront log bucket:

1
Tags.of(this.logBucket).add('VanityPlateApplication', 'LogBucket');

Now, I can go back to the test and check for the tag in addition to the lifecycle rule:

1
2
3
4
5
6
7
8
9
template.hasResourceProperties("AWS::S3::Bucket", {
"LifecycleConfiguration": Match.absent(),
Tags: [
{
Key: "VanityPlateApplication",
Value: "LogBucket"
}
]
}

That test is unambiguous, and you can apply tags to auto-generated resources like the bucket created by the Synthetic Canary. This tagging strategy also creates some interesting possibilities for resource groups, but that’s another post.