AWS Patterns
VPC Design (3-tier)
VPC: 10.0.0.0/16
Public subnets (10.0.1.0/24, 10.0.2.0/24) — ALB, NAT Gateway
Private subnets (10.0.10.0/24, 10.0.11.0/24) — ECS/EKS workloads
Data subnets (10.0.20.0/24, 10.0.21.0/24) — RDS, ElastiCache
IAM Least Privilege (CDK)
from aws_cdk import aws_iam as iam
lambda_role = iam.Role(self, "LambdaRole",
assumed_by=iam.ServicePrincipal("lambda.amazonaws.com"),
managed_policies=[
iam.ManagedPolicy.from_aws_managed_policy_name(
"service-role/AWSLambdaVPCAccessExecutionRole"
)
]
)
# Only the specific S3 bucket, not *
lambda_role.add_to_policy(iam.PolicyStatement(
actions=["s3:GetObject", "s3:PutObject"],
resources=[f"{bucket.bucket_arn}/*"],
effect=iam.Effect.ALLOW,
))
Lambda Function (CDK)
from aws_cdk import aws_lambda as lambda_, Duration
fn = lambda_.Function(self, "ApiHandler",
runtime=lambda_.Runtime.PYTHON_3_12,
handler="handler.main",
code=lambda_.Code.from_asset("src"),
timeout=Duration.seconds(30),
memory_size=512,
environment={
"TABLE_NAME": table.table_name,
"LOG_LEVEL": "INFO",
},
tracing=lambda_.Tracing.ACTIVE, # X-Ray
reserved_concurrent_executions=100,
)
table.grant_read_write_data(fn)
ECS Fargate Service (CDK)
from aws_cdk import aws_ecs as ecs, aws_ecs_patterns as patterns
service = patterns.ApplicationLoadBalancedFargateService(self, "Service",
cluster=cluster,
task_image_options=patterns.ApplicationLoadBalancedTaskImageOptions(
image=ecs.ContainerImage.from_ecr_repository(repo, tag="1.2.3"),
container_port=8080,
environment={"LOG_LEVEL": "info"},
secrets={"DB_PASSWORD": ecs.Secret.from_secrets_manager(secret)},
),
desired_count=2,
cpu=512,
memory_limit_mib=1024,
health_check_grace_period=Duration.seconds(60),
)
# Auto-scaling
scaling = service.service.auto_scale_task_count(max_capacity=10)
scaling.scale_on_cpu_utilization("CpuScaling",
target_utilization_percent=70,
scale_in_cooldown=Duration.seconds(60),
scale_out_cooldown=Duration.seconds(30),
)
RDS Aurora Serverless v2 (CDK)
from aws_cdk import aws_rds as rds
cluster = rds.DatabaseCluster(self, "DB",
engine=rds.DatabaseClusterEngine.aurora_postgres(
version=rds.AuroraPostgresEngineVersion.VER_15_4
),
serverless_v2_min_capacity=0.5,
serverless_v2_max_capacity=16,
writer=rds.ClusterInstance.serverless_v2("writer"),
readers=[rds.ClusterInstance.serverless_v2("reader", scale_with_writer=True)],
vpc=vpc,
vpc_subnets=ec2.SubnetSelection(subnet_type=ec2.SubnetType.PRIVATE_WITH_EGRESS),
backup=rds.BackupProps(retention=Duration.days(7)),
deletion_protection=True,
storage_encrypted=True,
)
S3 + CloudFront (CDK)
from aws_cdk import aws_s3 as s3, aws_cloudfront as cf, aws_cloudfront_origins as origins
bucket = s3.Bucket(self, "Assets",
block_public_access=s3.BlockPublicAccess.BLOCK_ALL,
encryption=s3.BucketEncryption.S3_MANAGED,
enforce_ssl=True,
)
distribution = cf.Distribution(self, "CDN",
default_behavior=cf.BehaviorOptions(
origin=origins.S3BucketOrigin.with_origin_access_control(bucket),
viewer_protocol_policy=cf.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
cache_policy=cf.CachePolicy.CACHING_OPTIMIZED,
),
price_class=cf.PriceClass.PRICE_CLASS_100,
)
Key Rules
- Enable CloudTrail + GuardDuty in every account by default
- Use AWS Secrets Manager, not SSM Parameter Store, for sensitive values
- Tag all resources:
Environment, Team, CostCenter, ManagedBy
- Enable VPC Flow Logs for security forensics
- Never use root account credentials — create IAM users/roles per team