Awesome-omni-skill aws
AWS hosting and deployment patterns covering compute (EC2, ECS, Lambda), networking (ALB, CloudFront, Route 53, API Gateway), databases (RDS, ElastiCache), infrastructure-as-code (CDK), IAM, monitoring (CloudWatch), and cost optimization. Use when deploying applications to AWS or designing cloud architecture. Triggers on AWS, EC2, ECS, Fargate, Lambda, CloudFront, CDK, API Gateway, Route 53, RDS, IAM.
git clone https://github.com/diegosouzapw/awesome-omni-skill
T=$(mktemp -d) && git clone --depth=1 https://github.com/diegosouzapw/awesome-omni-skill "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/devops/aws" ~/.claude/skills/diegosouzapw-awesome-omni-skill-aws && rm -rf "$T"
skills/devops/aws/SKILL.mdAWS Hosting
AWS provides the broadest set of cloud services. This skill covers the most common hosting patterns for web applications, APIs, and background services, with infrastructure-as-code via AWS CDK.
Architecture Decision Tree
What are you deploying? ├─ Static site (HTML/CSS/JS) ──────────> S3 + CloudFront ├─ Server-rendered app (Next.js, etc.) ─> ECS Fargate or Lambda ├─ REST/GraphQL API ───────────────────> Lambda + API Gateway OR ECS Fargate + ALB ├─ Long-running background workers ────> ECS Fargate (always-on) or EC2 ├─ Event-driven functions ─────────────> Lambda (triggered by SQS, S3, EventBridge) ├─ Containerized microservices ────────> ECS Fargate + ALB + Service Connect └─ Full control over the VM ───────────> EC2 (last resort)
EC2 — Virtual Machines
Use EC2 only when you need full OS-level control, GPU instances, or specific hardware. For most web apps, prefer ECS Fargate or Lambda.
// CDK: EC2 instance import * as ec2 from 'aws-cdk-lib/aws-ec2'; const vpc = new ec2.Vpc(this, 'Vpc', { maxAzs: 2 }); const instance = new ec2.Instance(this, 'WebServer', { vpc, instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MICRO), machineImage: ec2.MachineImage.latestAmazonLinux2023(), keyPair: ec2.KeyPair.fromKeyPairName(this, 'KeyPair', 'my-key'), }); instance.connections.allowFromAnyIpv4(ec2.Port.tcp(80)); instance.connections.allowFromAnyIpv4(ec2.Port.tcp(443));
ECS Fargate — Serverless Containers
The standard choice for containerized web applications. No servers to manage, auto-scaling built in.
import * as ecs from 'aws-cdk-lib/aws-ecs'; import * as ecsPatterns from 'aws-cdk-lib/aws-ecs-patterns'; const cluster = new ecs.Cluster(this, 'Cluster', { vpc }); // Web service with ALB (most common pattern) const service = new ecsPatterns.ApplicationLoadBalancedFargateService(this, 'WebApp', { cluster, cpu: 512, memoryLimitMiB: 1024, desiredCount: 2, taskImageOptions: { image: ecs.ContainerImage.fromAsset('./'), // Build from Dockerfile in root containerPort: 3000, environment: { NODE_ENV: 'production', DATABASE_URL: databaseUrl, }, }, publicLoadBalancer: true, }); // Auto-scaling const scaling = service.service.autoScaleTaskCount({ maxCapacity: 10 }); scaling.scaleOnCpuUtilization('CpuScaling', { targetUtilizationPercent: 70, }); scaling.scaleOnMemoryUtilization('MemoryScaling', { targetUtilizationPercent: 80, });
ECS with custom task definition
const taskDef = new ecs.FargateTaskDefinition(this, 'TaskDef', { cpu: 1024, memoryLimitMiB: 2048, }); taskDef.addContainer('app', { image: ecs.ContainerImage.fromEcrRepository(repo, 'latest'), portMappings: [{ containerPort: 3000 }], logging: ecs.LogDrivers.awsLogs({ streamPrefix: 'app' }), healthCheck: { command: ['CMD-SHELL', 'curl -f http://localhost:3000/health || exit 1'], interval: cdk.Duration.seconds(30), timeout: cdk.Duration.seconds(5), retries: 3, }, });
Lambda — Serverless Functions
Best for event-driven workloads, APIs with variable traffic, and cost-sensitive projects.
import * as lambda from 'aws-cdk-lib/aws-lambda'; import * as lambdaNode from 'aws-cdk-lib/aws-lambda-nodejs'; const handler = new lambdaNode.NodejsFunction(this, 'ApiHandler', { runtime: lambda.Runtime.NODEJS_20_X, entry: 'src/lambda/handler.ts', handler: 'handler', memorySize: 512, timeout: cdk.Duration.seconds(30), environment: { DATABASE_URL: databaseUrl, }, bundling: { minify: true, sourceMap: true, }, });
Lambda handler pattern
// src/lambda/handler.ts import type { APIGatewayProxyHandlerV2 } from 'aws-lambda'; export const handler: APIGatewayProxyHandlerV2 = async (event) => { const body = JSON.parse(event.body ?? '{}'); return { statusCode: 200, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: 'OK', data: body }), }; };
Lambda limitations
| Constraint | Limit |
|---|---|
| Max execution time | 15 minutes |
| Max memory | 10,240 MB |
| Max payload (sync) | 6 MB |
| Max payload (async) | 256 KB |
| Cold start | 100ms-2s (depends on runtime/size) |
| Concurrent executions | 1,000 (default, can increase) |
API Gateway
HTTP API (v2) — Recommended
import * as apigwv2 from 'aws-cdk-lib/aws-apigatewayv2'; import * as integrations from 'aws-cdk-lib/aws-apigatewayv2-integrations'; const httpApi = new apigwv2.HttpApi(this, 'Api', { corsPreflight: { allowOrigins: ['https://myapp.com'], allowMethods: [apigwv2.CorsHttpMethod.GET, apigwv2.CorsHttpMethod.POST], allowHeaders: ['Content-Type', 'Authorization'], }, }); httpApi.addRoutes({ path: '/users/{id}', methods: [apigwv2.HttpMethod.GET], integration: new integrations.HttpLambdaIntegration('GetUser', handler), });
REST API (v1) — When you need request validation, API keys, or usage plans
import * as apigw from 'aws-cdk-lib/aws-apigateway'; const api = new apigw.RestApi(this, 'RestApi', { restApiName: 'MyService', deployOptions: { stageName: 'prod' }, }); const users = api.root.addResource('users'); users.addMethod('GET', new apigw.LambdaIntegration(handler));
CloudFront CDN
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront'; import * as origins from 'aws-cdk-lib/aws-cloudfront-origins'; import * as s3 from 'aws-cdk-lib/aws-s3'; const siteBucket = new s3.Bucket(this, 'SiteBucket', { blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, }); const distribution = new cloudfront.Distribution(this, 'CDN', { defaultBehavior: { origin: origins.S3BucketOrigin.withOriginAccessControl(siteBucket), viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED, }, defaultRootObject: 'index.html', errorResponses: [ { httpStatus: 404, responsePagePath: '/index.html', // SPA fallback responseHttpStatus: 200, }, ], });
Route 53 DNS
import * as route53 from 'aws-cdk-lib/aws-route53'; import * as targets from 'aws-cdk-lib/aws-route53-targets'; const zone = route53.HostedZone.fromLookup(this, 'Zone', { domainName: 'example.com', }); new route53.ARecord(this, 'SiteAlias', { zone, recordName: 'app', // app.example.com target: route53.RecordTarget.fromAlias( new targets.CloudFrontTarget(distribution) ), });
RDS — Relational Database
import * as rds from 'aws-cdk-lib/aws-rds'; const database = new rds.DatabaseInstance(this, 'Database', { engine: rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_16_4, }), instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MICRO), vpc, vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, databaseName: 'myapp', credentials: rds.Credentials.fromGeneratedSecret('dbadmin'), multiAz: false, // true for production allocatedStorage: 20, maxAllocatedStorage: 100, // Auto-scaling storage backupRetention: cdk.Duration.days(7), deletionProtection: true, // Prevent accidental deletion }); // Allow ECS tasks to connect database.connections.allowFrom(service.service, ec2.Port.tcp(5432));
ElastiCache — Redis
import * as elasticache from 'aws-cdk-lib/aws-elasticache'; const subnetGroup = new elasticache.CfnSubnetGroup(this, 'RedisSubnets', { description: 'Subnets for Redis', subnetIds: vpc.privateSubnets.map(s => s.subnetId), }); const redis = new elasticache.CfnCacheCluster(this, 'Redis', { cacheNodeType: 'cache.t3.micro', engine: 'redis', numCacheNodes: 1, cacheSubnetGroupName: subnetGroup.ref, vpcSecurityGroupIds: [redisSecurityGroup.securityGroupId], });
IAM Best Practices
import * as iam from 'aws-cdk-lib/aws-iam'; // Principle of least privilege — grant only what is needed handler.addToRolePolicy(new iam.PolicyStatement({ actions: ['s3:GetObject', 's3:PutObject'], resources: [`${bucket.bucketArn}/uploads/*`], // Scoped to prefix })); // Never use wildcards for actions in production // BAD: actions: ['s3:*'] // GOOD: actions: ['s3:GetObject', 's3:PutObject'] // Use managed policies for common patterns taskDef.taskRole.addManagedPolicy( iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonS3ReadOnlyAccess') );
IAM Anti-Patterns
| Anti-Pattern | Risk | Correct Approach |
|---|---|---|
| Full account access | List specific actions |
| Applies to all resources | Scope to specific ARNs |
| Long-lived access keys | Key rotation burden, leak risk | Use IAM roles (EC2, ECS, Lambda get them automatically) |
| Root account for anything | Unrestricted, unauditable | Create IAM users/roles, enable MFA on root |
| Sharing credentials between services | Blast radius, no audit trail | One role per service |
AWS CDK — Infrastructure as Code
pnpm add -D aws-cdk-lib constructs npx cdk init app --language typescript
CDK Project Structure
infra/ bin/app.ts # Entry point — instantiates stacks lib/ network-stack.ts # VPC, subnets, security groups compute-stack.ts # ECS, Lambda data-stack.ts # RDS, ElastiCache, S3 cdn-stack.ts # CloudFront, Route 53
CDK Commands
npx cdk synth # Generate CloudFormation template npx cdk diff # Preview changes npx cdk deploy # Deploy all stacks npx cdk deploy ComputeStack # Deploy specific stack npx cdk destroy # Tear down
CDK Stack Pattern
import * as cdk from 'aws-cdk-lib'; import { Construct } from 'constructs'; export class ComputeStack extends cdk.Stack { public readonly serviceUrl: string; constructor(scope: Construct, id: string, props: cdk.StackProps & { vpc: ec2.IVpc; databaseUrl: string; }) { super(scope, id, props); // Resources defined here // Export values for cross-stack references this.serviceUrl = service.loadBalancer.loadBalancerDnsName; } }
CloudWatch Monitoring
import * as cloudwatch from 'aws-cdk-lib/aws-cloudwatch'; import * as actions from 'aws-cdk-lib/aws-cloudwatch-actions'; import * as sns from 'aws-cdk-lib/aws-sns'; const alarmTopic = new sns.Topic(this, 'AlarmTopic'); // ECS CPU alarm new cloudwatch.Alarm(this, 'HighCpu', { metric: service.service.metricCpuUtilization(), threshold: 80, evaluationPeriods: 3, comparisonOperator: cloudwatch.ComparisonOperator.GREATER_THAN_THRESHOLD, }).addAlarmAction(new actions.SnsAction(alarmTopic)); // Lambda error rate alarm new cloudwatch.Alarm(this, 'LambdaErrors', { metric: handler.metricErrors({ period: cdk.Duration.minutes(5) }), threshold: 5, evaluationPeriods: 1, }).addAlarmAction(new actions.SnsAction(alarmTopic)); // Custom dashboard const dashboard = new cloudwatch.Dashboard(this, 'AppDashboard'); dashboard.addWidgets( new cloudwatch.GraphWidget({ title: 'ECS CPU & Memory', left: [service.service.metricCpuUtilization()], right: [service.service.metricMemoryUtilization()], }), );
Cost Optimization
| Strategy | Savings | How |
|---|---|---|
| Right-size instances | 30-50% | Use CloudWatch metrics to identify over-provisioned resources |
| Spot instances (ECS) | Up to 90% on compute | Use Fargate Spot for fault-tolerant workloads |
| Reserved instances | 30-60% | Commit to 1-3 year terms for steady-state workloads |
| S3 lifecycle rules | Variable | Move infrequent data to IA/Glacier automatically |
| Lambda right-sizing | 10-40% | Use AWS Lambda Power Tuning to find optimal memory |
| NAT Gateway alternatives | $30+/mo | Use VPC endpoints for S3/DynamoDB, reduce NAT traffic |
| CloudFront caching | Variable | Reduce origin requests with proper cache policies |
| Scheduled scaling | Variable | Scale down non-prod environments nights/weekends |
Fargate Spot for cost savings
const service = new ecsPatterns.ApplicationLoadBalancedFargateService(this, 'App', { cluster, capacityProviderStrategies: [ { capacityProvider: 'FARGATE_SPOT', weight: 2 }, { capacityProvider: 'FARGATE', weight: 1 }, // Fallback to on-demand ], taskImageOptions: { image: ecs.ContainerImage.fromAsset('./') }, });
Common Architecture Patterns
Static Site
Route 53 -> CloudFront -> S3 (static files)
API + Database
Route 53 -> CloudFront -> API Gateway -> Lambda -> RDS -> ElastiCache (caching)
Containerized Web App
Route 53 -> CloudFront -> ALB -> ECS Fargate (2+ tasks) | RDS (private subnet)
Event-Driven Processing
S3 upload -> EventBridge -> Lambda -> DynamoDB SQS queue -> Lambda -> External API Schedule -> EventBridge -> Lambda -> SNS notification
Anti-Patterns
| Anti-Pattern | Why It Fails | Correct Approach |
|---|---|---|
| Public subnets for databases | Direct internet exposure | Private subnets, access only via application layer |
| No health checks on ALB targets | Traffic routed to dead instances | Configure endpoint, set healthy thresholds |
| Lambda with VPC when not needed | Cold start penalty (seconds) | Only put Lambda in VPC if it needs private resources |
| Hardcoding region/account IDs | Breaks multi-env deploys | Use and env variables |
| One giant CloudFormation stack | Slow deploys, blast radius | Split into network, compute, data, CDN stacks |
| Not enabling deletion protection | Accidental kills DB | Set on RDS, |
| Storing secrets in environment variables | Visible in console, logs | Use AWS Secrets Manager or SSM Parameter Store |