cheat sheet

AWS CLI

Drive every AWS service from a terminal. Covers install (pip vs v2 installer), aws configure, profiles, SSO, day-to-day commands across S3 / EC2 / Lambda / IAM / STS, common scenarios, and credential precedence.

#python#aws#cloud#cli#sdkupdated 05-31-2026

AWS CLI — Command-Line Interface for Amazon Web Services

What it is

The AWS CLI (aws) is Amazon's official command-line interface for managing AWS resources from a terminal or shell script. It wraps the same botocore library that powers the Python boto3 SDK, exposing every AWS service operation as a subcommand. Wherever the AWS Console gives you a button, the AWS CLI gives you a command.

There are two product lines:

  • AWS CLI v1 — pip-installed, written entirely in Python. Still maintained for security fixes; new feature development stopped years ago.
  • AWS CLI v2 — the current default. Ships as a self-contained binary (no Python install required), adds first-class SSO, a redesigned aws configure flow, and a few syntax improvements. Available on macOS, Linux, Windows, and Docker.

Reach for the AWS CLI whenever you need to inspect or drive AWS from a shell. For application code, boto3 (the Python SDK) is the right layer; for repeatable infrastructure changes, IaC (CDK, Terraform) is better than a script of aws calls. The CLI is best for: one-off operations, support tickets, CI/CD glue, and exploratory work.

Install

macOS (universal .pkg):

bash
curl -O https://awscli.amazonaws.com/AWSCLIV2.pkg
sudo installer -pkg AWSCLIV2.pkg -target /
aws --version

Output:

bash
aws-cli/2.17.42 Python/3.12.x Darwin/24.0.0 source/arm64

Linux (x86_64):

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

Output:

bash
aws-cli/2.17.42 Python/3.12.x Linux/6.x source/x86_64.ubuntu

Windows (PowerShell):

powershell
msiexec.exe /i https://awscli.amazonaws.com/AWSCLIV2.msi
aws --version

Output: aws-cli/2.17.42 Python/3.12.x Windows/10

v1 via pip (legacy)

bash
pip install awscli
aws --version

Output:

code
aws-cli/1.34.0 Python/3.12.x Darwin/24.0.0 botocore/1.34.0

Prefer v2 for any new install. v1 is in security-fix-only mode and lacks SSO support, the modern aws configure sso flow, and several newer service operations.

v2 via pip (not officially supported)

bash
pip install awscliv2     # community-packaged wrapper

Output: installs a Python wrapper that downloads and shells out to the official v2 binary. Functional, but the official installer is preferred.

Verify your install

bash
aws --version
aws configure list
which aws        # macOS / Linux
where aws        # Windows

Output: version line, the current credentials/profile/region settings, and the binary's location. If aws --version says aws-cli/1.x, you have v1.

Configuration

The AWS CLI reads credentials, region, and output settings from (in order): command-line flags → environment variables → the active profile in ~/.aws/credentials / ~/.aws/config → an EC2/ECS/Lambda IAM role.

Initial setup with aws configure

bash
aws configure

Output:

rust
AWS Access Key ID [None]: AKIAEXAMPLE...
AWS Secret Access Key [None]: ...
Default region name [None]: us-east-1
Default output format [None]: json

Writes to ~/.aws/credentials (the keys) and ~/.aws/config (region + output). Subsequent aws calls use the default profile unless overridden.

Named profiles

bash
aws configure --profile prod
aws configure --profile dev
aws s3 ls --profile prod

Output: profile-specific configuration; --profile prod switches credentials for that one call. Set AWS_PROFILE=prod to make it sticky for the shell session.

Environment variables (CI and Docker)

bash
export AWS_ACCESS_KEY_ID=AKIAEXAMPLE...
export AWS_SECRET_ACCESS_KEY=...
export AWS_SESSION_TOKEN=...               # only when using STS / SSO
export AWS_REGION=us-east-1
export AWS_PROFILE=prod                    # alternative to keys
aws sts get-caller-identity

Output: JSON identity payload — UserId, Account, Arn. The most useful sanity check after configuring anything.

Files involved

  • ~/.aws/credentialsaws_access_key_id / aws_secret_access_key per profile
  • ~/.aws/configregion, output, role_arn, source_profile, sso_* settings per profile (profiles use [profile prod] header except for [default])
  • ~/.aws/sso/cache/ — SSO token cache

Day-to-day commands

The table below covers the operations you'll reach for most often. Every command supports --region, --profile, --output, --query, and --no-paginate.

CommandWhat it does
aws sts get-caller-identityPrint the current identity (account, ARN). Best smoke test.
aws configure listShow resolved configuration (which keys/region come from where).
aws s3 lsList buckets.
aws s3 ls s3://my-bucket/prefix/List objects under a prefix.
aws s3 cp local.txt s3://my-bucket/key.txtUpload a file.
aws s3 cp s3://my-bucket/key.txt ./Download a file.
aws s3 sync ./build s3://my-site/Recursive sync (idempotent).
aws s3 rm s3://my-bucket/key.txtDelete an object.
aws s3 presign s3://my-bucket/key --expires-in 3600Generate a time-limited URL.
aws ec2 describe-instancesList EC2 instances (paginated).
aws ec2 start-instances --instance-ids i-abc123Start an instance.
aws ec2 stop-instances --instance-ids i-abc123Stop an instance.
aws lambda invoke --function-name my-fn out.jsonSynchronous Lambda invoke.
aws lambda list-functionsList functions in the current region.
aws logs tail /aws/lambda/my-fn --followTail CloudWatch logs (v2 only).
aws iam list-usersList IAM users.
aws iam get-user --user-name alicedevGet one user.
aws iam list-attached-user-policies --user-name alicedevList attached managed policies.
aws ssm get-parameter --name /app/db_url --with-decryptionRead a parameter (decrypts SecureString).
aws secretsmanager get-secret-value --secret-id app/dbRead a secret.
aws cloudformation deploy --template-file t.yaml --stack-name sDeploy a stack.
aws dynamodb scan --table-name usersScan a table (avoid in prod).
aws sqs receive-message --queue-url $URL --wait-time-seconds 20Long-poll a queue.

Common scenarios

The recipes below show end-to-end patterns you'll repeat across many environments.

Verify your identity and region

bash
aws sts get-caller-identity
aws configure list
echo "Region: ${AWS_REGION:-$(aws configure get region)}"

Output:

csharp
{
    "UserId": "AIDAEXAMPLEUSERID",
    "Account": "123456789012",
    "Arn": "arn:aws:iam::123456789012:user/alicedev"
}
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                  prod           env-var    AWS_PROFILE
access_key     ****************XYZA shared-credentials-file
secret_key     ****************wxyz shared-credentials-file
    region                us-east-1            config-file
Region: us-east-1

The single best diagnostic when "AWS isn't working" — confirms which credentials and region are in effect.

Copy a bucket between accounts

bash
aws s3 sync s3://source-bucket s3://dest-bucket \
    --source-region us-east-1 --region us-west-2 \
    --acl bucket-owner-full-control

Output: progress lines per object (copy: s3://source-bucket/key to s3://dest-bucket/key). --acl bucket-owner-full-control ensures the destination account owns the copies — critical for cross-account scenarios.

List EC2 instances with custom output

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

Output:

lua
----------------------------------------------------
|                DescribeInstances                 |
+-----------------+----------+---------------------+
|  i-0abc123     |  running |  web-1              |
|  i-0def456     |  stopped |  worker-2           |
+-----------------+----------+---------------------+

--query is JMESPath — same engine boto3's Paginator.search() uses. Faster than piping through jq for simple filtering.

Invoke a Lambda synchronously

bash
aws lambda invoke \
    --function-name my-fn \
    --cli-binary-format raw-in-base64-out \
    --payload '{"name": "alice-dev"}' \
    /tmp/response.json
cat /tmp/response.json

Output:

bash
{
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST"
}
{"greeting":"Hello, alice-dev!"}

--cli-binary-format raw-in-base64-out is the v2 default that lets you pass JSON directly. Without it v2 expects base64-encoded payloads.

Assume a cross-account role

bash
CREDS=$(aws sts assume-role \
    --role-arn arn:aws:iam::123456789012:role/CrossAccount \
    --role-session-name myhost-$(date +%Y%m%d-%H%M))

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

aws sts get-caller-identity     # now reports the assumed role

Output: the second get-caller-identity shows the assumed-role ARN. Cleaner alternative: configure a profile with role_arn + source_profile in ~/.aws/config and use --profile.

List IAM users with the account they belong to

bash
aws iam list-users \
    --query 'Users[*].[UserName, Arn, CreateDate]' \
    --output table

Output:

ruby
-----------------------------------------------------------------
|                          ListUsers                            |
+-----------+--------------------------------------+------------+
|  alicedev | arn:aws:iam::123456789012:user/alic… | 2024-01-15 |
|  bobops   | arn:aws:iam::123456789012:user/bobo… | 2025-03-22 |
+-----------+--------------------------------------+------------+

Read CloudWatch Logs from the last hour

bash
aws logs tail /aws/lambda/my-fn --since 1h --format short

Output:

makefile
2026-05-31T13:32:01 START RequestId: a1b2c3d4-…
2026-05-31T13:32:01 INFO  Processing payload
2026-05-31T13:32:02 END   RequestId: a1b2c3d4-…

Add --follow to stream live. v1 doesn't have aws logs tail — use aws logs filter-log-events instead.

Useful flags

The flags below apply to nearly every command.

FlagPurpose
--profile <name>Use the named profile from ~/.aws/config.
--region <region>Override the resolved region.
--output json|text|table|yamlResponse format. json is the default; table is nicer for ad-hoc reading.
--query '<jmespath>'Filter/reshape the response with JMESPath.
--no-paginateGet one page only; useful when piping to head.
--max-items NCap items returned across pages.
--page-size NPer-page request size (lower CPU on big lists).
--debugPrint full HTTP request/response. Verbose; never use in CI logs (leaks signatures).
--cli-auto-promptInteractive prompt — useful when exploring an unfamiliar service (v2 only).
--cli-binary-format raw-in-base64-outv2 default for raw JSON --payload arguments.
--endpoint-url <url>Override the endpoint (LocalStack, VPC endpoints).
--no-cli-pagerDisable the auto-pager (less).
--no-verify-sslDisable TLS verification. Don't.

Profile management

Profiles are the main mechanism for switching between AWS accounts and roles. They live in ~/.aws/config and ~/.aws/credentials.

Static keys

ini
# ~/.aws/credentials
[default]
aws_access_key_id = AKIA...
aws_secret_access_key = ...

[dev]
aws_access_key_id = AKIA...
aws_secret_access_key = ...
ini
# ~/.aws/config
[default]
region = us-east-1
output = json

[profile dev]
region = us-west-2
output = yaml

Output: aws sts get-caller-identity --profile dev runs against the dev account.

Role assumption profiles

ini
# ~/.aws/config
[profile prod-admin]
role_arn = arn:aws:iam::555555555555:role/Admin
source_profile = default
region = us-east-1
duration_seconds = 3600

Output: aws sts get-caller-identity --profile prod-admin returns the assumed role. The CLI auto-renews the STS credentials as needed.

bash
aws configure sso

Output (interactive):

yaml
SSO session name (Recommended): jay-sso
SSO start URL: https://my-org.awsapps.com/start
SSO region: us-east-1
SSO registration scopes: sso:account:access

Then opens a browser for the SSO login. Subsequent commands use the SSO token:

ini
# ~/.aws/config (generated)
[profile prod]
sso_session = jay-sso
sso_account_id = 123456789012
sso_role_name = AdminAccess
region = us-east-1
bash
aws sso login --profile prod
aws s3 ls --profile prod

Output: SSO token cached for ~8 hours (varies by config); aws s3 ls works until token expires.

Inspect resolved profile

bash
aws configure list --profile prod
aws configure get region --profile prod

Output: shows where each setting came from (env var, profile file, default). The single most useful command when "wrong region" / "wrong account" surprises you.

Common pitfalls

The list below collects the failures I see in support tickets month after month.

  1. Region defaults silently. If neither AWS_REGION nor a profile region is set, calls default to us-east-1 for global services (IAM, STS) but FAIL for regional ones (EC2, Lambda). Always set a region explicitly — aws configure set region us-east-1 in default, or AWS_REGION in CI.
  2. Credential precedence surprises. The CLI walks: CLI flags → env vars → profile → IAM role. A stray AWS_PROFILE env var beats your --profile flag in some shells (shell-specific behavior); a stray AWS_ACCESS_KEY_ID env var beats every profile. aws configure list reveals which wins.
  3. v1 vs v2 syntax differences. v2 changed --cli-binary-format default; v2 added aws logs tail; v2 removed some long-deprecated aliases. Scripts that "worked before" may need a small refactor when moving from v1 to v2.
  4. Pagination by default. aws ec2 describe-instances returns all instances by paginating in the background — slow for big accounts. Use --page-size 100 and --max-items 50 for exploration; --no-paginate to see one raw page.
  5. --output table truncates. Long ARNs and tags get cut. Use --output json (or yaml) when feeding to other tools.
  6. Auto-pager (less) swallows stdout in scripts. Set AWS_PAGER="" or pass --no-cli-pager in non-interactive contexts.
  7. aws s3 vs aws s3api. aws s3 is the high-level wrapper (cp, sync, ls); aws s3api is the raw 1:1 API. Some operations only exist under s3api (s3api put-bucket-cors, etc.).
  8. --query JMESPath is finicky with mixed types and missing keys. Tags[?Key==``Name``].Value | [0] returns null when the tag is missing — wrap with --output text filters in shell scripts cautiously.
  9. SSO tokens expire. A long-running CI job that runs over an SSO session boundary will fail. Switch to a long-lived IAM role for CI.
  10. --debug leaks credentials. Request signatures, headers, and sometimes payloads land in the log. Never run --debug in a pipeline that uploads logs.
  11. Empty output ≠ error. aws s3 ls s3://my-bucket/missing/ exits 0 with no output. Check exit codes carefully; many list commands succeed even when zero items match.
  12. aws configure overwrites silently — it does not back up the existing profile. Keep ~/.aws/ under chezmoi or a personal dotfiles repo.

See also

  • Packages: pip-boto3 — Python SDK for application code
  • Concept: API — REST + signing fundamentals
  • Python: installation — getting Python ready for pip install awscli
  • Official AWS CLI documentation
  • Full v2 command reference
  • JMESPath query language (used by --query)