Categories
AWS CDK

Using aspects in AWS CDK

AWS CDK introduces not only tooling, wrappers, constructs, and patterns, but also additional elements that allow us to leverage the expressive power of programming languages. Today I’d like to show you such items: aspects that would enable us to do cool stuff, that is very hard to achieve otherwise.

When it comes to the expressive power, AWS CDK does not stop on the Constructs (which I have explained here). We have more things available, and today I would like to show how we can leverage aspects in the AWS CDK Applications.

AOP 101

If you haven’t heard about Aspect-Oriented Programming, it is a programming paradigm that aims to increase modularity by allowing the separation of cross-cutting concerns. It does so by adding additional behavior to existing code (formally named advice) without modifying the code itself, instead separately specifying which is adjusted via a pointcut specification.

In other words, aspects are the way to apply an operation to all constructs in a given scope. And as our scope is the infrastructure graph with the root at the CDK Application, to understand the application mechanism, we need to talk about the Visitor pattern.

According to the Gang of Four Design Patterns Book, the Visitor pattern is defined as follows:

Represent an operation to be performed on elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.

Design Patterns: Elements of Reusable Object-Oriented Software (Gamma, Helm, Johnson, Vlissides)

So it’s a typical way to leverage OCP principle from SOLID acronym (classes should be open for extension, but closed for modifications). It should be possible to define a new operation for (some) classes of an object structure without changing the classes.

Aspect definition in TypeScript looks as follows:

interface IAspect { visit(node: IConstruct): void; }

And after instanting a class that implements following interface, we can apply it to a desired scope via this mechanism:

const aspect = new SomeAspect(...); construct.node.applyAspect(aspect)

With the great power comes great responsibility

One thing worth mentioning in this context is that this can tremendously complicate your code and understanding. This is especially problematic because it is an approach and uses cases that may complicate and create a convoluted solution.

A great heuristic, when to use it is when you want to validate a specific prerequisite in a given scope (e.g., tagging, enabling a particular feature across the various applications).

Examples

Let’s start with the adjustments of the example that are described in the official documentation. In our case, it makes much more sense to check if all buckets are encrypted so that we will do so:

import * as cdk from '@aws-cdk/core'; import * as s3 from '@aws-cdk/aws-s3'; export class BucketEncryptionChecker implements cdk.IAspect { public visit(node: cdk.IConstruct): void { if (node instanceof s3.CfnBucket) { if (!node.bucketEncryption) { node.node.addError('Bucket encryption is not enabled'); } } } } // ... // Apply to the given construct: app.node.applyAspect(new BucketEncryptionChecker());
Resulting error after applying aspect without adding the S3 bucket encryption.
Resulting error after applying aspect without adding the S3 bucket encryption.

Also, under the hood tagging mechanism in AWS CDK uses aspects. In this way, we can also apply a unified strategy for tagging our resources:

Tag.add(myConstuct, 'Key', 'Value'); // Or you can apply them based on the resource type: Tag.add(myConstruct, 'Key', 'Value', { includeResourceTypes: ['AWS::Xxx::Yyy'], excludeResourceTypes: ['AWS::Xxx::Zzz'] });

Summary

Aspects are powerful addition, especially for horizontal (aka cross-cutting concerns) elements that are affecting many resources across our AWS CDK Applications.

However, they look and work so cool that they can be abused very easily. Yet, this is true for almost anything introduced by this tool. Be careful and use it as a seasoning – to not spoil the main dish. 😉

By Wojciech Gawroński

Principal Cloud Architect at Pattern Match. Infrastructure as Code, DevOps culture and AWS aficionado. Functional Programming wrangler (Erlang/Elixir).

Comments

This site uses Akismet to reduce spam. Learn how your comment data is processed.