AWS — Practical
AWS — Practical (commands & patterns)
Section titled “AWS — Practical (commands & patterns)”CLI cheats
Section titled “CLI cheats”# whoamiaws sts get-caller-identityaws configure list-profiles
# assume roleaws sts assume-role --role-arn ROLE --role-session-name s | jq
# S3aws s3 cp file.txt s3://bkt/path/aws s3 sync ./dist s3://bkt --deleteaws s3 presign s3://bkt/key --expires-in 3600
# EC2aws ec2 describe-instances \ --query 'Reservations[].Instances[].[InstanceId,Tags[?Key==`Name`].Value|[0],State.Name]' \ --output tableaws ec2 start-instances --instance-ids i-xxxaws ssm start-session --target i-xxx # SSH-less shell
# Logsaws logs tail /aws/lambda/fn --since 30m --follow --filter-pattern ERRORaws logs start-query --log-group-name /app --start-time $(date +%s -d '-1h') --end-time $(date +%s) \ --query-string 'fields @timestamp, @message | filter @message like /ERROR/'
# Lambdaaws lambda invoke --function-name fn --payload '{"x":1}' out.jsonaws lambda update-function-code --function-name fn --zip-file fileb://app.zip
# Secretsaws secretsmanager get-secret-value --secret-id db/prod | jq -r .SecretStringaws ssm get-parameter --name /app/api_key --with-decryption | jq -r .Parameter.ValueIAM policy snippets
Section titled “IAM policy snippets”// Least-privilege S3 read on a prefix{ "Effect": "Allow", "Action": ["s3:GetObject", "s3:ListBucket"], "Resource": ["arn:aws:s3:::bkt", "arn:aws:s3:::bkt/uploads/*"]}
// Trust policy for a role assumed by Lambda{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" }]}
// Cross-account access via session tag{ "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": "arn:aws:iam::222222222222:role/Reader", "Condition": { "StringEquals": { "aws:PrincipalTag/team": "data" } }}VPC layout (typical 3-tier)
Section titled “VPC layout (typical 3-tier)”VPC 10.0.0.0/16 AZ-a: public 10.0.0.0/24 (ALB, NAT) private 10.0.1.0/24 (app) db 10.0.2.0/24 (RDS, Redis) AZ-b: public 10.0.10.0/24 private 10.0.11.0/24 db 10.0.12.0/24 AZ-c: ...- IGW attached.
- 1 NAT GW per AZ for HA (or 1 if cost-conscious).
- VPC Endpoints for S3, DynamoDB, SSM, Secrets, ECR.
- SG rules: ALB → app on 8080; app → RDS on 5432; deny all else.
Terraform — minimal Lambda + API
Section titled “Terraform — minimal Lambda + API”resource "aws_iam_role" "fn" { name = "fn-role" assume_role_policy = data.aws_iam_policy_document.assume.json}data "aws_iam_policy_document" "assume" { statement { actions = ["sts:AssumeRole"] principals { type = "Service" identifiers = ["lambda.amazonaws.com"] } }}resource "aws_iam_role_policy_attachment" "logs" { role = aws_iam_role.fn.name policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"}
resource "aws_lambda_function" "fn" { function_name = "demo" runtime = "nodejs20.x" handler = "index.handler" role = aws_iam_role.fn.arn filename = "app.zip" source_code_hash = filebase64sha256("app.zip") architectures = ["arm64"] memory_size = 256 timeout = 10}
resource "aws_apigatewayv2_api" "api" { name = "demo" protocol_type = "HTTP"}resource "aws_apigatewayv2_integration" "lambda" { api_id = aws_apigatewayv2_api.api.id integration_type = "AWS_PROXY" integration_uri = aws_lambda_function.fn.invoke_arn payload_format_version = "2.0"}resource "aws_apigatewayv2_route" "default" { api_id = aws_apigatewayv2_api.api.id route_key = "$default" target = "integrations/${aws_apigatewayv2_integration.lambda.id}"}resource "aws_lambda_permission" "apigw" { statement_id = "AllowAPIGW" action = "lambda:InvokeFunction" function_name = aws_lambda_function.fn.function_name principal = "apigateway.amazonaws.com" source_arn = "${aws_apigatewayv2_api.api.execution_arn}/*"}DynamoDB single-table sketch
Section titled “DynamoDB single-table sketch”PK SK attrsUSER#123 PROFILE { name, email }USER#123 ORDER#2026-... { total, items }ORDER#x META { status }GSI1PK=ORDER#x GSI1SK=USER#123 (reverse lookup)Queries:
- Get user profile:
PK=USER#123 AND SK=PROFILE. - List user orders:
PK=USER#123 AND begins_with(SK, "ORDER#"). - Find user by order id: GSI1.
CloudWatch alarms (essentials)
Section titled “CloudWatch alarms (essentials)”resource "aws_cloudwatch_metric_alarm" "lambda_errors" { alarm_name = "fn-errors" comparison_operator = "GreaterThanThreshold" evaluation_periods = 2 metric_name = "Errors" namespace = "AWS/Lambda" period = 60 statistic = "Sum" threshold = 5 dimensions = { FunctionName = aws_lambda_function.fn.function_name } alarm_actions = [aws_sns_topic.alerts.arn]}Container image lifecycle (ECR)
Section titled “Container image lifecycle (ECR)”resource "aws_ecr_lifecycle_policy" "p" { repository = aws_ecr_repository.r.name policy = jsonencode({ rules = [{ rulePriority = 1 description = "Keep last 30 images" selection = { tagStatus = "any", countType = "imageCountMoreThan", countNumber = 30 } action = { type = "expire" } }] })}Cost tagging
Section titled “Cost tagging”provider "aws" { default_tags { tags = { Owner = "platform-team" Environment = "prod" Project = "X" ManagedBy = "terraform" } }}Common gotchas
Section titled “Common gotchas”- ALB target group health check path matches actual health endpoint, not
/. - Lambda cold start spikes during deploy unless using alias with provisioned concurrency.
- RDS minor version upgrade can restart instance — schedule windows.
- KMS request rate quota — bursty workloads can throttle.
- DynamoDB hot partition shows as throttles; check Contributor Insights.
- S3 cross-region replication doesn’t cover existing objects (must batch replicate).
- Spot interruption can drop your fleet — design for it.
- API Gateway integration timeout is 30s max.
Recommended tools
Section titled “Recommended tools”- AWS CDK / Pulumi / Terraform — IaC.
- AWS SAM — serverless tool (Lambda + API GW + DDB).
- awscli-local + LocalStack — local dev/test.
- aws-vault — secure CLI creds.
- gp / Steampipe — query AWS like SQL.
- CloudShell — browser shell.
- CloudCustodian — policy/cost enforcement.