Skip to content

AWS — Practical

Terminal window
# whoami
aws sts get-caller-identity
aws configure list-profiles
# assume role
aws sts assume-role --role-arn ROLE --role-session-name s | jq
# S3
aws s3 cp file.txt s3://bkt/path/
aws s3 sync ./dist s3://bkt --delete
aws s3 presign s3://bkt/key --expires-in 3600
# EC2
aws ec2 describe-instances \
--query 'Reservations[].Instances[].[InstanceId,Tags[?Key==`Name`].Value|[0],State.Name]' \
--output table
aws ec2 start-instances --instance-ids i-xxx
aws ssm start-session --target i-xxx # SSH-less shell
# Logs
aws logs tail /aws/lambda/fn --since 30m --follow --filter-pattern ERROR
aws 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/'
# Lambda
aws lambda invoke --function-name fn --payload '{"x":1}' out.json
aws lambda update-function-code --function-name fn --zip-file fileb://app.zip
# Secrets
aws secretsmanager get-secret-value --secret-id db/prod | jq -r .SecretString
aws ssm get-parameter --name /app/api_key --with-decryption | jq -r .Parameter.Value
// 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 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.
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}/*"
}
PK SK attrs
USER#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.
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]
}
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" }
}] })
}
provider "aws" {
default_tags {
tags = {
Owner = "platform-team"
Environment = "prod"
Project = "X"
ManagedBy = "terraform"
}
}
}
  • 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.
  • 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.