Everything you need to know about AWS CLI Profiles

The AWS CLI uses two files in ~/.aws/:

  • ~/.aws/credentials — access keys, one section per profile.
  • ~/.aws/config — region, output format, SSO settings.

If you only have one AWS account this is overkill, but the moment you have a personal account and a work account — or several work accounts — profiles are what let you keep them all addressable from a single shell. Here's the lay of the land in 2026, starting with the legacy access-key flow and ending with IAM Identity Center, which is what you should actually be using.

Multiple profiles, the basics

Each section in ~/.aws/credentials is a profile. Add new ones beneath [default]:

1[default] 2aws_access_key_id = YOUR_DEFAULT_ACCESS_KEY 3aws_secret_access_key = YOUR_DEFAULT_SECRET_KEY 4 5[personal] 6aws_access_key_id = YOUR_PERSONAL_ACCESS_KEY 7aws_secret_access_key = YOUR_PERSONAL_SECRET_KEY 8 9[work] 10aws_access_key_id = YOUR_WORK_ACCESS_KEY 11aws_secret_access_key = YOUR_WORK_SECRET_KEY

In ~/.aws/config, the section names are prefixed profile (except for [default]):

1[default] 2region = us-west-2 3output = json 4 5[profile personal] 6region = us-west-1 7output = text 8 9[profile work] 10region = eu-west-1 11output = json

These files are INI, despite the = syntax looking TOML-ish.

Switching profiles

Use --profile:

1aws s3 ls --profile personal

Or set AWS_PROFILE (AWS_DEFAULT_PROFILE is the older name and still works, but AWS_PROFILE wins if both are set):

1export AWS_PROFILE=personal

If --profile is omitted and neither env var is set, the CLI uses [default].

Aliases are convenient when you switch between two or three profiles all day. Add to your shell rc file:

1alias awspersonal="AWS_PROFILE=personal aws" 2alias awswork="AWS_PROFILE=work aws"

Then awspersonal s3 ls runs against the personal profile without changing the env for the rest of the shell.

IAM Identity Center: the right way in 2026

What used to be called "AWS SSO" was renamed IAM Identity Center in mid-2022. The CLI integration was overhauled at the same time — modern AWS CLI v2 (since 2.9) writes a separate [sso-session] block that profiles reference by name, rather than inlining the SSO settings into every profile.

Run:

1aws configure sso

The wizard prompts for an SSO session name first, then the start URL, region, account, and role:

1SSO session name (Recommended): my-sso 2SSO start URL [None]: https://your-org.awsapps.com/start 3SSO region [None]: eu-north-1 4SSO registration scopes [sso:account:access]:

It opens a browser, you click through the device-grant flow, and the wizard writes something like this to ~/.aws/config:

1[sso-session my-sso] 2sso_start_url = https://your-org.awsapps.com/start 3sso_region = eu-north-1 4sso_registration_scopes = sso:account:access 5 6[profile work] 7sso_session = my-sso 8sso_account_id = 123456789012 9sso_role_name = AdministratorAccess 10region = eu-north-1 11output = json

After that, aws s3 ls --profile work just works. When the SSO session expires (12 hours by default), you'll get a token error — re-authenticate with:

1aws sso login --profile work

The CLI does not silently re-launch the browser flow on expiration; you have to ask.

The big win: no long-lived access keys on disk. Temporary credentials are fetched fresh per role assumption and cached under ~/.aws/sso/cache/ until the session expires.

When you're stuck with long-lived keys

Some CI runners, third-party tools, and bootstrap scripts still want raw AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY env vars. If you can't avoid them, get them out of the plaintext credentials file.

Option 1: credential_process. Point ~/.aws/config at a tool that returns credentials as JSON. The de-facto choices in 2026:

  • aws-vault — stores keys in the OS keychain, vends short-lived session tokens to the CLI on demand.
  • granted — same idea, plus per-tab role switching for the AWS console.
  • Leapp — GUI alternative if you'd rather not drive it from the terminal.

These plug into the AWS CLI through credential_process, so every SDK that reads the shared config picks them up automatically.

Option 2: hand-rolled keychain export. Lower-level, no extra binaries. Stuff the keys into the OS keychain and export them in your shell:

1# macOS 2security add-generic-password -a AWS -s AWS_ACCESS_KEY_ID -w <ACCESS_KEY> 3security add-generic-password -a AWS -s AWS_SECRET_ACCESS_KEY -w <SECRET_KEY> 4 5export AWS_ACCESS_KEY_ID=$(security find-generic-password -a AWS -s AWS_ACCESS_KEY_ID -w) 6export AWS_SECRET_ACCESS_KEY=$(security find-generic-password -a AWS -s AWS_SECRET_ACCESS_KEY -w)
1:: Windows 2cmdkey /add:AWS_ACCESS_KEY_ID /user:AWS /pass:<ACCESS_KEY> 3cmdkey /add:AWS_SECRET_ACCESS_KEY /user:AWS /pass:<SECRET_KEY>
1# Linux (libsecret) 2secret-tool store --label='AWS access key' service AWS account AWS_ACCESS_KEY_ID 3secret-tool store --label='AWS secret key' service AWS account AWS_SECRET_ACCESS_KEY 4 5export AWS_ACCESS_KEY_ID=$(secret-tool lookup service AWS account AWS_ACCESS_KEY_ID) 6export AWS_SECRET_ACCESS_KEY=$(secret-tool lookup service AWS account AWS_SECRET_ACCESS_KEY)

secret-tool matches secrets by attribute key/value pairs — the service and account attributes have to be identical between the store and lookup calls. The actual secret is read from stdin during store.

Both options beat plaintext in ~/.aws/credentials. Both are still worse than IAM Identity Center.