Best Practices
Learn industry best practices for CDK development with real-world examples. See how to build secure, performant, and cost-effective infrastructure using AWS CDK.
💡 Note: These are general AWS CDK best practices. CDK Insights automatically detects many of these issues, including: unencrypted S3 buckets, overly permissive IAM policies, missing versioning, public access configurations, and more. The examples below show both what to avoid (which CDK Insights will flag) and recommended implementations.
Best Practice Categories
Security
Essential security practices for CDK applications
- Principle of least privilege
- Encryption at rest and in transit
- Network security controls
- Secrets management
Performance
Optimization strategies for better performance
- Resource sizing optimization
- Caching strategies
- Connection pooling
- Auto-scaling configuration
Cost Optimization
Cost-effective infrastructure patterns
- Right-sizing resources
- Reserved instances usage
- Lifecycle policies
- Monitoring and alerting
Maintainability
Code organization and maintainability
- Consistent naming conventions
- Modular architecture
- Comprehensive documentation
- Testing strategies
Security Best Practices
S3 Bucket Security
Implement secure S3 bucket configuration
❌ Avoid This:
// ❌ Insecure S3 bucket
new s3.Bucket(this, 'DataBucket', {
publicReadAccess: true,
removalPolicy: RemovalPolicy.DESTROY,
// No encryption, no access logging
});✅ Do This Instead:
// ✅ Secure S3 bucket
new s3.Bucket(this, 'DataBucket', {
// Block all public access
blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
// Enable encryption
encryption: s3.BucketEncryption.S3_MANAGED,
// Enable versioning
versioned: true,
// Enable access logging
serverAccessLogsBucket: accessLogsBucket,
// Lifecycle policy for cost optimization
lifecycleRules: [
{
id: 'DeleteIncompleteMultipartUploads',
abortIncompleteMultipartUploadAfter: Duration.days(1),
},
{
id: 'TransitionToIA',
transitions: [
{
storageClass: s3.StorageClass.INFREQUENT_ACCESS,
transitionAfter: Duration.days(30),
},
],
},
],
// Prevent accidental deletion
removalPolicy: RemovalPolicy.RETAIN,
});Benefits:
IAM Role Best Practices
Create least-privilege IAM roles
❌ Avoid This:
// ❌ Overly permissive IAM role
new iam.Role(this, 'LambdaRole', {
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
managedPolicies: [
iam.ManagedPolicy.fromAwsManagedPolicyName('AdministratorAccess'), // Too broad!
],
});✅ Do This Instead:
// ✅ Least-privilege IAM role
new iam.Role(this, 'LambdaRole', {
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
// Use minimal managed policies
managedPolicies: [
iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole'),
],
// Specific inline policies
inlinePolicies: {
S3Access: new iam.PolicyDocument({
statements: [
new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: ['s3:GetObject'],
resources: [
`${dataBucket.bucketArn}/specific-folder/*`,
],
}),
new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: ['s3:PutObject'],
resources: [
`${outputBucket.bucketArn}/processed/*`,
],
}),
],
}),
},
// Set maximum session duration
maxSessionDuration: Duration.hours(1),
});Benefits:
VPC Security Configuration
Secure network configuration for VPC
❌ Avoid This:
// ❌ Insecure VPC configuration
const vpc = new ec2.Vpc(this, 'VPC', {
maxAzs: 2,
});
// Public subnet with no restrictions
const publicSubnet = vpc.publicSubnets[0];
new ec2.SecurityGroup(this, 'WebSG', {
vpc: vpc,
allowAllOutbound: true,
});
publicSubnet.securityGroup.addIngressRule(
ec2.Peer.anyIpv4(),
ec2.Port.allTraffic(), // Too permissive!
);✅ Do This Instead:
// ✅ Secure VPC configuration
const vpc = new ec2.Vpc(this, 'VPC', {
maxAzs: 2,
subnetConfiguration: [
{
cidrMask: 24,
name: 'Public',
subnetType: ec2.SubnetType.PUBLIC,
},
{
cidrMask: 24,
name: 'Private',
subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
},
{
cidrMask: 28,
name: 'Database',
subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
},
],
});
// Web tier security group
const webSecurityGroup = new ec2.SecurityGroup(this, 'WebSG', {
vpc: vpc,
description: 'Security group for web servers',
allowAllOutbound: false,
});
webSecurityGroup.addIngressRule(
ec2.Peer.anyIpv4(),
ec2.Port.tcp(80),
'Allow HTTP from anywhere'
);
webSecurityGroup.addIngressRule(
ec2.Peer.anyIpv4(),
ec2.Port.tcp(443),
'Allow HTTPS from anywhere'
);
// Application tier security group
const appSecurityGroup = new ec2.SecurityGroup(this, 'AppSG', {
vpc: vpc,
description: 'Security group for application servers',
allowAllOutbound: false,
});
appSecurityGroup.addIngressRule(
webSecurityGroup,
ec2.Port.tcp(8080),
'Allow traffic from web tier'
);Benefits:
Performance Best Practices
Lambda Function Optimization
Optimize Lambda function configuration
❌ Inefficient:
// ❌ Inefficient Lambda configuration
new lambda.Function(this, 'DataProcessor', {
runtime: lambda.Runtime.NODEJS_14_X, // Outdated runtime
handler: 'index.handler',
code: lambda.Code.fromAsset('lambda'),
memorySize: 3008, // Maximum memory (expensive)
timeout: Duration.minutes(15), // Too long
// No environment variables, no dead letter queue
});✅ Optimized:
// ✅ Optimized Lambda configuration
new lambda.Function(this, 'DataProcessor', {
runtime: lambda.Runtime.NODEJS_18_X, // Latest LTS
handler: 'index.handler',
code: lambda.Code.fromAsset('lambda'),
// Right-sized memory based on actual usage
memorySize: 512,
// Appropriate timeout
timeout: Duration.minutes(5),
// Environment variables
environment: {
LOG_LEVEL: 'INFO',
MAX_RETRIES: '3',
S3_BUCKET: dataBucket.bucketName,
},
// Dead letter queue for failed invocations
deadLetterQueue: new sqs.Queue(this, 'DLQ'),
// Reserved concurrency to prevent cost spikes
reservedConcurrency: 10,
// Enable X-Ray tracing
tracing: lambda.Tracing.ACTIVE,
// Retry configuration
retryAttempts: 2,
});Benefits:
RDS Database Optimization
Optimize RDS database configuration
❌ Inefficient:
// ❌ Inefficient RDS configuration
new rds.DatabaseInstance(this, 'Database', {
engine: rds.DatabaseInstanceEngine.mysql({
version: rds.MysqlEngineVersion.VER_5_7, // Outdated version
}),
instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.XLARGE),
allocatedStorage: 100, // Fixed storage
storageEncrypted: false, // No encryption
backupRetention: Duration.days(7), // Short retention
// No monitoring, no parameter group
});✅ Optimized:
// ✅ Optimized RDS configuration
new rds.DatabaseInstance(this, 'Database', {
engine: rds.DatabaseInstanceEngine.mysql({
version: rds.MysqlEngineVersion.VER_8_0, // Latest version
}),
// Right-sized instance
instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MEDIUM),
// Auto-scaling storage
allocatedStorage: 20,
maxAllocatedStorage: 100,
// Enable encryption
storageEncrypted: true,
storageEncryptionKey: encryptionKey,
// Enhanced monitoring
monitoringInterval: Duration.seconds(60),
enablePerformanceInsights: true,
// Backup configuration
backupRetention: Duration.days(30),
deleteAutomatedBackups: false,
// Parameter group for optimization
parameterGroup: new rds.ParameterGroup(this, 'DBParams', {
engine: rds.DatabaseInstanceEngine.mysql({
version: rds.MysqlEngineVersion.VER_8_0,
}),
parameters: {
innodb_buffer_pool_size: '{DBInstanceClassMemory*3/4}',
max_connections: '100',
},
}),
// Multi-AZ for high availability
multiAz: true,
// VPC configuration
vpc: vpc,
vpcSubnets: {
subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
},
});Benefits:
Cost Optimization Best Practices
Auto Scaling Configuration
Implement cost-effective auto scaling
// ✅ Cost-optimized auto scaling
const autoScalingGroup = new autoscaling.AutoScalingGroup(this, 'ASG', {
vpc: vpc,
instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MICRO),
machineImage: ec2.MachineImage.latestAmazonLinux(),
minCapacity: 1,
maxCapacity: 10,
desiredCapacity: 2,
// Use Spot instances for cost savings
mixedInstancesPolicy: {
instancesDistribution: {
onDemandPercentageAboveBaseCapacity: 20, // 20% on-demand, 80% spot
spotAllocationStrategy: autoscaling.SpotAllocationStrategy.CAPACITY_OPTIMIZED,
},
instancesTypes: [
ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MICRO),
ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.SMALL),
],
},
// Scaling policies
scalingPolicies: [
{
id: 'ScaleUp',
scalingTarget: {
metric: new cloudwatch.Metric({
namespace: 'AWS/EC2',
metricName: 'CPUUtilization',
statistic: 'Average',
}),
targetValue: 70,
},
scaleOutCooldown: Duration.minutes(5),
scaleInCooldown: Duration.minutes(10),
},
],
// Lifecycle hooks for graceful shutdowns
lifecycleHook: {
defaultResult: autoscaling.DefaultResult.ABANDON,
heartbeatTimeout: Duration.minutes(5),
},
});Benefits:
Implementation Checklist
Security Checklist
- Enable encryption for all storage services
- Implement least-privilege IAM policies
- Use VPC security groups appropriately
- Enable CloudTrail logging
- Implement secrets management
- Use HTTPS/TLS everywhere
Performance Checklist
- Right-size all compute resources
- Implement auto-scaling policies
- Use appropriate caching strategies
- Enable monitoring and alerting
- Optimize database configurations
- Use CDN for static content
Ready to Implement Best Practices?
Start applying these best practices to your CDK projects and use CDK Insights to validate your implementations.