Skip to content

AWS CLI

Every single AWS CLI command follows this pattern:

aws <service> <action> [--option value] [--option value]
  • <service> = iam, s3, ec2, rds, lambda, vpc (it’s actually ec2 for VPC too)
  • <action> = verb like list-, create-, delete-, describe-, attach-, put-, get-
  • options = - flags that qualify the action

The 4 action prefixes you’ll use 90% of the time:

  • list- / describe- → read/query stuff
  • create- / run- / put- / add- → make stuff
  • delete- / remove- / detach- → destroy/disconnect stuff
  • attach- / associate- → link stuff together

If you can guess the verb, you can guess the command. That’s the whole game.


Terminal window
# Install (on ubuntu/debian)
sudo apt install awscli
# or via pip (gets you latest v2)
pip install awscli --break-system-packages
# Configure credentials
aws configure
# prompts: Access Key ID, Secret Access Key, region (ap-south-1 for Mumbai), output format (json)
# Config is stored here:
cat ~/.aws/credentials
cat ~/.aws/config
# Multiple profiles (for multiple accounts)
aws configure --profile myprofile
aws s3 ls --profile myprofile
# Set default profile in shell
export AWS_PROFILE=myprofile
# Quick sanity check — who am I?
aws sts get-caller-identity

IAM has 4 core concepts. Know these cold:

  • User → a person or app with long-term credentials (access keys / password)
  • Group → a collection of users, you attach policies to the group
  • Role → an identity assumed temporarily (by EC2, Lambda, another AWS account, etc.) — no long-term credentials
  • Policy → a JSON document that says what’s allowed/denied. Attached to users, groups, or roles.

Policy attachment chain:

Policy → attached to → User / Group / Role

Terminal window
# List all users
aws iam list-users
# List users with cleaner output (query is JMESPath)
aws iam list-users --query 'Users[*].[UserName,UserId,CreateDate]' --output table
# Create a user
aws iam create-user --user-name john
# Get details of a specific user
aws iam get-user --user-name john
# Create login profile (console password) for a user
aws iam create-login-profile --user-name john --password 'SecurePass@123' --password-reset-required
# Update a user's console password
aws iam update-login-profile --user-name john --password 'NewPass@456'
# Create access keys (programmatic access) for a user
aws iam create-access-key --user-name john
# SAVE the output — SecretAccessKey shown only once
# List access keys for a user
aws iam list-access-keys --user-name john
# Deactivate an access key
aws iam update-access-key --user-name john --access-key-id AKIAIOSFODNN7EXAMPLE --status Inactive
# Delete an access key
aws iam delete-access-key --user-name john --access-key-id AKIAIOSFODNN7EXAMPLE
# Delete a user (must clean up dependencies first)
aws iam delete-user --user-name john
# List all users in the account with their ARNs
aws iam list-users --query 'Users[*].Arn' --output text

Terminal window
# List all groups
aws iam list-groups
# Create a group
aws iam create-group --group-name Developers
# Add a user to a group
aws iam add-user-to-group --group-name Developers --user-name john
# List users in a group
aws iam get-group --group-name Developers
# List groups a user belongs to
aws iam list-groups-for-user --user-name john
# Remove user from group
aws iam remove-user-from-group --group-name Developers --user-name john
# Delete group
aws iam delete-group --group-name Developers

Terminal window
# List AWS managed policies (there are 1000s — filter it)
aws iam list-policies --scope AWS --query 'Policies[?PolicyName==`AdministratorAccess`]'
# List only customer managed policies
aws iam list-policies --scope Local
# Find a specific AWS managed policy ARN (you need this to attach)
aws iam list-policies --scope AWS --query 'Policies[?PolicyName==`AmazonS3FullAccess`].Arn' --output text
# Get policy details
aws iam get-policy --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess
# Get the actual JSON of a policy (need version id first)
aws iam get-policy-version \\
--policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess \\
--version-id v1
# Create a custom policy from a JSON file
aws iam create-policy \\
--policy-name MyCustomPolicy \\
--policy-document file://policy.json
# Example policy.json:
cat > policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject"],
"Resource": "arn:aws:s3:::my-bucket/*"
}
]
}
EOF
# Delete a customer managed policy
aws iam delete-policy --policy-arn arn:aws:iam::<account-id>:policy/MyCustomPolicy

Attaching Policies — Users, Groups, Roles

Section titled “Attaching Policies — Users, Groups, Roles”
Terminal window
# Attach AWS managed policy directly to a user
aws iam attach-user-policy \\
--user-name john \\
--policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
# Attach policy to a group
aws iam attach-group-policy \\
--group-name Developers \\
--policy-arn arn:aws:iam::aws:policy/AmazonEC2FullAccess
# Attach policy to a role
aws iam attach-role-policy \\
--role-name MyLambdaRole \\
--policy-arn arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess
# List policies attached to a user
aws iam list-attached-user-policies --user-name john
# List policies attached to a group
aws iam list-attached-group-policies --group-name Developers
# List policies attached to a role
aws iam list-attached-role-policies --role-name MyLambdaRole
# Detach policy from user
aws iam detach-user-policy \\
--user-name john \\
--policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
# Inline policies (embedded directly, not reusable) — use sparingly
aws iam put-user-policy \\
--user-name john \\
--policy-name InlineS3Policy \\
--policy-document file://policy.json
# List inline policies on a user
aws iam list-user-policies --user-name john
# Get an inline policy
aws iam get-user-policy --user-name john --policy-name InlineS3Policy
# Delete inline policy
aws iam delete-user-policy --user-name john --policy-name InlineS3Policy

Roles are what EC2, Lambda, ECS tasks etc. use to get AWS permissions without hardcoding keys.

Terminal window
# List all roles
aws iam list-roles
# List roles with just names
aws iam list-roles --query Roles[*].RoleName --output text
# Create a role — needs a trust policy (who can assume this role)
# Trust policy for EC2:
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 MyEC2Role \\
--assume-role-policy-document file://trust-policy.json
# Trust policy for Lambda:
# change "Service": "lambda.amazonaws.com"
# Trust policy for another AWS account to assume this role:
# "Principal": { "AWS": "arn:aws:iam::<other-account-id>:root" }
# Get role details (including trust policy)
aws iam get-role --role-name MyEC2Role
# Attach policy to role
aws iam attach-role-policy \\
--role-name MyEC2Role \\
--policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
# Create instance profile (needed to attach a role to EC2)
aws iam create-instance-profile --instance-profile-name MyEC2Profile
# Add role to instance profile
aws iam add-role-to-instance-profile \\
--instance-profile-name MyEC2Profile \\
--role-name MyEC2Role
# List instance profiles
aws iam list-instance-profiles
# Delete role (detach all policies first)
aws iam detach-role-policy \\
--role-name MyEC2Role \\
--policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
aws iam delete-role --role-name MyEC2Role

Terminal window
# Simulate whether a user/role CAN do something
aws iam simulate-principal-policy \\
--policy-source-arn arn:aws:iam::<account-id>:user/john \\
--action-names s3:GetObject \\
--resource-arns arn:aws:s3:::my-bucket/file.txt
# Get credential report (CSV of all users + their MFA/key status)
aws iam generate-credential-report
aws iam get-credential-report --query 'Content' --output text | base64 -d
# List all policies attached to a user (managed + inline + via groups)
# There's no single command for this — combine:
aws iam list-attached-user-policies --user-name john # managed policies direct
aws iam list-user-policies --user-name john # inline policies
aws iam list-groups-for-user --user-name john # groups (then check group policies)
# Get the full access report for a role/user
aws iam generate-service-last-accessed-details \\
--arn arn:aws:iam::<account-id>:user/john
# Then fetch it (takes a second, use the JobId from above)
aws iam get-service-last-accessed-details --job-id <job-id>

Terminal window
# List MFA devices for a user
aws iam list-mfa-devices --user-name john
# List virtual MFA devices in the account
aws iam list-virtual-mfa-devices
# Create a virtual MFA device
aws iam create-virtual-mfa-device \\
--virtual-mfa-device-name john-mfa \\
--outfile /tmp/john-mfa-qr.png \\
--bootstrap-method QRCodePNG
# Scan the QR code with Google Authenticator / Authy
# Enable/associate MFA for a user (need 2 consecutive OTP codes)
aws iam enable-mfa-device \\
--user-name john \\
--serial-number arn:aws:iam::<account-id>:mfa/john-mfa \\
--authentication-code1 123456 \\
--authentication-code2 789012
# Deactivate MFA for a user
aws iam deactivate-mfa-device \\
--user-name john \\
--serial-number arn:aws:iam::<account-id>:mfa/john-mfa
# Delete the virtual MFA device itself
aws iam delete-virtual-mfa-device \\
--serial-number arn:aws:iam::<account-id>:mfa/john-mfa
# Enforce MFA via policy — attach this policy to force MFA usage
# Classic "DenyWithoutMFA" pattern:
cat > enforce-mfa.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"NotAction": ["iam:CreateVirtualMFADevice","iam:EnableMFADevice",
"iam:GetUser","iam:ListMFADevices","iam:ListVirtualMFADevices",
"iam:ResyncMFADevice","sts:GetSessionToken"],
"Resource": "*",
"Condition": {
"BoolIfExists": { "aws:MultiFactorAuthPresent": "false" }
}
}
]
}
EOF

Terminal window
# Get account password policy
aws iam get-account-password-policy
# Set password policy
aws iam update-account-password-policy \\
--minimum-password-length 12 \\
--require-symbols \\
--require-numbers \\
--require-uppercase-characters \\
--require-lowercase-characters \\
--allow-users-to-change-password \\
--max-password-age 90 \\
--password-reuse-prevention 5

S3 has two CLI interfaces:

  • aws s3 → high-level, human-friendly (cp, ls, sync, mv)
  • aws s3api → low-level, full control (bucket policies, ACLs, versioning, etc.)

Use s3 for day-to-day file ops, s3api for configuration.

Terminal window
# List all buckets
aws s3 ls
# List contents of a bucket
aws s3 ls s3://my-bucket
aws s3 ls s3://my-bucket/some/prefix/ --recursive
# Create a bucket
aws s3 mb s3://my-unique-bucket-name
# In specific region:
aws s3 mb s3://my-unique-bucket-name --region ap-south-1
# Delete empty bucket
aws s3 rb s3://my-bucket
# Delete bucket and all contents (nuclear option)
aws s3 rb s3://my-bucket --force
# Upload file
aws s3 cp localfile.txt s3://my-bucket/
aws s3 cp localfile.txt s3://my-bucket/folder/renamed.txt
# Download file
aws s3 cp s3://my-bucket/file.txt ./
# Upload entire directory
aws s3 cp ./mydir s3://my-bucket/mydir/ --recursive
# Sync local dir to S3 (only uploads changed/new files)
aws s3 sync ./mydir s3://my-bucket/mydir/
# Sync S3 to local
aws s3 sync s3://my-bucket/mydir/ ./mydir
# Sync and delete files in destination that don't exist in source
aws s3 sync ./mydir s3://my-bucket/mydir/ --delete
# Move (copy + delete)
aws s3 mv s3://my-bucket/old.txt s3://my-bucket/new.txt
# Delete a file
aws s3 rm s3://my-bucket/file.txt
# Delete all files with a prefix
aws s3 rm s3://my-bucket/logs/ --recursive
# Presigned URL (temporary access link, default 1 hour)
aws s3 presign s3://my-bucket/private-file.pdf
# Custom expiry (in seconds)
aws s3 presign s3://my-bucket/private-file.pdf --expires-in 3600
Terminal window
# Create bucket (s3api way — needed for LocationConstraint outside us-east-1)
aws s3api create-bucket \\
--bucket my-bucket \\
--region ap-south-1 \\
--create-bucket-configuration LocationConstraint=ap-south-1
# Enable versioning
aws s3api put-bucket-versioning \\
--bucket my-bucket \\
--versioning-configuration Status=Enabled
# Check versioning status
aws s3api get-bucket-versioning --bucket my-bucket
# Block all public access (do this for private buckets)
aws s3api put-public-access-block \\
--bucket my-bucket \\
--public-access-block-configuration \\
BlockPublicAcls=true,IgnorePublicAcls=true,\\
BlockPublicPolicy=true,RestrictPublicBuckets=true
# Get bucket policy
aws s3api get-bucket-policy --bucket my-bucket
# Set bucket policy
aws s3api put-bucket-policy \\
--bucket my-bucket \\
--policy file://bucket-policy.json
# Enable server-side encryption (SSE-S3)
aws s3api put-bucket-encryption \\
--bucket my-bucket \\
--server-side-encryption-configuration '{
"Rules": [{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "AES256"
}
}]
}'
# List object versions
aws s3api list-object-versions --bucket my-bucket
# Get object metadata
aws s3api head-object --bucket my-bucket --key file.txt
# Enable static website hosting
aws s3api put-bucket-website \\
--bucket my-bucket \\
--website-configuration '{
"IndexDocument": {"Suffix": "index.html"},
"ErrorDocument": {"Key": "error.html"}
}'

EC2’s main entities: AMI (the image), Instance (running VM), Security Group (firewall), Key Pair (SSH), EBS (disk).

Terminal window
# Describe all instances (verbose)
aws ec2 describe-instances
# Clean list of running instances
aws ec2 describe-instances \\
--query 'Reservations[*].Instances[*].[InstanceId,State.Name,InstanceType,PublicIpAddress,Tags[?Key==`Name`].Value|[0]]' \\
--output table
# Describe instances with a filter
aws ec2 describe-instances \\
--filters "Name=instance-state-name,Values=running"
# Launch an instance (bare minimum)
aws ec2 run-instances \\
--image-id ami-0f58b397bc5c1f2e8 \\ # Amazon Linux 2 AMI (region-specific)
--instance-type t2.micro \\
--count 1
# Launch with key pair + security group + subnet
aws ec2 run-instances \\
--image-id ami-0f58b397bc5c1f2e8 \\
--instance-type t2.micro \\
--key-name my-key-pair \\
--security-group-ids sg-0123456789abcdef0 \\
--subnet-id subnet-0123456789abcdef0 \\
--count 1 \\
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=MyServer}]'
# Launch with user-data script (runs on first boot)
aws ec2 run-instances \\
--image-id ami-0f58b397bc5c1f2e8 \\
--instance-type t2.micro \\
--user-data file://userdata.sh \\
--key-name my-key-pair
# Attach IAM role to instance at launch
aws ec2 run-instances \\
--image-id ami-0f58b397bc5c1f2e8 \\
--instance-type t2.micro \\
--iam-instance-profile Name=MyEC2Profile
# Stop / Start / Reboot / Terminate
aws ec2 stop-instances --instance-ids i-1234567890abcdef0
aws ec2 start-instances --instance-ids i-1234567890abcdef0
aws ec2 reboot-instances --instance-ids i-1234567890abcdef0
aws ec2 terminate-instances --instance-ids i-1234567890abcdef0
# Get public IP of an instance
aws ec2 describe-instances \\
--instance-ids i-1234567890abcdef0 \\
--query 'Reservations[0].Instances[0].PublicIpAddress' \\
--output text
# Describe available AMIs (filter by owner to avoid noise)
aws ec2 describe-images \\
--owners amazon \\
--filters "Name=name,Values=amzn2-ami-hvm-*" \\
--query 'Images[*].[ImageId,Name,CreationDate]' \\
--output table
Terminal window
# List key pairs
aws ec2 describe-key-pairs
# Create a key pair and save private key
aws ec2 create-key-pair \\
--key-name my-key-pair \\
--query 'KeyMaterial' \\
--output text > my-key-pair.pem
chmod 400 my-key-pair.pem
# Import existing public key
aws ec2 import-key-pair \\
--key-name my-key-pair \\
--public-key-material fileb://~/.ssh/id_rsa.pub
# Delete key pair
aws ec2 delete-key-pair --key-name my-key-pair
Terminal window
# List security groups
aws ec2 describe-security-groups
aws ec2 describe-security-groups \\
--query 'SecurityGroups[*].[GroupId,GroupName,Description]' \\
--output table
# Create security group (needs VPC ID)
aws ec2 create-security-group \\
--group-name my-sg \\
--description "My security group" \\
--vpc-id vpc-0123456789abcdef0
# Add inbound rule — SSH from anywhere (don't do this in prod lol)
aws ec2 authorize-security-group-ingress \\
--group-id sg-0123456789abcdef0 \\
--protocol tcp \\
--port 22 \\
--cidr 0.0.0.0/0
# Add inbound rule — HTTP
aws ec2 authorize-security-group-ingress \\
--group-id sg-0123456789abcdef0 \\
--protocol tcp \\
--port 80 \\
--cidr 0.0.0.0/0
# Add inbound rule from another security group (not CIDR)
aws ec2 authorize-security-group-ingress \\
--group-id sg-0123456789abcdef0 \\
--protocol tcp \\
--port 5432 \\
--source-group sg-anothergroup
# Remove inbound rule
aws ec2 revoke-security-group-ingress \\
--group-id sg-0123456789abcdef0 \\
--protocol tcp \\
--port 22 \\
--cidr 0.0.0.0/0
# Delete security group
aws ec2 delete-security-group --group-id sg-0123456789abcdef0
Terminal window
# List volumes
aws ec2 describe-volumes
# Create a volume
aws ec2 create-volume \\
--size 20 \\
--volume-type gp3 \\
--availability-zone ap-south-1a
# Attach volume to instance
aws ec2 attach-volume \\
--volume-id vol-0123456789abcdef0 \\
--instance-id i-1234567890abcdef0 \\
--device /dev/sdf
# Detach volume
aws ec2 detach-volume --volume-id vol-0123456789abcdef0
# Create snapshot
aws ec2 create-snapshot \\
--volume-id vol-0123456789abcdef0 \\
--description "My snapshot"
# List snapshots
aws ec2 describe-snapshots --owner-ids self

VPC → Subnets (public/private) → Route Tables → Internet Gateway (for public) / NAT Gateway (for private outbound) → Security Groups + NACLs.

Terminal window
# List VPCs
aws ec2 describe-vpcs
aws ec2 describe-vpcs \\
--query 'Vpcs[*].[VpcId,CidrBlock,Tags[?Key==`Name`].Value|[0]]' \\
--output table
# Create VPC
aws ec2 create-vpc --cidr-block 10.0.0.0/16
# Tag it right away
aws ec2 create-tags \\
--resources vpc-0123456789abcdef0 \\
--tags Key=Name,Value=MyVPC
# Enable DNS hostnames (needed for many services)
aws ec2 modify-vpc-attribute \\
--vpc-id vpc-0123456789abcdef0 \\
--enable-dns-hostnames '{"Value": true}'
# Delete VPC (must remove all dependencies first)
aws ec2 delete-vpc --vpc-id vpc-0123456789abcdef0
# List subnets
aws ec2 describe-subnets
aws ec2 describe-subnets \\
--filters "Name=vpc-id,Values=vpc-0123456789abcdef0" \\
--query 'Subnets[*].[SubnetId,CidrBlock,AvailabilityZone,Tags[?Key==`Name`].Value|[0]]' \\
--output table
# Create subnet
aws ec2 create-subnet \\
--vpc-id vpc-0123456789abcdef0 \\
--cidr-block 10.0.1.0/24 \\
--availability-zone ap-south-1a
# Enable auto-assign public IP for public subnet
aws ec2 modify-subnet-attribute \\
--subnet-id subnet-0123456789abcdef0 \\
--map-public-ip-on-launch
# Create Internet Gateway (for public internet access)
aws ec2 create-internet-gateway
# Attach to VPC
aws ec2 attach-internet-gateway \\
--internet-gateway-id igw-0123456789abcdef0 \\
--vpc-id vpc-0123456789abcdef0
# List internet gateways
aws ec2 describe-internet-gateways
# Create Route Table
aws ec2 create-route-table --vpc-id vpc-0123456789abcdef0
# Add route to IGW (makes it a "public" route table)
aws ec2 create-route \\
--route-table-id rtb-0123456789abcdef0 \\
--destination-cidr-block 0.0.0.0/0 \\
--gateway-id igw-0123456789abcdef0
# Associate route table with subnet
aws ec2 associate-route-table \\
--route-table-id rtb-0123456789abcdef0 \\
--subnet-id subnet-0123456789abcdef0
# List route tables
aws ec2 describe-route-tables \\
--filters "Name=vpc-id,Values=vpc-0123456789abcdef0"
# Describe NACLs
aws ec2 describe-network-acls \\
--filters "Name=vpc-id,Values=vpc-0123456789abcdef0"
# List NAT Gateways
aws ec2 describe-nat-gateways
# Create NAT Gateway (needs an Elastic IP first, goes in public subnet)
aws ec2 allocate-address --domain vpc # get EIP
aws ec2 create-nat-gateway \\
--subnet-id subnet-public-id \\
--allocation-id eipalloc-0123456789abcdef0

RDS instance → lives in a subnet group (spans multiple AZs) → protected by security groups → optionally has Multi-AZ (HA) and Read Replicas.

Terminal window
# List all RDS instances
aws rds describe-db-instances
aws rds describe-db-instances \\
--query 'DBInstances[*].[DBInstanceIdentifier,DBInstanceStatus,Engine,Endpoint.Address]' \\
--output table
# Create a DB subnet group (required before creating RDS)
aws rds create-db-subnet-group \\
--db-subnet-group-name my-db-subnet-group \\
--db-subnet-group-description "My DB subnet group" \\
--subnet-ids subnet-0abc subnet-0def
# Create a PostgreSQL RDS instance
aws rds create-db-instance \\
--db-instance-identifier mydb \\
--db-instance-class db.t3.micro \\
--engine postgres \\
--engine-version 14.7 \\
--master-username admin \\
--master-user-password 'SecurePass@123' \\
--allocated-storage 20 \\
--db-subnet-group-name my-db-subnet-group \\
--vpc-security-group-ids sg-0123456789abcdef0 \\
--no-publicly-accessible \\
--backup-retention-period 7
# Create MySQL instance (same thing, different engine)
# --engine mysql --engine-version 8.0
# Get the endpoint (wait for status = available first)
aws rds describe-db-instances \\
--db-instance-identifier mydb \\
--query 'DBInstances[0].Endpoint.Address' \\
--output text
# Start / Stop RDS instance
aws rds stop-db-instance --db-instance-identifier mydb
aws rds start-db-instance --db-instance-identifier mydb
# Create a snapshot
aws rds create-db-snapshot \\
--db-instance-identifier mydb \\
--db-snapshot-identifier mydb-snapshot-2024
# List snapshots
aws rds describe-db-snapshots --db-instance-identifier mydb
# Restore from snapshot
aws rds restore-db-instance-from-db-snapshot \\
--db-instance-identifier mydb-restored \\
--db-snapshot-identifier mydb-snapshot-2024 \\
--db-instance-class db.t3.micro
# Modify instance (e.g., change instance class)
aws rds modify-db-instance \\
--db-instance-identifier mydb \\
--db-instance-class db.t3.small \\
--apply-immediately
# Create read replica
aws rds create-db-instance-read-replica \\
--db-instance-identifier mydb-replica \\
--source-db-instance-identifier mydb
# Delete RDS (with final snapshot)
aws rds delete-db-instance \\
--db-instance-identifier mydb \\
--final-db-snapshot-identifier mydb-final-snap
# Delete without snapshot (destructive!)
aws rds delete-db-instance \\
--db-instance-identifier mydb \\
--skip-final-snapshot

Lambda = a function packaged as a ZIP or container → triggered by events (API Gateway, S3, SQS, schedule, etc.) → executes with an IAM role.

Terminal window
# List all functions
aws lambda list-functions
aws lambda list-functions \\
--query 'Functions[*].[FunctionName,Runtime,LastModified]' \\
--output table
# Get function details
aws lambda get-function --function-name my-function
# Get just the config (no download URL)
aws lambda get-function-configuration --function-name my-function
# Create a function from a zip
# First, zip your code:
zip function.zip index.js
aws lambda create-function \\
--function-name my-function \\
--runtime nodejs20.x \\
--role arn:aws:iam::<account-id>:role/MyLambdaRole \\
--handler index.handler \\
--zip-file fileb://function.zip \\
--timeout 30 \\
--memory-size 256
# Update function code
zip function.zip index.js
aws lambda update-function-code \\
--function-name my-function \\
--zip-file fileb://function.zip
# Update function config (env vars, timeout, memory)
aws lambda update-function-configuration \\
--function-name my-function \\
--timeout 60 \\
--memory-size 512 \\
--environment 'Variables={DB_HOST=myhost,NODE_ENV=production}'
# Invoke a function synchronously
aws lambda invoke \\
--function-name my-function \\
--payload '{"key": "value"}' \\
output.json
cat output.json
# Invoke asynchronously
aws lambda invoke \\
--function-name my-function \\
--invocation-type Event \\
--payload '{"key": "value"}' \\
output.json
# Add environment variables
aws lambda update-function-configuration \\
--function-name my-function \\
--environment 'Variables={KEY1=val1,KEY2=val2}'
# List versions
aws lambda list-versions-by-function --function-name my-function
# Publish a version (immutable snapshot)
aws lambda publish-version --function-name my-function
# Create an alias
aws lambda create-alias \\
--function-name my-function \\
--name production \\
--function-version 3
# List event source mappings (SQS, DynamoDB stream triggers)
aws lambda list-event-source-mappings --function-name my-function
# Add permission (allow another service to invoke this function)
aws lambda add-permission \\
--function-name my-function \\
--statement-id AllowS3Invoke \\
--action lambda:InvokeFunction \\
--principal s3.amazonaws.com \\
--source-arn arn:aws:s3:::my-bucket
# View function policy (permissions)
aws lambda get-policy --function-name my-function
# Delete function
aws lambda delete-function --function-name my-function

CloudWatch Logs — Essential for Lambda/EC2 debugging

Section titled “CloudWatch Logs — Essential for Lambda/EC2 debugging”
Terminal window
# List log groups
aws logs describe-log-groups
# List log groups for Lambda (they follow a naming pattern)
aws logs describe-log-groups \\
--log-group-name-prefix /aws/lambda/
# Get log streams in a group (latest first)
aws logs describe-log-streams \\
--log-group-name /aws/lambda/my-function \\
--order-by LastEventTime \\
--descending
# Fetch actual log events
aws logs get-log-events \\
--log-group-name /aws/lambda/my-function \\
--log-stream-name '2024/01/01/[$LATEST]abc123'
# Live tail logs (v2 only, extremely useful)
aws logs tail /aws/lambda/my-function --follow
# Filter logs by pattern
aws logs filter-log-events \\
--log-group-name /aws/lambda/my-function \\
--filter-pattern "ERROR"
# Filter by time range
aws logs filter-log-events \\
--log-group-name /aws/lambda/my-function \\
--start-time $(date -d '1 hour ago' +%s000) \\
--end-time $(date +%s000)

The --query flag uses JMESPath. Learn this, it saves your life.

Terminal window
# Get a single field
aws ec2 describe-instances \\
--query 'Reservations[0].Instances[0].InstanceId' \\
--output text
# Get multiple fields as table
aws iam list-users \\
--query 'Users[*].[UserName,CreateDate,PasswordLastUsed]' \\
--output table
# Filter by value (like WHERE clause)
aws ec2 describe-instances \\
--query 'Reservations[*].Instances[?State.Name==`running`].[InstanceId,PublicIpAddress]' \\
--output table
# Output as JSON (default), table, text, yaml
--output json # default, machine-readable
--output table # human-readable grid
--output text # plain, good for piping/scripting
# Pagination — some commands paginate, use --no-paginate to get all
aws s3api list-objects-v2 --bucket my-bucket --no-paginate
# Dry-run (supported by EC2) — checks permissions without doing the action
aws ec2 run-instances \\
--image-id ami-xxx \\
--instance-type t2.micro \\
--dry-run

What you want to doTypical verb prefix
Read/list thingslist-, describe-, get-
Create a resourcecreate-, run- (EC2), put-
Delete a resourcedelete-, remove-
Modify/updateupdate-, modify-, put-
Link two thingsattach-, associate-, add-
Unlink two thingsdetach-, disassociate-, remove-
Trigger an actionstart-, stop-, invoke-, enable-

When stuck on a command, just run:

Terminal window
aws <service> help
aws <service> <action> help

That’s your offline docs. Use it constantly.


Terminal window
# In your ~/.bashrc or ~/.zshrc
# Shorter aws
alias a='aws'
# Get your own identity fast
alias whoami-aws='aws sts get-caller-identity'
# List running EC2s formatted
alias ec2-running='aws ec2 describe-instances \\
--filters Name=instance-state-name,Values=running \\
--query "Reservations[*].Instances[*].[InstanceId,InstanceType,PublicIpAddress,Tags[?Key==\\`Name\\`].Value|[0]]" \\
--output table'

That’s the full picture. The intuition is: service → verb → resource → options. Every service follows the same grammar. Once IAM clicks, the rest is just learning the nouns.