DS DevShelfHub Projects · AI tools
Cheatsheets / AWS CLI
Cheatsheet · Dev tooling

AWS CLI v2 Cheatsheet: S3, EC2, IAM, Lambda and JMESPath

By DevShelfHub

Profiles, SSO, S3, EC2, IAM, Lambda, CloudFormation, ECS, logs, --query JMESPath — the AWS CLI v2 commands used daily in cloud automation and CI/CD pipelines. Covers named profiles, assume-role chaining, and the output formats needed for scripting.

121 items 9 min Profiles S3 IAM

Start hereQuick start · 6 you’ll reach for daily

Who am Iaws sts get-caller-identity
Switch profileexport AWS_PROFILE=prod
SSO refreshaws sso login --profile prod
Sync to S3aws s3 sync ./dist s3://bucket
Tail logsaws logs tail /aws/lambda/x --follow
Slice JSON--query 'X[?Y==`z`].Id'

Target versions · paceVersions

Targets: aws-cli ≥ 2.15 SSO sessions IMDSv2

v1 is end-of-life — aws --version must start with aws-cli/2.. v2 ships its own Python, supports SSO, auto-paginates by default, and prefers --profile over --region-style flag soup. Region resolution order: --regionAWS_REGION → profile’s region → EC2/ECS metadata.

install · configure · envSetup

bash
# install (macOS — Homebrew)
brew install awscli

# install (Linux — official bundle, recommended for v2)
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip && sudo ./aws/install

# verify
aws --version          # aws-cli/2.x.x Python/3.x …

# classic long-lived keys
aws configure                                      # writes ~/.aws/credentials + ~/.aws/config
aws configure --profile prod                       # named profile

# SSO (preferred for orgs)
aws configure sso                                  # browser-based device flow
aws sso login --profile prod                       # refresh expired token

# env overrides (beat ~/.aws/*)
export AWS_PROFILE=prod
export AWS_REGION=us-east-1
export AWS_PAGER=""                                # disable the less pager

credentials · sso · stsProfiles & auth

aws configureInteractive wizard for the default profile.
aws configure --profile prodNamed profile in ~/.aws/credentials.
aws configure ssoPreferred Org-wide SSO with refreshable session.
aws sso login --profile prodRefresh expired SSO token.
aws sso logoutClear cached SSO creds.
aws configure listShow resolved profile + where each value came from.
aws configure list-profilesAll profile names known to the CLI.
aws sts get-caller-identityUserId/Account/Arn for the current creds. Always start a debug here.
aws sts assume-role --role-arn ARN --role-session-name sCross-account / privilege-escalation flow.
aws sts get-session-token --serial-number ARN --token-code 123456MFA session token.
export AWS_PROFILE=prodPin a profile for this shell.
export AWS_REGION=us-east-1Override default region.
--profile prod --region eu-west-1One-shot override on any command.
Long-lived access keys are a smell. Use SSO for humans, IAM roles for workloads (EC2 instance profile, ECS task role, Lambda execution role). Static keys belong only in ~/.aws/credentials for tools that don’t speak SSO yet.

--output · --query · --filterOutput & queries

--output jsonDefault. Pipe into jq.
--output yamlHuman-readable; round-trips with CloudFormation.
--output textTab-separated. Easy to cut/awk.
--output tableASCII grid. Eyeball-friendly, scripting-hostile.
--query 'Reservations[].Instances[].InstanceId'JMESPath. Project + filter client-side.
--filters Name=tag:Env,Values=prodServer-side filter (only certain APIs).
--no-cli-pagerPrint straight to stdout instead of less.
--no-paginateSkip auto-pagination. Caps at one API page.
--max-items 100 --page-size 50Cap total items and per-call page.
--starting-token TOKENResume from a NextToken.
bash
# --query is client-side JMESPath, but skips the noise.

# one field
aws ec2 describe-instances \
  --query 'Reservations[].Instances[].InstanceId'

# table of {Id, State, Type, Name-tag}
aws ec2 describe-instances \
  --query 'Reservations[].Instances[].{Id:InstanceId, State:State.Name, Type:InstanceType, Name:Tags[?Key==`Name`]|[0].Value}' \
  --output table

# filter by tag, then project
aws ec2 describe-instances \
  --filters 'Name=tag:Env,Values=prod' \
  --query 'Reservations[].Instances[?State.Name==`running`].InstanceId' \
  --output text

# bucket names only
aws s3api list-buckets --query 'Buckets[].Name' --output text

cp · sync · presignS3

aws s3 lsList buckets in current account.
aws s3 ls s3://bucket/path/ --recursive --human-readable --summarizeTree listing + total size.
aws s3 cp file.txt s3://bucket/keySingle object upload.
aws s3 cp s3://bucket/key - | jq .Stream object to stdout.
aws s3 sync ./dist s3://bucket --deleteMirror a local dir; remove orphans on remote.
aws s3 sync s3://src s3://dst --source-region us-east-1Cross-bucket copy.
aws s3 rm s3://bucket/keyDelete object.
aws s3 rb s3://bucket --forceDelete bucket and its contents.
aws s3 presign s3://bucket/key --expires-in 3600Time-limited signed URL.
aws s3api list-objects-v2 --bucket b --prefix p/Lower-level API. Returns metadata.
aws s3api put-object-tagging --bucket b --key k --tagging 'TagSet=[{Key=env,Value=prod}]'Tag an object.
aws s3api put-bucket-policy --bucket b --policy file://p.jsonReplace bucket policy from file.
aws s3 cp file s3://b/k --storage-class GLACIER_IRSet storage class on upload.

instances · SSM · AMIsEC2

aws ec2 describe-instancesAll instances in region. Use --query to tame the output.
aws ec2 describe-instances --instance-ids i-abcSingle instance details.
aws ec2 start-instances --instance-ids i-abcPower on.
aws ec2 stop-instances --instance-ids i-abcPower off. Keeps EBS.
aws ec2 terminate-instances --instance-ids i-abcDestructive. Destroys instance + root volume by default.
aws ec2 run-instances --image-id ami-… --instance-type t3.microLaunch from CLI. Prefer Terraform/CloudFormation in real life.
aws ec2 describe-security-groups --group-ids sg-…Inspect SG rules.
aws ec2 authorize-security-group-ingress --group-id sg-… --protocol tcp --port 22 --cidr 1.2.3.4/32Open a port.
aws ec2 describe-images --owners self --filters Name=tag:role,Values=webFind your AMIs.
aws ec2 create-tags --resources i-abc --tags Key=Env,Value=prodTag an existing resource.
aws ssm start-session --target i-abcPreferred Shell into an instance without SSH/keypair.
aws ec2-instance-connect send-ssh-public-key --instance-id i-abc --instance-os-user ec2-user --ssh-public-key file://k.pubPush a 60-second SSH key.

users · roles · policiesIAM

aws iam list-usersAll users in account.
aws iam list-roles --query 'Roles[].RoleName'Role names only.
aws iam get-role --role-name RRole detail + trust policy.
aws iam list-attached-role-policies --role-name RManaged policies attached to a role.
aws iam list-role-policies --role-name RInline policies on a role.
aws iam get-policy --policy-arn ARNMetadata for a managed policy.
aws iam get-policy-version --policy-arn ARN --version-id v3Actual JSON of a managed policy version.
aws iam create-role --role-name R --assume-role-policy-document file://trust.jsonCreate role with trust policy.
aws iam attach-role-policy --role-name R --policy-arn ARNAttach a managed policy.
aws iam put-role-policy --role-name R --policy-name P --policy-document file://p.jsonAdd an inline policy.
aws iam simulate-principal-policy --policy-source-arn ARN --action-names s3:GetObjectDry-run an authorization decision.
aws iam create-access-key --user-name UMint long-lived keys. Prefer roles + SSO.
aws iam update-access-key --access-key-id AK --status Inactive --user-name UDisable a key without deleting it.
bash
# assume a role from one account into another — capture the temp creds
CREDS=$(aws sts assume-role \
  --role-arn arn:aws:iam::123456789012:role/Deployer \
  --role-session-name ci-deploy \
  --duration-seconds 3600 \
  --query 'Credentials' --output json)

export AWS_ACCESS_KEY_ID=$(echo "$CREDS" | jq -r .AccessKeyId)
export AWS_SECRET_ACCESS_KEY=$(echo "$CREDS" | jq -r .SecretAccessKey)
export AWS_SESSION_TOKEN=$(echo "$CREDS" | jq -r .SessionToken)

# verify identity
aws sts get-caller-identity

functions · invoke · layersLambda

aws lambda list-functions --query 'Functions[].FunctionName'Function inventory.
aws lambda get-function --function-name FConfig + code URL.
aws lambda invoke --function-name F --payload '{"k":"v"}' out.jsonSync invoke. Result goes to out.json.
aws lambda invoke --function-name F --invocation-type Event out.jsonAsync (fire-and-forget).
aws lambda invoke --function-name F --cli-binary-format raw-in-base64-out --payload file://p.json out.jsonv2 requires base64 unless you pass this flag.
aws lambda update-function-code --function-name F --zip-file fileb://fn.zipShip new code from a zip.
aws lambda update-function-code --function-name F --image-uri ECR_URI:tagImage-based deploy.
aws lambda update-function-configuration --function-name F --memory-size 1024 --timeout 30Tweak runtime knobs.
aws lambda update-function-configuration --function-name F --environment Variables='{LOG_LEVEL=info}'Set env vars.
aws lambda publish-version --function-name FSnapshot current config as a numbered version.
aws lambda update-alias --function-name F --name live --function-version 7Shift an alias to a new version.
aws lambda list-layersLayer inventory in region.

clusters · services · tasksECS / Fargate

aws ecs list-clustersCluster ARNs.
aws ecs list-services --cluster CService ARNs in a cluster.
aws ecs describe-services --cluster C --services SDesired/running count, deployments, events.
aws ecs update-service --cluster C --service S --force-new-deploymentRoll the service even if the image tag is unchanged.
aws ecs update-service --cluster C --service S --desired-count 4Scale.
aws ecs register-task-definition --cli-input-json file://task-def.jsonRegister a new task-def revision.
aws ecs describe-task-definition --task-definition fam:revInspect a task-def.
aws ecs run-task --cluster C --task-definition fam --launch-type FARGATE --network-configuration …Run an ad-hoc task (cron, migration).
aws ecs execute-command --cluster C --task T --container c --interactive --command "/bin/sh"Shell into a Fargate task (needs exec-config enabled).
aws ecs list-tasks --cluster C --service-name STask ARNs for a service.

stacks · change sets · driftCloudFormation

aws cloudformation deploy --template-file t.yml --stack-name S --capabilities CAPABILITY_NAMED_IAMPreferred Creates stack if missing, otherwise applies a change set.
aws cloudformation create-stack --stack-name S --template-body file://t.ymlLegacy Lower-level create.
aws cloudformation update-stack --stack-name S --template-body file://t.ymlApply a diff. Fails if no changes.
aws cloudformation describe-stacks --stack-name SStatus, outputs, parameters.
aws cloudformation describe-stack-events --stack-name SPer-resource event log. Find the failing resource here.
aws cloudformation list-stack-resources --stack-name SResource inventory + physical IDs.
aws cloudformation create-change-set --stack-name S --template-body file://t.yml --change-set-name cs1Preview a deploy without applying.
aws cloudformation execute-change-set --change-set-name cs1 --stack-name SApply the previewed change set.
aws cloudformation detect-stack-drift --stack-name SAsync drift check. Poll with describe-stack-drift-detection-status.
aws cloudformation delete-stack --stack-name SDestructive. Tears down all managed resources.
aws cloudformation validate-template --template-body file://t.ymlSyntactic validation only — no resource checks.

CloudWatch logs · insightsLogs & metrics

aws logs describe-log-groups --query 'logGroups[].logGroupName'Log-group inventory.
aws logs tail /aws/lambda/F --since 15m --followPreferred Live tail in your terminal.
aws logs tail /aws/ecs/svc --filter-pattern 'ERROR'Substring filter on the live stream.
aws logs filter-log-events --log-group-name G --start-time MS --filter-pattern 'p'One-shot batch query.
aws logs put-retention-policy --log-group-name G --retention-in-days 30Cap retention. New groups default to Never expire.
aws cloudwatch get-metric-statistics --namespace AWS/Lambda --metric-name Errors --start-time T --end-time T --period 300 --statistics Sum --dimensions Name=FunctionName,Value=FPull a metric series.
aws cloudwatch put-metric-alarm --alarm-name A --metric-name Errors --namespace AWS/Lambda --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --period 60 --statistic SumCreate an alarm from CLI.
bash
# live tail (follow), last 10 min
aws logs tail /aws/lambda/my-fn --since 10m --follow

# filter by pattern (case-sensitive substring or metric filter syntax)
aws logs tail /aws/lambda/my-fn --since 1h --filter-pattern 'ERROR'

# multiple streams, JSON output for piping
aws logs tail /aws/ecs/my-svc --format json --since 30m | jq '.message'

# one-shot query via Logs Insights
QUERY_ID=$(aws logs start-query \
  --log-group-name /aws/lambda/my-fn \
  --start-time $(date -v-1H +%s) --end-time $(date +%s) \
  --query-string 'fields @timestamp, @message | filter @message like /ERROR/ | sort @timestamp desc | limit 50' \
  --query queryId --output text)

aws logs get-query-results --query-id "$QUERY_ID"

sync · invalidate · tailEnd-to-end · Ship a static site

Upload a built site to S3 with sane cache headers, invalidate CloudFront so the change is visible instantly, then tail the edge function’s logs to confirm it’s healthy. Wire this into CI and you have a single-command deploy.

bash
# end-to-end: ship a static site to S3 + invalidate CloudFront
BUCKET=my-site-prod
DIST_ID=E1ABCDXYZ12345
REGION=us-east-1

# 1) sync the build (delete removed files, set cache headers)
aws s3 sync ./dist "s3://$BUCKET" \
  --delete \
  --cache-control "public, max-age=31536000, immutable" \
  --exclude "index.html"

# 2) re-upload index.html with a short TTL so updates roll out fast
aws s3 cp ./dist/index.html "s3://$BUCKET/index.html" \
  --cache-control "public, max-age=60"

# 3) bust CloudFront edge cache
aws cloudfront create-invalidation \
  --distribution-id "$DIST_ID" \
  --paths "/*"

# 4) tail Lambda@Edge logs (optional)
aws logs tail "/aws/lambda/us-east-1.my-edge-fn" --since 5m --follow

Best practiceGood to know

Anchor every debug session with sts get-caller-identity. If the answer surprises you, every command after this point is hitting the wrong account or role. Faster than chasing a confusing 403.
Prefer --query over piping to jq for shell composition. --output text with a JMESPath projection produces clean tab/newline-separated values that xargs and while read handle natively.
SSM Session Manager beats SSH for ad-hoc access. No keypair, no bastion, no inbound port 22 — just aws ssm start-session and IAM authorizes the shell. Sessions are logged to CloudTrail.

Common trapsWatch out for

v2 expects payloads as base64. aws lambda invoke --payload '{…}' errors with Invalid base64. Either pass --cli-binary-format raw-in-base64-out or set cli_binary_format = raw-in-base64-out in your profile.
Region defaults are sticky in subtle ways. A profile’s region wins over AWS_REGION only if you pass --profile. EC2 metadata wins when no profile is set. Always pass --region explicitly in CI to remove ambiguity.
aws s3 sync --delete is one keystroke from data loss. Reversing src/dst (or pointing at the wrong bucket) deletes everything not present locally. Dry-run with --dryrun the first time on a new path.

Go deeperSee also

AWS CLI FAQ

What is AWS CLI v2?

AWS CLI v2 is the official command-line tool for managing AWS services. It ships as a self-contained binary with no Python runtime dependency, adds native SSO support, automatic pagination, and a built-in pager. Install it from the official AWS installer — not pip — to get the full v2 feature set.

How do I configure named profiles in the AWS CLI?

Run `aws configure --profile <name>` and enter your access key, secret key, default region, and output format. Reference the profile per command with `--profile <name>`, or export `AWS_PROFILE=<name>` to use it for the entire shell session without repeating the flag.

How does the AWS CLI --query flag work?

The `--query` flag accepts a JMESPath expression that filters or reshapes the JSON response before output. For example, `--query 'Reservations[].Instances[].InstanceId'` returns a flat list of EC2 instance IDs from the verbose `describe-instances` response.

How do I use AWS SSO with the AWS CLI?

Run `aws configure sso` to register your SSO start URL and region. The wizard creates a named profile automatically. Authenticate each session with `aws sso login --profile <name>`, which opens a browser for the SSO portal. Tokens are cached locally and expire per your IdP policy.

What is the difference between AWS CLI v1 and v2?

AWS CLI v2 ships as a standalone binary with no Python dependency, adds native SSO and credential-process support, outputs pagination hints automatically, and breaks a small number of v1 behaviours (such as how binary parameters are passed). AWS recommends v2 for all new work; v1 is in maintenance mode only.

How do I use the AWS CLI in CI/CD pipelines without hardcoded credentials?

In GitHub Actions, use the aws-actions/configure-aws-credentials action with OIDC federation — no secrets needed. The action exchanges a GitHub-issued OIDC token for temporary AWS credentials via sts:AssumeRoleWithWebIdentity. For EC2 and ECS, attach an IAM instance role or task role; the CLI automatically picks up credentials from the metadata service.