AWS โ Amazon Web Services
Last reviewed: 2026-06-16
Purpose: Comprehensive Knowledge Base reference for core AWS services โ CLI setup, EC2, S3, IAM, VPC, and cost management. Includes practical CLI commands and a full end-to-end example.
Table of Contents
- AWS CLI โ Install & Configure
- EC2 โ Elastic Compute Cloud
- S3 โ Simple Storage Service
- IAM โ Identity & Access Management
- VPC โ Virtual Private Cloud Basics
- Cost Management
- Complete Example โ Launch EC2 with S3 Backend
- Troubleshooting & Tips
1. AWS CLI โ Install & Configure
Installation
Linux (Debian/Ubuntu):
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
rm -rf aws awscliv2.zip
macOS:
curl "https://awscli.amazonaws.com/AWSCLIV2.pkg" -o "AWSCLIV2.pkg"
sudo installer -pkg AWSCLIV2.pkg -target /
Verify:
Configuration
Interactive:
aws configure
# AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE
# AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
# Default region name [None]: us-east-1
# Default output format [None]: json
Non-interactive (scripts/CI):
aws configure set aws_access_key_id AKIAIOSFODNN7EXAMPLE
aws configure set aws_secret_access_key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
aws configure set region us-east-1
aws configure set output json
Multiple profiles:
Configuration files live in ~/.aws/:
- ~/.aws/config โ region, output format, profile settings
- ~/.aws/credentials โ access keys (keep secure; chmod 600)
IMDSv2 (EC2 instance roles): When running on an EC2 instance with an IAM role, the CLI automatically obtains temporary credentials from the instance metadata service. No manual keys needed.
Useful CLI Flags
| Flag | Purpose |
|---|---|
--profile |
Use a named profile |
--region |
Override the default region |
--output |
json, text, table, or yaml |
--no-sign-request |
Access public S3 buckets without credentials |
--dry-run |
Check permissions without executing (EC2, S3) |
--cli-auto-prompt |
Interactive prompt mode (v2) |
2. EC2 โ Elastic Compute Cloud
Instance Types โ Naming Convention
m5.large
โ โ โโโ Size (small, medium, large, xlarge, 2xlarge, โฆ)
โ โโโ Generation number
โโโ Instance family
| Family | Use Case | Example Types |
|---|---|---|
| t (burstable) | General-purpose, dev/test, low-CPU | t3.micro (free tier), t3.medium |
| m (general) | Balanced compute/memory/networking | m5.large, m6i.xlarge |
| c (compute) | Compute-optimized, batch, gaming | c5.2xlarge, c6g.large |
| r (memory) | Memory-optimized, databases, caching | r5.large, r6g.xlarge |
| i (storage) | I/O-intensive, high-throughput storage | i3.large |
| g (GPU) | ML, rendering, CUDA workloads | g4dn.xlarge |
Free tier eligible: t2.micro or t3.micro (750 hours/month for 12 months).
Launching an EC2 Instance
# Create a key pair (if you don't have one)
aws ec2 create-key-pair --key-name my-key --query 'KeyMaterial' --output text > my-key.pem
chmod 400 my-key.pem
# Create a security group
aws ec2 create-security-group \
--group-name web-sg \
--description "Web server security group"
# Authorize inbound SSH (port 22) and HTTP (port 80)
aws ec2 authorize-security-group-ingress \
--group-name web-sg \
--protocol tcp --port 22 --cidr 0.0.0.0/0
aws ec2 authorize-security-group-ingress \
--group-name web-sg \
--protocol tcp --port 80 --cidr 0.0.0.0/0
# Launch an instance
aws ec2 run-instances \
--image-id ami-0c7217cdde317cfec \
--instance-type t3.micro \
--key-name my-key \
--security-groups web-sg \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=MyWebServer}]'
AMIs โ Amazon Machine Images
Find the latest Amazon Linux 2023 AMI:
aws ec2 describe-images \
--owners amazon \
--filters 'Name=name,Values=al2023-ami-*-kernel-6.1-x86_64' \
--query 'reverse(sort_by(Images, &CreationDate))[:1].ImageId' \
--output text
Common AMI IDs per region (Amazon Linux 2023, x86_64, HVM, EBS SSD):
| Region | AMI ID |
|--------|--------|
| us-east-1 | ami-0c7217cdde317cfec |
| us-west-2 | ami-0f0c7f5e6f7a8b9c0 |
| eu-west-1 | ami-0a1b2c3d4e5f6a7b8 |
AMI IDs differ by region and are updated frequently. Always query
describe-imagesrather than hardcoding.
SSH Access
# Standard SSH
ssh -i my-key.pem ec2-user@<public-ip-or-dns>
# Using SSH config (~/.ssh/config)
Host my-server
HostName ec2-1-2-3-4.compute-1.amazonaws.com
User ec2-user
IdentityFile ~/.ssh/my-key.pem
# Then simply:
ssh my-server
Default usernames by AMI:
| AMI | Username |
|-----|----------|
| Amazon Linux 2023/2 | ec2-user |
| Ubuntu | ubuntu |
| RHEL | ec2-user or root |
| Debian | admin |
| CentOS | centos |
Security Groups โ Rules & Best Practices
# List all security groups
aws ec2 describe-security-groups
# Add HTTPS inbound (port 443) from a specific CIDR
aws ec2 authorize-security-group-ingress \
--group-id sg-12345678 \
--protocol tcp --port 443 \
--cidr 10.0.0.0/16
# Remove a rule
aws ec2 revoke-security-group-ingress \
--group-id sg-12345678 \
--protocol tcp --port 22 \
--cidr 0.0.0.0/0
# Reference another security group (instead of CIDR)
aws ec2 authorize-security-group-ingress \
--group-id sg-12345678 \
--protocol tcp --port 3306 \
--source-group sg-87654321
Rules of thumb:
- Least privilege โ only open ports you need
- Use security group references instead of CIDR where possible (e.g., app โ db)
- Never open SSH (port 22) to 0.0.0.0/0 in production โ use a bastion host or VPN
- Stateful โ return traffic is automatically allowed
- Separate security groups per tier (web, app, db)
Managing Instances
# List instances with details
aws ec2 describe-instances --query 'Reservations[*].Instances[*].[InstanceId,State.Name,InstanceType,PublicIpAddress,Tags[?Key==`Name`].Value | [0]]' --output table
# Stop
aws ec2 stop-instances --instance-ids i-1234567890abcdef0
# Start
aws ec2 start-instances --instance-ids i-1234567890abcdef0
# Terminate (destructive โ data on instance store is lost)
aws ec2 terminate-instances --instance-ids i-1234567890abcdef0
# Tag an instance
aws ec2 create-tags --resources i-1234567890abcdef0 --tags Key=Environment,Value=Production
3. S3 โ Simple Storage Service
Bucket Operations
# Create a bucket (bucket names are globally unique)
aws s3 mb s3://my-unique-bucket-name --region us-east-1
# List all buckets
aws s3 ls
# List objects in a bucket
aws s3 ls s3://my-bucket/
# List with human-readable sizes and total count
aws s3 ls s3://my-bucket/ --summarize --human-readable
# Get bucket info
aws s3api get-bucket-location --bucket my-bucket
Upload, Download, and Sync
# Upload a single file
aws s3 cp index.html s3://my-bucket/www/
# Upload a directory (recursive)
aws s3 cp ./build/ s3://my-bucket/www/ --recursive
# Download a file
aws s3 cp s3://my-bucket/config.json ./
# Sync โ one-way, copies only newer/missing files
aws s3 sync ./local-dir/ s3://my-bucket/remote-dir/
# Sync from S3 to local
aws s3 sync s3://my-bucket/remote-dir/ ./local-dir/
# Sync with delete (removes files at destination that aren't at source)
aws s3 sync ./local-dir/ s3://my-bucket/remote-dir/ --delete
# Dry-run sync
aws s3 sync ./local-dir/ s3://my-bucket/remote-dir/ --dryrun
Presigned URLs
Generate time-limited URLs for private objects โ no IAM credentials needed by the consumer.
# Generate a presigned URL valid for 1 hour (default 3600 seconds)
aws s3 presign s3://my-bucket/private/report.pdf --expires-in 3600
# Using s3api for more control
aws s3api presign \
--bucket my-bucket \
--key private/report.pdf \
--expires-in 86400 # 24 hours
# Use with curl to download
curl -o report.pdf "$(aws s3 presign s3://my-bucket/private/report.pdf --expires-in 300)"
Use cases: Temporary access to reports, user file downloads, image sharing.
Lifecycle Policies
Automate object transitions and expirations.
CLI โ apply a lifecycle policy:
# Save policy to JSON
cat > lifecycle.json << 'EOF'
{
"Rules": [
{
"Id": "expire-logs",
"Status": "Enabled",
"Filter": {
"Prefix": "logs/"
},
"Transitions": [
{
"Days": 30,
"StorageClass": "STANDARD_IA"
},
{
"Days": 90,
"StorageClass": "GLACIER"
}
],
"Expiration": {
"Days": 365
}
},
{
"Id": "abort-incomplete-multipart",
"Status": "Enabled",
"Filter": {
"Prefix": ""
},
"AbortIncompleteMultipartUpload": {
"DaysAfterInitiation": 7
}
}
]
}
EOF
aws s3api put-bucket-lifecycle-configuration \
--bucket my-bucket \
--lifecycle-configuration file://lifecycle.json
Storage classes from warmest to coldest:
| Class | Durability | Min Duration | Retrieval |
|-------|-----------|-------------|-----------|
| STANDARD | 99.999999999% | None | Instant |
| STANDARD_IA | 99.999999999% | 30 days | Instant |
| ONEZONE_IA | 99.999999999% | 30 days | Instant |
| GLACIER_INSTANT | 99.999999999% | 90 days | Millisecond |
| GLACIER_FLEXIBLE | 99.999999999% | 90 days | Minutesโhours |
| DEEP_ARCHIVE | 99.999999999% | 180 days | Hours |
Bucket Policies (Access Control)
# Make a bucket publicly readable (caution!)
cat > public-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-public-bucket/*"
}
]
}
EOF
aws s3api put-bucket-policy \
--bucket my-public-bucket \
--policy file://public-policy.json
# Block public access (default best practice)
aws s3api put-public-access-block \
--bucket my-bucket \
--public-access-block-configuration 'BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true'
4. IAM โ Identity & Access Management
Users
# Create a user
aws iam create-user --user-name developer-1
# Create an access key pair
aws iam create-access-key --user-name developer-1
# Attach a managed policy directly
aws iam attach-user-policy \
--user-name developer-1 \
--policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
# List user's policies
aws iam list-attached-user-policies --user-name developer-1
Groups
# Create a group
aws iam create-group --group-name Developers
# Add user to group
aws iam add-user-to-group --user-name developer-1 --group-name Developers
# Attach policy to group (all members inherit)
aws iam attach-group-policy \
--group-name Developers \
--policy-arn arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess
Roles
Roles are assumed by AWS services (EC2, Lambda, etc.) or federated users.
# Create an IAM role for EC2 with a trust policy
cat > trust-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
aws iam create-role \
--role-name EC2-S3-Access-Role \
--assume-role-policy-document file://trust-policy.json
# Attach a permissions policy to the role
aws iam attach-role-policy \
--role-name EC2-S3-Access-Role \
--policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess
# Create an instance profile (needed for 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-Access-Role
# Launch EC2 with the role
aws ec2 run-instances \
--image-id ami-0c7217cdde317cfec \
--instance-type t3.micro \
--iam-instance-profile Name=EC2-S3-Profile
Custom Policies (JSON)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::my-app-bucket/uploads/*"
},
{
"Effect": "Deny",
"Action": "s3:DeleteBucket",
"Resource": "*"
}
]
}
# Create a customer managed policy
aws iam create-policy \
--policy-name AppUploadAccess \
--policy-document file://app-policy.json
# Attach to user or role
aws iam attach-user-policy \
--user-name developer-1 \
--policy-arn arn:aws:iam::123456789012:policy/AppUploadAccess
IAM Best Practices
| # | Practice | Why |
|---|---|---|
| 1 | No root user access keys | Use the root account only for billing and account recovery |
| 2 | Enable MFA | Required for root and strongly recommended for all users |
| 3 | Least privilege | Start with minimum permissions, grant more only when needed |
| 4 | Use roles for EC2 | Never store access keys on instances โ use instance profiles |
| 5 | Audit with IAM Access Analyzer | Identifies unused permissions and external access |
| 6 | Use groups, not individual policies | Attach policies to groups, add users to groups |
| 7 | Rotate keys regularly | Max 90 days; use IAM Access Advisor for unused keys |
| 8 | Use conditions in policies | Add aws:SourceIp, aws:RequestedRegion constraints |
5. VPC โ Virtual Private Cloud Basics
VPC Components
| Component | Purpose |
|---|---|
| VPC | Isolated virtual network (one per account per region) |
| Subnet | IP range within a VPC (public or private) |
| Internet Gateway (IGW) | Enables public internet access for public subnets |
| NAT Gateway | Allows private subnets to reach the internet (outbound only) |
| Route Table | Controls traffic routing between subnets and gateways |
| Security Group | Instance-level firewall (stateful) |
| Network ACL | Subnet-level firewall (stateless) |
| VPC Endpoint | Private connection to AWS services (no internet needed) |
Default vs. Custom VPC
When you create an AWS account, each region gets a default VPC with:
- A /16 CIDR block (usually 172.31.0.0/16)
- One public subnet per AZ
- An internet gateway and main route table
- Security group allowing all outbound traffic
Key CLI Commands
# List VPCs
aws ec2 describe-vpcs
# Create a VPC with a /16 CIDR
VPC_ID=$(aws ec2 create-vpc --cidr-block 10.0.0.0/16 --query 'Vpc.VpcId' --output text)
# Create a public subnet (/24)
aws ec2 create-subnet \
--vpc-id $VPC_ID \
--cidr-block 10.0.1.0/24 \
--map-public-ip-on-launch
# Create a private subnet (/24)
aws ec2 create-subnet \
--vpc-id $VPC_ID \
--cidr-block 10.0.2.0/24
# Create an internet gateway and attach it
IGW_ID=$(aws ec2 create-internet-gateway --query 'InternetGateway.InternetGatewayId' --output text)
aws ec2 attach-internet-gateway --vpc-id $VPC_ID --internet-gateway-id $IGW_ID
# Create a route table and add a default route via IGW
RT_ID=$(aws ec2 create-route-table --vpc-id $VPC_ID --query 'RouteTable.RouteTableId' --output text)
aws ec2 create-route --route-table-id $RT_ID --destination-cidr-block 0.0.0.0/0 --gateway-id $IGW_ID
# Associate the route table with the public subnet
aws ec2 associate-route-table --subnet-id subnet-xxxxx --route-table-id $RT_ID
Subnet Types
| Type | Route to IGW? | Public IP on Launch? | Use Case |
|---|---|---|---|
| Public | Yes (0.0.0.0/0 โ IGW) | Yes | Web servers, bastion hosts |
| Private | No direct IGW route | No | Databases, app servers |
| VPN-only | Routes via VPN/TGW | No | Internal services |
6. Cost Management
AWS Budgets
# Create a monthly cost budget
aws budgets create-budget \
--account-id 123456789012 \
--budget '{
"BudgetName": "Monthly-Dev-Budget",
"BudgetLimit": {"Amount": "500", "Unit": "USD"},
"TimePeriod": {"Start": "2026-01-01T00:00:00Z"},
"TimeUnit": "MONTHLY",
"BudgetType": "COST",
"CostFilters": {"TagKeyValue": ["Environment:dev$"]},
"CostTypes": {"IncludeTax": true, "IncludeSubscription": true}
}' \
--notifications-with-subscribers '[
{
"Notification": {
"NotificationType": "ACTUAL",
"ComparisonOperator": "GREATER_THAN",
"Threshold": 80.0
},
"Subscribers": [
{"SubscriptionType": "EMAIL", "Address": "team@example.com"}
]
}
]'
Cost Explorer (CLI)
# Get last month's costs by service
aws ce get-cost-and-usage \
--time-period Start=2026-05-01,End=2026-06-01 \
--granularity MONTHLY \
--metrics "BlendedCost" "UnblendedCost" \
--group-by Type=DIMENSION,Key=SERVICE
Cost-Saving Strategies
| Strategy | Savings | Effort |
|---|---|---|
| Reserved Instances / Savings Plans | 30โ72% | Low (commit 1โ3 yr) |
| Spot Instances | 60โ90% | Medium (fault-tolerant workloads) |
| S3 Lifecycle Policies | 50โ80% | Low (move cold data to Glacier) |
| Stop idle instances | 100% of compute cost | Medium (automate with Lambda) |
| Right-size instances | 20โ50% | Medium (use Compute Optimizer) |
| EBS gp3 instead of gp2 | 20%+ | Low (same cost as gp2, better perf) |
| Delete unused EBS snapshots | Varies | Low |
| S3 Intelligent-Tiering | 20โ40% | Low (auto-optimize access patterns) |
Cost Allocation Tags
# Activate cost allocation tags
aws ce update-cost-allocation-tags-status \
--tags-status 'TagKey=Environment,Status=Active'
Recommended tag schema: Environment (dev/staging/prod), Project, Team, CostCenter, AutoStop.
7. Complete Example โ Launch EC2 with S3 Backend
This example provisions a web server that stores uploaded files in S3.
Prerequisites
Step 1 โ Create an S3 Bucket
BUCKET="my-app-uploads-$(date +%s)"
aws s3 mb "s3://$BUCKET" --region us-east-1
echo "Bucket: $BUCKET"
Step 2 โ Create an IAM Role with S3 Access
cat > trust-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {"Service": "ec2.amazonaws.com"},
"Action": "sts:AssumeRole"
}
]
}
EOF
aws iam create-role \
--role-name WebServer-S3-Role \
--assume-role-policy-document file://trust-policy.json
cat > s3-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:PutObject", "s3:GetObject", "s3:ListBucket"],
"Resource": [
"arn:aws:s3:::my-app-uploads-*",
"arn:aws:s3:::my-app-uploads-*/*"
]
}
]
}
EOF
aws iam put-role-policy \
--role-name WebServer-S3-Role \
--policy-name S3-Upload-Access \
--policy-document file://s3-policy.json
aws iam create-instance-profile \
--instance-profile-name WebServer-S3-Profile
aws iam add-role-to-instance-profile \
--instance-profile-name WebServer-S3-Profile \
--role-name WebServer-S3-Role
Step 3 โ Set Up Networking (Security Group + Key Pair)
# Create a key pair
aws ec2 create-key-pair \
--key-name webserver-key \
--query 'KeyMaterial' --output text > webserver-key.pem
chmod 400 webserver-key.pem
# Security group
SG_ID=$(aws ec2 create-security-group \
--group-name webserver-sg \
--description "Web server SG (SSH + HTTP)" \
--query 'GroupId' --output text)
aws ec2 authorize-security-group-ingress \
--group-id "$SG_ID" \
--protocol tcp --port 22 --cidr $(curl -s ifconfig.me)/32
aws ec2 authorize-security-group-ingress \
--group-id "$SG_ID" \
--protocol tcp --port 80 --cidr 0.0.0.0/0
Step 4 โ Launch the EC2 Instance
# Get latest Amazon Linux 2023 AMI
AMI=$(aws ec2 describe-images \
--owners amazon \
--filters 'Name=name,Values=al2023-ami-*-kernel-6.1-x86_64' \
--query 'reverse(sort_by(Images, &CreationDate))[:1].ImageId' \
--output text)
INSTANCE_ID=$(aws ec2 run-instances \
--image-id "$AMI" \
--instance-type t3.micro \
--key-name webserver-key \
--security-group-ids "$SG_ID" \
--iam-instance-profile Name=WebServer-S3-Profile \
--user-data '#!/bin/bash
dnf update -y
dnf install -y httpd
systemctl enable --now httpd
echo "<h1>EC2 + S3 Demo</h1><p>Bucket: '"$BUCKET"'</p>" > /var/www/html/index.html
echo "<?php putenv(\"BUCKET=$BUCKET\"); ?>" > /var/www/html/env.php
' \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=WebServer-Demo}]' \
--query 'Instances[0].InstanceId' --output text)
echo "Instance ID: $INSTANCE_ID"
# Wait for running state and get public IP
aws ec2 wait instance-running --instance-ids "$INSTANCE_ID"
PUBLIC_IP=$(aws ec2 describe-instances \
--instance-ids "$INSTANCE_ID" \
--query 'Reservations[0].Instances[0].PublicIpAddress' \
--output text)
echo "Connect via: ssh -i webserver-key.pem ec2-user@$PUBLIC_IP"
echo "Visit: http://$PUBLIC_IP"
Step 5 โ Verify
# SSH to the server
ssh -i webserver-key.pem ec2-user@"$PUBLIC_IP"
# Test S3 access from the instance
aws s3 ls "s3://$BUCKET"
# Create a test file and upload
echo "Hello from EC2 $(date)" > test.txt
aws s3 cp test.txt "s3://$BUCKET/"
# Verify the file exists
aws s3 ls "s3://$BUCKET/"
# Generate a presigned URL for the file
aws s3 presign "s3://$BUCKET/test.txt" --expires-in 300
Step 6 โ Clean Up
# Clean up S3 (must empty bucket first)
aws s3 rm "s3://$BUCKET" --recursive
aws s3 rb "s3://$BUCKET"
# Terminate EC2
aws ec2 terminate-instances --instance-ids "$INSTANCE_ID"
aws ec2 wait instance-terminated --instance-ids "$INSTANCE_ID"
# Clean up IAM resources
aws iam remove-role-from-instance-profile \
--instance-profile-name WebServer-S3-Profile \
--role-name WebServer-S3-Role
aws iam delete-instance-profile --instance-profile-name WebServer-S3-Profile
aws iam delete-role-policy --role-name WebServer-S3-Role --policy-name S3-Upload-Access
aws iam delete-role --role-name WebServer-S3-Role
# Delete security group
aws ec2 delete-security-group --group-id "$SG_ID"
8. Troubleshooting & Tips
Common CLI Errors
| Error | Likely Cause | Fix |
|---|---|---|
An error occurred (AuthFailure) when calling ... |
Invalid/expired keys | Run aws configure or check env vars AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY |
Unable to locate credentials |
No credentials configured | Set AWS_PROFILE or configure ~/.aws/credentials |
The config profile (...) could not be found |
Profile doesn't exist | Check ~/.aws/config and ~/.aws/credentials |
RequestExpired |
Clock skew | Sync system clock: sudo ntpdate -s time.nist.gov |
AccessDenied when calling S3 |
Bucket policy or IAM policy blocking | Use IAM Policy Simulator in the AWS Console |
InvalidPermission.Duplicate |
Security group rule already exists | It's idempotent โ can be safely ignored |
Environment Variables (Overrides CLI config)
export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
export AWS_DEFAULT_REGION=us-west-2
export AWS_DEFAULT_OUTPUT=json
export AWS_PROFILE=production
Useful Debugging Flags
# Increase verbosity
aws s3 ls --debug
# Dry-run (test permissions without making changes)
aws ec2 run-instances --dry-run --image-id ami-xxx --instance-type t3.micro
# Simulate IAM policy
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::123456789012:user/developer-1 \
--action-names s3:PutObject ec2:RunInstances \
--resource-arns arn:aws:s3:::my-bucket/*
Quick Reference โ Most Common Commands
# Identity
aws sts get-caller-identity
# S3
aws s3 ls
aws s3 sync ./dir s3://bucket/dir --delete
aws s3 presign s3://bucket/key --expires-in 3600
# EC2
aws ec2 describe-instances
aws ec2 stop-instances --instance-ids i-xxx
aws ec2 start-instances --instance-ids i-xxx
# IAM
aws iam list-users
aws iam list-attached-user-policies --user-name xxx
# Cost
aws ce get-cost-and-usage --time-period Start=2026-05-01,End=2026-06-01 --granularity MONTHLY --metrics BlendedCost
This article is part of the DevOps & Infrastructure KB. For corrections or updates, submit a PR or open an issue.