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)
| Parameter | Type | Description |
|---|---|---|
permissionBoundaryArn | string | ARN 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
PermissionsBoundaryproperty on allAWS::IAM::Roleresources - 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
BucketEncryptionproperty on allAWS::S3::Bucketresources - 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
PublicAccessBlockConfigurationon allAWS::S3::Bucketresources - 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
CidrBlockproperty on allAWS::EC2::VPCresources - 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
- Constructs - Resources that aspects validate
- Stacks - Where to apply aspects
- CI/CD Workflows - Aspects run during synth