Managing Multiple AWS Accounts with CLI Profiles: A Practical Guide
Running work and personal AWS accounts from the same machine is a common reality for engineers — and without a proper profile strategy, you risk deploying personal side projects into your company's production account, or worse, billing your employer for your weekend experiments.
TL;DR
| Step | Action | File Modified |
|---|---|---|
| 1 | Add named credentials | ~/.aws/credentials |
| 2 | Add named config (region, output) | ~/.aws/config |
| 3 | Use --profile flag per command | CLI invocation |
| 4 | (Optional) Set AWS_PROFILE env var | Shell session |
How AWS CLI Profile Resolution Works
The AWS CLI uses a layered credential resolution chain. Named profiles are stored across two files: ~/.aws/credentials (access keys) and ~/.aws/config (region, output format, and advanced settings). The default profile is used when no profile is explicitly specified. Every other named profile must be referenced explicitly — either via the --profile flag or the AWS_PROFILE environment variable.
or AWS_PROFILE set?"} B -- "Yes" --> C["Load Named Profile
from ~/.aws/config"] B -- "No" --> D["Load 'default' Profile"] C --> E["Read Credentials
from ~/.aws/credentials"] D --> E E --> F["Resolve Region
& Output Format"] F --> G["Sign Request &
Call AWS API"] G --> H["Target AWS Account"]
- CLI Command Issued: You run an AWS CLI command, optionally with
--profile work. - Profile Lookup: The CLI reads the named profile from
~/.aws/configand~/.aws/credentials. - Credential Resolution: The matching access key ID and secret are loaded for that profile.
- Region & Output: Region and output format are pulled from the profile's config block.
- API Call: The request is signed with the resolved credentials and dispatched to the correct AWS account.
Step 1 — Configure Your Credentials File
The ~/.aws/credentials file stores raw access key pairs. Each section header (e.g., [work]) defines a named profile.
# ~/.aws/credentials
[default]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
[work]
aws_access_key_id = AKIAI44QH8DHBEXAMPLE
aws_secret_access_key = je7MtGbClwBF/2Zp9Utk/h3yCo8nvbEXAMPLEKEY
[personal]
aws_access_key_id = AKIAIOSFODNN7PERSONAL
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYPERSONALKEY
Analogy: Think of ~/.aws/credentials as a keychain. Each named profile is a labeled key — you pick the right key for the right door (AWS account) without fumbling through all of them every time.
Step 2 — Configure Your Config File
The ~/.aws/config file stores non-secret settings. Note the naming convention difference: the default profile is [default], but all other named profiles use the [profile <name>] prefix — this is a strict AWS CLI requirement.
# ~/.aws/config
[default]
region = us-east-1
output = json
[profile work]
region = us-east-1
output = json
[profile personal]
region = ap-southeast-1
output = yaml
Step 3 — Using the --profile Flag
Pass --profile <name> to any AWS CLI command to explicitly select which account context to use. This is the safest, most explicit approach — it leaves no ambiguity about which account is being targeted.
# List S3 buckets in your work account
aws s3 ls --profile work
# List EC2 instances in your personal account (ap-southeast-1)
aws ec2 describe-instances --profile personal
# Deploy a CloudFormation stack to your work account
aws cloudformation deploy \
--template-file template.yaml \
--stack-name my-app-stack \
--profile work
Step 4 — Using AWS_PROFILE for Session-Level Switching
If you're running multiple commands in a row against the same account, exporting AWS_PROFILE in your shell session avoids repeating the flag on every command. This is ideal for dedicated terminal windows per account.
# Set the active profile for this shell session
export AWS_PROFILE=work
# All subsequent commands use the 'work' profile implicitly
aws sts get-caller-identity
aws s3 ls
aws ec2 describe-vpcs
# Switch to personal for this session
export AWS_PROFILE=personal
aws sts get-caller-identity
# Unset to fall back to the default profile
unset AWS_PROFILE
Pro tip: Always run aws sts get-caller-identity --profile <name> to verify which account and IAM principal you're operating as before executing any destructive or expensive commands.
# Verify active identity — always do this before critical operations
aws sts get-caller-identity --profile work
# Expected output:
# {
# "UserId": "AIDACKCEVSQ6C2EXAMPLE",
# "Account": "111122223333",
# "Arn": "arn:aws:iam::111122223333:user/work-admin"
# }
Advanced: IAM Role Assumption Across Accounts
For more secure cross-account workflows — especially in enterprise environments — you can configure a profile to automatically assume an IAM role in another account using role_arn and source_profile. This avoids storing long-lived access keys for every account.
🔽 [Click to expand] — Role Assumption Profile Config
# ~/.aws/config
[profile base-user]
region = us-east-1
output = json
[profile work-role]
role_arn = arn:aws:iam::111122223333:role/DevOpsRole
source_profile = base-user
region = us-east-1
output = json
[profile personal-role]
role_arn = arn:aws:iam::444455556666:role/PersonalAdminRole
source_profile = base-user
region = ap-southeast-1
output = yaml
With this setup, running aws s3 ls --profile work-role causes the CLI to first authenticate as base-user, then call sts:AssumeRole to obtain temporary credentials for DevOpsRole in account 111122223333. Temporary credentials are cached locally by the CLI.
(base-user)" participant STS as "AWS STS" participant Service as "AWS Service
(Target Account)" CLI->>Creds: "Read base-user access keys" Creds-->>CLI: "Long-lived credentials" CLI->>STS: "sts:AssumeRole (DevOpsRole ARN)" STS-->>CLI: "Temporary credentials
(AccessKey + SecretKey + SessionToken)" CLI->>Service: "API Call with temporary credentials" Service-->>CLI: "Response"
- CLI reads
work-roleprofile: Detectsrole_arnandsource_profiledirectives. - Authenticates as
base-user: Uses long-lived access keys from~/.aws/credentials. - Calls
sts:AssumeRole: Requests temporary credentials forDevOpsRolein the target account. - STS returns temp credentials: Access key, secret, and session token (valid for up to 1 hour by default, configurable).
- API call executes: The actual AWS service call is made using the temporary credentials in the target account.
Shell Prompt Integration (Optional but Recommended)
To prevent accidental cross-account operations, display the active AWS profile in your shell prompt. Add the following to your ~/.zshrc or ~/.bashrc:
# Add to ~/.zshrc or ~/.bashrc
prompt_aws_profile() {
if [ -n "$AWS_PROFILE" ]; then
echo "[AWS:$AWS_PROFILE] "
fi
}
# For zsh (add to PROMPT)
PROMPT='$(prompt_aws_profile)'$PROMPT
Security Best Practices
- Least Privilege: Each profile's IAM user or role should have only the permissions required for its intended workload — avoid using root account credentials or overly broad
AdministratorAccesspolicies for day-to-day CLI use. - Prefer Role Assumption: Use
role_arn+source_profileover storing multiple long-lived access keys. Temporary credentials reduce the blast radius of a key compromise. - Rotate Access Keys: Regularly rotate IAM access keys stored in
~/.aws/credentials. Consider using AWS IAM Identity Center (SSO) for credential vending instead of static keys. - File Permissions: Ensure your credentials file is not world-readable:
chmod 600 ~/.aws/credentials.
Glossary
| Term | Definition |
|---|---|
| Named Profile | A labeled configuration block in AWS CLI config/credentials files that groups credentials and settings for a specific account or role. |
| Credential Resolution Chain | The ordered sequence the AWS CLI uses to find credentials: env vars → CLI flags → config files → instance metadata, etc. |
| STS AssumeRole | An AWS Security Token Service API call that returns temporary, scoped credentials for an IAM role in any account that trusts the caller. |
| source_profile | A config directive that tells the CLI which base profile's credentials to use when calling sts:AssumeRole for a role-based profile. |
| AWS_PROFILE | An environment variable that sets the active named profile for all AWS CLI commands in the current shell session. |
Next Steps
- For teams managing many accounts, evaluate AWS IAM Identity Center (formerly AWS SSO) with the
aws configure ssocommand — it eliminates static key management entirely. - Official reference: AWS CLI Named Profiles Documentation
- For automated pipelines, prefer IAM roles attached to compute (EC2 instance profiles, ECS task roles, Lambda execution roles) over any file-based credentials.
Comments
Post a Comment