Aspects

Cross-cutting governance rules for IAM, S3, and VPC resources in the AWS CDK Starter Kit.


Overview

Aspects apply cross-cutting rules to all resources in a scope. The starter kit includes security and validation aspects you can enable globally or per-stack.

PermissionBoundaryAspect

Source: src/aspects/permission-boundary-aspect.ts

Attaches a permissions boundary to every IAM role in the scope. Prevents privilege escalation by limiting what roles can do, regardless of their attached policies.

Constructor

new PermissionBoundaryAspect(permissionBoundaryArn: string)
ParameterTypeDescription
permissionBoundaryArnstringARN of the IAM permissions boundary policy

Usage

import * as cdk from 'aws-cdk-lib';
import { PermissionBoundaryAspect } from '../aspects/permission-boundary-aspect';

const accountId = process.env.CDK_DEFAULT_ACCOUNT;

cdk.Aspects.of(app).add(
  new PermissionBoundaryAspect(
    `arn:aws:iam::${accountId}:policy/base-permission-boundary`
  )
);

Behavior

  • Overrides the PermissionsBoundary property on all AWS::IAM::Role resources
  • Applied during synthesis
  • No runtime impact

BucketEncryptionAspect

Source: src/aspects/s3-aspect.ts

Validates that all S3 buckets have server-side encryption enabled. Fails synthesis if any bucket lacks encryption.

Constructor

new BucketEncryptionAspect()

No parameters required.

Usage

import * as cdk from 'aws-cdk-lib';
import { BucketEncryptionAspect } from '../aspects/s3-aspect';

cdk.Aspects.of(app).add(new BucketEncryptionAspect());

Behavior

  • Checks BucketEncryption property on all AWS::S3::Bucket resources
  • Adds synthesis error if encryption is missing
  • Does not auto-fix (requires manual correction)

BucketPublicAccessAspect

Source: src/aspects/s3-aspect.ts

Ensures all S3 buckets block public access. Auto-fixes non-compliant buckets and adds a warning.

Constructor

new BucketPublicAccessAspect()

No parameters required.

Usage

import * as cdk from 'aws-cdk-lib';
import { BucketPublicAccessAspect } from '../aspects/s3-aspect';

cdk.Aspects.of(app).add(new BucketPublicAccessAspect());

Behavior

  • Checks PublicAccessBlockConfiguration on all AWS::S3::Bucket resources
  • Auto-sets block all public access if missing
  • Adds synthesis warning when auto-fixing

vpcCidrAspect

Source: src/aspects/vpc-aspect.ts

Validates that VPC CIDR blocks use RFC1918 private address ranges. Prevents accidental use of public IP ranges in VPCs.

Constructor

new vpcCidrAspect()

No parameters required.

Usage

import * as cdk from 'aws-cdk-lib';
import { vpcCidrAspect } from '../aspects/vpc-aspect';

cdk.Aspects.of(app).add(new vpcCidrAspect());

Behavior

  • Checks CidrBlock property on all AWS::EC2::VPC resources
  • Valid ranges: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
  • Adds synthesis error for non-compliant CIDRs

Applying aspects

Apply aspects at different scopes depending on your needs:

import * as cdk from 'aws-cdk-lib';

const app = new cdk.App();

// Apply to entire app (all stacks)
cdk.Aspects.of(app).add(new BucketEncryptionAspect());

// Apply to specific stack only
const myStack = new MyStack(app, 'MyStack');
cdk.Aspects.of(myStack).add(new PermissionBoundaryAspect(boundaryArn));

// Apply to specific construct
const myConstruct = new MyConstruct(myStack, 'MyConstruct');
cdk.Aspects.of(myConstruct).add(new BucketPublicAccessAspect());

Creating custom aspects

Follow this pattern for new governance rules:

// src/aspects/my-aspect.ts
import * as cdk from 'aws-cdk-lib';
import { IConstruct } from 'constructs';

export class MyCustomAspect implements cdk.IAspect {
  public visit(node: IConstruct): void {
    if (node instanceof cdk.CfnResource) {
      // Check resource type
      if (node.cfnResourceType === 'AWS::Lambda::Function') {
        // Add validation or modification logic
        const timeout = node.getAtt('Timeout');
        if (!timeout) {
          cdk.Annotations.of(node).addWarning('Lambda timeout not set');
        }
      }
    }
  }
}

Next steps