Toolmingo
Guides14 min read

AWS Cheat Sheet: CLI Commands, Services, and Architecture Patterns

A complete AWS cheat sheet — AWS CLI commands, IAM, EC2, S3, Lambda, RDS, CloudFormation, and common architecture patterns. Copy-ready examples for every AWS service.

AWS (Amazon Web Services) is the world's most widely adopted cloud platform, with over 200 fully featured services. This cheat sheet covers the AWS CLI, the most important services, and the patterns you use every day.

Quick reference

The AWS CLI commands you reach for most often.

Command What it does
aws configure Set up credentials and region
aws s3 ls List all S3 buckets
aws s3 cp file.txt s3://bucket/ Upload file to S3
aws s3 sync ./dist s3://bucket/ Sync folder to S3
aws ec2 describe-instances List EC2 instances
aws ec2 start-instances --instance-ids i-xxx Start an instance
aws ec2 stop-instances --instance-ids i-xxx Stop an instance
aws lambda invoke --function-name fn out.json Invoke a Lambda
aws logs tail /aws/lambda/fn --follow Stream Lambda logs
aws sts get-caller-identity Show current IAM identity
aws cloudformation deploy --stack-name ... Deploy CloudFormation stack
aws rds describe-db-instances List RDS databases
aws iam list-users List IAM users
aws ssm get-parameter --name /app/secret Fetch SSM parameter

AWS CLI setup

Installation

# macOS (Homebrew)
brew install awscli

# Linux
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o awscliv2.zip
unzip awscliv2.zip && sudo ./aws/install

# Windows (PowerShell)
msiexec.exe /i https://awscli.amazonaws.com/AWSCLIV2.msi

# Verify
aws --version

Configure credentials

# Interactive setup (writes ~/.aws/credentials and ~/.aws/config)
aws configure

# You will be prompted:
# AWS Access Key ID: AKIA...
# AWS Secret Access Key: ...
# Default region: eu-west-1
# Default output format: json

# Use a named profile
aws configure --profile prod
aws s3 ls --profile prod

# Temporary credentials via STS (MFA)
aws sts get-session-token \
  --serial-number arn:aws:iam::123456789:mfa/user \
  --token-code 123456

# Export env vars (overrides config)
export AWS_ACCESS_KEY_ID=AKIA...
export AWS_SECRET_ACCESS_KEY=...
export AWS_DEFAULT_REGION=eu-west-1

Useful CLI flags

--region eu-west-1          # Override region for one command
--profile staging           # Use named profile
--output json|text|table|yaml
--query 'Instances[*].InstanceId'   # JMESPath filter
--no-sign-request           # Public buckets without creds
--dry-run                   # Validate without executing (EC2)

S3 (Simple Storage Service)

Object storage — the backbone of almost every AWS workload.

Bucket operations

# List buckets
aws s3 ls

# Create bucket (us-east-1 has no LocationConstraint)
aws s3 mb s3://my-bucket
aws s3 mb s3://my-bucket --region eu-west-1

# Delete empty bucket
aws s3 rb s3://my-bucket

# Force-delete bucket with all objects
aws s3 rb s3://my-bucket --force

Object operations

# List objects
aws s3 ls s3://my-bucket/
aws s3 ls s3://my-bucket/prefix/ --recursive --human-readable

# Upload
aws s3 cp file.txt s3://my-bucket/
aws s3 cp file.txt s3://my-bucket/folder/file.txt
aws s3 cp ./dist/ s3://my-bucket/ --recursive

# Download
aws s3 cp s3://my-bucket/file.txt .
aws s3 cp s3://my-bucket/ ./local/ --recursive

# Sync (only changed files, great for deploys)
aws s3 sync ./build s3://my-bucket/ --delete
aws s3 sync s3://my-bucket/ ./backup/

# Delete object
aws s3 rm s3://my-bucket/file.txt
aws s3 rm s3://my-bucket/folder/ --recursive

# Move/rename
aws s3 mv s3://my-bucket/old.txt s3://my-bucket/new.txt

# Presigned URL (time-limited access)
aws s3 presign s3://my-bucket/private.pdf --expires-in 3600

S3 static website hosting

# Enable website hosting
aws s3 website s3://my-bucket \
  --index-document index.html \
  --error-document error.html

# Make bucket public (website hosting)
aws s3api put-bucket-policy --bucket my-bucket --policy '{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": "*",
    "Action": "s3:GetObject",
    "Resource": "arn:aws:s3:::my-bucket/*"
  }]
}'

EC2 (Elastic Compute Cloud)

Virtual machines in the cloud.

Instance management

# List instances
aws ec2 describe-instances \
  --query 'Reservations[*].Instances[*].[InstanceId,State.Name,PublicIpAddress,Tags[?Key==`Name`].Value|[0]]' \
  --output table

# Start / stop / reboot / terminate
aws ec2 start-instances --instance-ids i-0abc123
aws ec2 stop-instances --instance-ids i-0abc123
aws ec2 reboot-instances --instance-ids i-0abc123
aws ec2 terminate-instances --instance-ids i-0abc123

# Launch instance
aws ec2 run-instances \
  --image-id ami-0c101f26f147fa7fd \
  --instance-type t3.micro \
  --key-name my-key \
  --security-group-ids sg-0abc123 \
  --subnet-id subnet-0abc123 \
  --count 1 \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=web-server}]'

# SSH into instance
aws ec2-instance-connect send-ssh-public-key \
  --instance-id i-0abc123 \
  --instance-os-user ec2-user \
  --ssh-public-key file://~/.ssh/id_rsa.pub
ssh ec2-user@<public-ip>

Key pairs and security groups

# Create key pair
aws ec2 create-key-pair \
  --key-name my-key \
  --query 'KeyMaterial' \
  --output text > my-key.pem
chmod 400 my-key.pem

# Create security group
aws ec2 create-security-group \
  --group-name web-sg \
  --description "Web server SG" \
  --vpc-id vpc-0abc123

# Allow inbound HTTP/HTTPS/SSH
aws ec2 authorize-security-group-ingress \
  --group-id sg-0abc123 \
  --protocol tcp --port 80 --cidr 0.0.0.0/0
aws ec2 authorize-security-group-ingress \
  --group-id sg-0abc123 \
  --protocol tcp --port 443 --cidr 0.0.0.0/0
aws ec2 authorize-security-group-ingress \
  --group-id sg-0abc123 \
  --protocol tcp --port 22 --cidr MY.IP.ADD.RESS/32

AMIs and snapshots

# List available AMIs (Amazon Linux 2023)
aws ec2 describe-images \
  --owners amazon \
  --filters "Name=name,Values=al2023-ami-*" \
  --query 'sort_by(Images, &CreationDate)[-1].ImageId'

# Create AMI from instance
aws ec2 create-image \
  --instance-id i-0abc123 \
  --name "my-server-backup-$(date +%Y-%m-%d)" \
  --no-reboot

# Create snapshot
aws ec2 create-snapshot \
  --volume-id vol-0abc123 \
  --description "Weekly backup"

IAM (Identity and Access Management)

Control who can do what in your AWS account.

Users and groups

# List users
aws iam list-users --query 'Users[*].[UserName,CreateDate]' --output table

# Create user
aws iam create-user --user-name alice

# Add user to group
aws iam add-user-to-group --user-name alice --group-name developers

# Create access keys
aws iam create-access-key --user-name alice

# Delete access key
aws iam delete-access-key --user-name alice --access-key-id AKIA...

# Attach managed policy
aws iam attach-user-policy \
  --user-name alice \
  --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess

Roles and policies

# Create role (for EC2 to access S3)
aws iam create-role \
  --role-name ec2-s3-role \
  --assume-role-policy-document '{
    "Version": "2012-10-17",
    "Statement": [{
      "Effect": "Allow",
      "Principal": { "Service": "ec2.amazonaws.com" },
      "Action": "sts:AssumeRole"
    }]
  }'

# Attach policy to role
aws iam attach-role-policy \
  --role-name ec2-s3-role \
  --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess

# Create instance profile (attach role to EC2)
aws iam create-instance-profile --instance-profile-name ec2-s3-profile
aws iam add-role-to-instance-profile \
  --instance-profile-name ec2-s3-profile \
  --role-name ec2-s3-role

# Who am I?
aws sts get-caller-identity

Inline policy example

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:PutObject"],
      "Resource": "arn:aws:s3:::my-bucket/*"
    },
    {
      "Effect": "Allow",
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::my-bucket"
    }
  ]
}

Lambda

Serverless functions — run code without managing servers.

# List functions
aws lambda list-functions \
  --query 'Functions[*].[FunctionName,Runtime,LastModified]' \
  --output table

# Create function (from zip)
zip function.zip index.js
aws lambda create-function \
  --function-name my-function \
  --runtime nodejs20.x \
  --role arn:aws:iam::123456789:role/lambda-role \
  --handler index.handler \
  --zip-file fileb://function.zip

# Update function code
zip function.zip index.js
aws lambda update-function-code \
  --function-name my-function \
  --zip-file fileb://function.zip

# Invoke function
aws lambda invoke \
  --function-name my-function \
  --payload '{"key":"value"}' \
  --cli-binary-format raw-in-base64-out \
  output.json
cat output.json

# Invoke asynchronously
aws lambda invoke \
  --function-name my-function \
  --invocation-type Event \
  --payload '{}' \
  --cli-binary-format raw-in-base64-out \
  /dev/null

# View logs
aws logs tail /aws/lambda/my-function --follow

# Set environment variables
aws lambda update-function-configuration \
  --function-name my-function \
  --environment 'Variables={DB_URL=postgres://...,API_KEY=abc}'

# Delete function
aws lambda delete-function --function-name my-function

Lambda handler (Node.js)

// index.js
export const handler = async (event, context) => {
  console.log('Event:', JSON.stringify(event));

  return {
    statusCode: 200,
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ message: 'Hello from Lambda!' }),
  };
};

Lambda handler (Python)

import json

def handler(event, context):
    print(f"Event: {json.dumps(event)}")
    return {
        "statusCode": 200,
        "headers": {"Content-Type": "application/json"},
        "body": json.dumps({"message": "Hello from Lambda!"}),
    }

RDS (Relational Database Service)

Managed databases — PostgreSQL, MySQL, MariaDB, Oracle, SQL Server.

# List DB instances
aws rds describe-db-instances \
  --query 'DBInstances[*].[DBInstanceIdentifier,DBInstanceStatus,Endpoint.Address]' \
  --output table

# Create PostgreSQL instance
aws rds create-db-instance \
  --db-instance-identifier my-postgres \
  --db-instance-class db.t3.micro \
  --engine postgres \
  --engine-version 16.1 \
  --master-username admin \
  --master-user-password MySecurePass123! \
  --allocated-storage 20 \
  --no-publicly-accessible \
  --db-subnet-group-name my-subnet-group

# Create DB snapshot
aws rds create-db-snapshot \
  --db-instance-identifier my-postgres \
  --db-snapshot-identifier my-postgres-snapshot-2024

# Start / stop instance (save costs in dev)
aws rds start-db-instance --db-instance-identifier my-postgres
aws rds stop-db-instance --db-instance-identifier my-postgres

# Delete instance (no final snapshot for dev)
aws rds delete-db-instance \
  --db-instance-identifier my-postgres \
  --skip-final-snapshot

CloudFormation

Infrastructure as Code — define all your AWS resources in YAML or JSON.

# Validate template
aws cloudformation validate-template \
  --template-body file://template.yaml

# Create stack
aws cloudformation create-stack \
  --stack-name my-stack \
  --template-body file://template.yaml \
  --parameters ParameterKey=Env,ParameterValue=production \
  --capabilities CAPABILITY_IAM

# Update stack
aws cloudformation update-stack \
  --stack-name my-stack \
  --template-body file://template.yaml \
  --capabilities CAPABILITY_IAM

# Deploy (create or update, recommended)
aws cloudformation deploy \
  --stack-name my-stack \
  --template-file template.yaml \
  --parameter-overrides Env=production \
  --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM

# Watch stack events
aws cloudformation describe-stack-events \
  --stack-name my-stack \
  --query 'StackEvents[*].[Timestamp,ResourceStatus,ResourceType,LogicalResourceId]' \
  --output table

# List stacks
aws cloudformation list-stacks \
  --stack-status-filter CREATE_COMPLETE UPDATE_COMPLETE

# Delete stack
aws cloudformation delete-stack --stack-name my-stack

Minimal CloudFormation template (S3 + Lambda)

AWSTemplateFormatVersion: "2010-09-09"
Description: S3 bucket + Lambda function

Parameters:
  Env:
    Type: String
    Default: dev
    AllowedValues: [dev, staging, production]

Resources:
  AssetsBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub "my-assets-${Env}-${AWS::AccountId}"
      VersioningConfiguration:
        Status: Enabled

  LambdaRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

  MyFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub "my-function-${Env}"
      Runtime: nodejs20.x
      Handler: index.handler
      Role: !GetAtt LambdaRole.Arn
      Code:
        ZipFile: |
          exports.handler = async (event) => ({
            statusCode: 200,
            body: JSON.stringify({ env: process.env.ENV }),
          });
      Environment:
        Variables:
          ENV: !Ref Env

Outputs:
  BucketName:
    Value: !Ref AssetsBucket
  FunctionArn:
    Value: !GetAtt MyFunction.Arn

SSM Parameter Store

Secure storage for configuration values and secrets.

# Store a plain text parameter
aws ssm put-parameter \
  --name "/app/db-host" \
  --value "mydb.cluster.eu-west-1.rds.amazonaws.com" \
  --type String

# Store a secret (encrypted with KMS)
aws ssm put-parameter \
  --name "/app/db-password" \
  --value "MySecurePass123!" \
  --type SecureString

# Get a parameter
aws ssm get-parameter --name "/app/db-host" --query 'Parameter.Value' --output text

# Get a secret (decrypt it)
aws ssm get-parameter --name "/app/db-password" --with-decryption --query 'Parameter.Value' --output text

# Get all parameters by path
aws ssm get-parameters-by-path \
  --path "/app/" \
  --recursive \
  --with-decryption \
  --query 'Parameters[*].[Name,Value]' \
  --output table

# Delete parameter
aws ssm delete-parameter --name "/app/db-host"

Read SSM in Node.js

import { SSMClient, GetParameterCommand } from "@aws-sdk/client-ssm";

const ssm = new SSMClient({ region: "eu-west-1" });

async function getSecret(name) {
  const result = await ssm.send(
    new GetParameterCommand({ Name: name, WithDecryption: true })
  );
  return result.Parameter.Value;
}

const dbPassword = await getSecret("/app/db-password");

CloudWatch

Monitoring, logs, and alarms.

# List log groups
aws logs describe-log-groups --query 'logGroups[*].logGroupName' --output table

# Stream logs in real time
aws logs tail /aws/lambda/my-function --follow
aws logs tail /ecs/my-service --follow --since 1h

# Get log events
aws logs get-log-events \
  --log-group-name /aws/lambda/my-function \
  --log-stream-name "2024/01/15/[$LATEST]abc123" \
  --start-time $(date -d '1 hour ago' +%s000)

# Create metric alarm (CPU > 80% for 5 min)
aws cloudwatch put-metric-alarm \
  --alarm-name high-cpu \
  --metric-name CPUUtilization \
  --namespace AWS/EC2 \
  --period 300 \
  --evaluation-periods 1 \
  --threshold 80 \
  --comparison-operator GreaterThanThreshold \
  --statistic Average \
  --dimensions Name=InstanceId,Value=i-0abc123 \
  --alarm-actions arn:aws:sns:eu-west-1:123:alerts

ECS (Elastic Container Service)

Run Docker containers at scale.

# List clusters
aws ecs list-clusters

# List services
aws ecs list-services --cluster my-cluster

# Describe service
aws ecs describe-services \
  --cluster my-cluster \
  --services my-service \
  --query 'services[0].[serviceName,status,runningCount,desiredCount]'

# Force new deployment (rolling update)
aws ecs update-service \
  --cluster my-cluster \
  --service my-service \
  --force-new-deployment

# Scale service
aws ecs update-service \
  --cluster my-cluster \
  --service my-service \
  --desired-count 3

# Run one-off task
aws ecs run-task \
  --cluster my-cluster \
  --task-definition my-task:5 \
  --launch-type FARGATE \
  --network-configuration 'awsvpcConfiguration={subnets=[subnet-xxx],securityGroups=[sg-xxx],assignPublicIp=ENABLED}'

VPC (Virtual Private Cloud)

Your isolated network in AWS.

# List VPCs
aws ec2 describe-vpcs --query 'Vpcs[*].[VpcId,CidrBlock,Tags[?Key==`Name`].Value|[0]]' --output table

# List subnets
aws ec2 describe-subnets \
  --query 'Subnets[*].[SubnetId,CidrBlock,AvailabilityZone,MapPublicIpOnLaunch]' \
  --output table

# Create VPC
aws ec2 create-vpc --cidr-block 10.0.0.0/16

# Create subnet
aws ec2 create-subnet \
  --vpc-id vpc-0abc123 \
  --cidr-block 10.0.1.0/24 \
  --availability-zone eu-west-1a

# Create internet gateway and attach
aws ec2 create-internet-gateway
aws ec2 attach-internet-gateway \
  --internet-gateway-id igw-0abc123 \
  --vpc-id vpc-0abc123

AWS service comparison table

Service Category Use case
EC2 Compute VMs — full OS control
ECS / Fargate Compute Docker containers
Lambda Compute Serverless functions, event-driven
Elastic Beanstalk Compute PaaS — deploy web apps without IaC
S3 Storage Object storage — files, backups, static sites
EBS Storage Block storage attached to EC2
EFS Storage Shared NFS for multiple EC2
RDS Database Managed relational DB (Postgres, MySQL…)
Aurora Database AWS-optimised Postgres/MySQL — 5× faster
DynamoDB Database Serverless NoSQL — key-value/document
ElastiCache Database Managed Redis / Memcached cache
CloudFront Networking CDN — edge caching for S3 / API
Route 53 Networking DNS + health checks
ALB / NLB Networking Load balancers
API Gateway Networking HTTP/WebSocket API front door
VPC Networking Isolated private network
IAM Security Identity, roles, permissions
KMS Security Encryption key management
Secrets Manager Security Rotate & store secrets
SSM Security Parameter store, run commands on EC2
CloudFormation IaC Deploy all AWS resources via YAML
CDK IaC CloudFormation via TypeScript/Python
CloudWatch Observability Logs, metrics, alarms, dashboards
X-Ray Observability Distributed tracing
SQS Messaging Queue — decoupled async messaging
SNS Messaging Pub/sub — fan-out notifications
EventBridge Messaging Event bus — route events between services
SES Email Send transactional email at scale
Cognito Auth Managed user pools / social login
CodePipeline CI/CD Automate build → test → deploy

Common architecture patterns

Static website with CDN

Route 53 → CloudFront → S3 (static files)
                      → API Gateway → Lambda → DynamoDB
# Deploy Next.js static export to S3 + CloudFront
next build && next export
aws s3 sync ./out s3://my-site-bucket --delete
aws cloudfront create-invalidation \
  --distribution-id E1XXXXX \
  --paths "/*"

Three-tier web application

Internet → ALB → EC2 Auto Scaling Group (App)
                                         ↓
                              RDS (Multi-AZ) in private subnets
                                         ↓
                              ElastiCache (Redis) for sessions

Serverless API

Client → API Gateway → Lambda → DynamoDB
                     → Lambda → RDS Proxy → Aurora Serverless

Event-driven microservices

Service A → SQS → Lambda → DynamoDB
          → SNS → SQS (B)
                → SQS (C)
                → Email (SES)

AWS regions and availability zones

# List all regions
aws ec2 describe-regions --query 'Regions[*].RegionName' --output table

# List AZs in current region
aws ec2 describe-availability-zones \
  --query 'AvailabilityZones[*].[ZoneName,State]' \
  --output table

Most popular regions:

Region code Location
us-east-1 N. Virginia (cheapest, most services)
us-west-2 Oregon
eu-west-1 Ireland
eu-central-1 Frankfurt
ap-southeast-1 Singapore
ap-northeast-1 Tokyo

Cost-saving tips

Tip Savings
Use Spot Instances for batch workloads Up to 90% vs On-Demand
Stop dev EC2/RDS instances overnight ~65% (8h off / 24h)
Use S3 Intelligent-Tiering for infrequent files 40–68% on storage
Use Lambda instead of always-on EC2 for low traffic Pay per invocation
Set S3 lifecycle rules — move old data to Glacier 80% cheaper storage
Use Reserved Instances for steady 24/7 workloads Up to 72% discount
Enable AWS Budgets alerts Avoid surprise bills
# Set up billing alarm ($50 threshold)
aws cloudwatch put-metric-alarm \
  --alarm-name billing-alarm-50 \
  --metric-name EstimatedCharges \
  --namespace AWS/Billing \
  --period 86400 \
  --evaluation-periods 1 \
  --threshold 50 \
  --comparison-operator GreaterThanThreshold \
  --statistic Maximum \
  --alarm-actions arn:aws:sns:us-east-1:123:billing-alerts \
  --dimensions Name=Currency,Value=USD \
  --region us-east-1

Common mistakes

Mistake Fix
Storing secrets in env vars or code Use SSM Parameter Store or Secrets Manager
Using root account for daily work Create IAM users with least-privilege roles
Public S3 bucket for sensitive data Block Public Access + use presigned URLs
Single AZ deployment Use Multi-AZ RDS + Auto Scaling across 2+ AZs
No CloudWatch alarms Set CPU, error rate, and billing alarms
Hardcoded region in code Use AWS_DEFAULT_REGION env var or SDK defaults
Forgetting to set --region Add AWS_DEFAULT_REGION to your shell profile
aws s3 rm without testing List first: aws s3 ls s3://bucket/prefix/

FAQ

Q: What's the difference between IAM roles and IAM users?
Users are for humans (long-lived credentials). Roles are for services and applications (temporary credentials via STS). An EC2 instance, Lambda function, or ECS task assumes a role — never embed user credentials in code. Always prefer roles over users for programmatic access.

Q: How do I avoid AWS billing surprises?
Enable billing alerts in CloudWatch (see example above), set an AWS Budget in the console, use the Cost Explorer, and tag all resources with a project/environment tag. Also: always terminate test resources — stop is not enough, a stopped EC2 still charges for the EBS volume.

Q: EC2 vs Lambda vs Fargate — when to use which?
Use Lambda for event-driven, short-lived tasks (API routes, processing triggers) — pay per millisecond, zero idle cost. Use Fargate for long-running containers where you need persistent processes, WebSockets, or tasks over 15 minutes. Use EC2 when you need full OS control, custom GPU instances, or steady heavy traffic where Reserved Instances save money.

Q: What's the difference between SQS and SNS?
SQS is a queue — one consumer reads and deletes each message (point-to-point). SNS is pub/sub — one message fans out to multiple subscribers (email, SQS, Lambda, HTTP). For fan-out to multiple services, publish to SNS and subscribe multiple SQS queues to it.

Q: How do I run commands on EC2 without SSH?
Use AWS Systems Manager Session Manager — no inbound ports needed, no SSH key required:

aws ssm start-session --target i-0abc123

Or use EC2 Instance Connect for browser-based terminal access from the console.

Q: What's the fastest way to look up an AWS CLI command?
Use aws <service> help (e.g., aws s3 help, aws lambda help) or add --help to any command. The AWS CLI Command Reference has every command, and the --query flag with JMESPath is essential for filtering JSON output.

Related tools

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools