Skip to main content
from-aws-config.md16.3 KB
View on GitHub

Migrating from AWS CLI Config

This reference is the agent's decision guide for users coming from ~/.aws/config and ~/.aws/credentials. There is no standalone prose tutorial for this migration yet -- for the full auth configuration schema, see Atmos Auth configuration and its providers and identities reference pages.

Identifying the User's Shape

A ~/.aws/config/~/.aws/credentials setup is rarely just one thing -- most users have a mix. Identify each profile's shape before proposing YAML:

Profile has...Maps to
sso_start_url/sso_region/sso_account_id/sso_role_name, or an [sso-session] blockSSO Profiles
aws_access_key_id/aws_secret_access_key in ~/.aws/credentialsStatic Access Keys
source_profile + role_arn (one or more hops)Role Chaining
The above plus mfa_serialMFA-Gated Role Assumption
credential_processaws/credential-process

Most real-world configs combine two or three of these (e.g., one SSO base profile, several role_arn/source_profile profiles chained off it). Migrate the base profile first, then layer the chains on top -- don't try to translate the whole file in one pass.

Command Equivalence

Old AWS CLI workflowatmos auth equivalent
export AWS_PROFILE=x then run aws ...atmos auth exec -i x -- aws ... (one-off) or atmos auth shell -i x then aws ... (session)
aws sso login --profile xatmos auth login -i x
aws sts get-caller-identity --profile xatmos auth whoami -i x
aws configure list-profilesatmos auth list
Manually running aws sts assume-role --role-arn ... --profile base and exporting the resultNo manual step -- via.identity chaining does this automatically on every atmos auth login/exec/shell
eval $(aws configure export-credentials --profile x --format env)eval $(atmos auth env -i x)
Switching profiles between terminal tabs by re-exporting AWS_PROFILEatmos auth shell -i x per tab (isolated) or atmos auth env -i x per tab

Shells, exec, and Your Default AWS Config File

By default, Atmos does not read or write your system's default ~/.aws/config or ~/.aws/credentials. It manages its own credential files elsewhere and keeps them out of the files the raw AWS CLI reads by default -- so migrating to Atmos doesn't clobber any profiles the user (or other tools) still rely on outside of Atmos.

The two recommended patterns for running commands under an identity:

  • atmos auth shell -i <identity> -- launches a subshell with that identity's credentials active. Nothing outside the subshell is affected; exiting it cleans up.
  • atmos auth exec -i <identity> -- <command> -- runs a single command with the identity's credentials injected, no subshell needed.

If the user wants their normal shell (and tools that assume the default file locations) to "just work" without a subshell or command wrapper, atmos auth env is the answer:

eval $(atmos auth env --identity dev-admin)
aws s3 ls # picks up Atmos-managed credentials transparently

This doesn't write into ~/.aws/config/~/.aws/credentials either -- it exports AWS_CONFIG_FILE and AWS_SHARED_CREDENTIALS_FILE pointing at Atmos-managed files (plus AWS_PROFILE/AWS_REGION), which the AWS CLI and SDKs honor transparently. The user's own default files stay untouched; atmos auth env just redirects where the current shell looks. Safe to put eval $(atmos auth env) in .bashrc/.zshrc -- it doesn't trigger a login prompt by itself (add --login if the user wants that too).

SSO Profiles → aws/iam-identity-center + aws/permission-set

Before (~/.aws/config):

[profile dev-admin]
sso_start_url = https://company.awsapps.com/start
sso_region = us-east-1
sso_account_id = 123456789012
sso_role_name = AdminAccess
region = us-east-1

After (atmos.yaml):

auth:
providers:
company-sso:
kind: aws/iam-identity-center
region: us-east-1
start_url: https://company.awsapps.com/start
auto_provision_identities: true # optional: bulk-discover accounts/permission sets

identities:
dev-admin:
kind: aws/permission-set
default: true
via:
provider: company-sso
principal:
name: AdminAccess
account:
id: "123456789012" # or account.name, if resolved via SSO ListAccounts

One aws/iam-identity-center provider serves every profile that shares the same sso_start_url/sso_region (including newer [sso-session]-based configs, which are the same shape -- the session block's sso_start_url/sso_region become the provider, each profile that references the session becomes an aws/permission-set identity). Don't create one provider per profile.

Static Access Keys → aws/user

Before (~/.aws/credentials):

[emergency-access]
aws_access_key_id = AKIA...
aws_secret_access_key = ...

After (atmos.yaml):

auth:
identities:
emergency-access:
kind: aws/user
credentials:
access_key_id: !env AWS_ACCESS_KEY_ID
secret_access_key: !env AWS_SECRET_ACCESS_KEY
region: us-east-1

aws/user is the only identity kind that needs no via -- credentials are inline. Prefer atmos auth user configure --identity=emergency-access over hand-writing keys into atmos.yaml or shell env files; it stores them in the OS keyring (or the configured keyring backend) instead of a config file a teammate or CI log could leak.

Zero-Config Alternative: Browser-Based Login (No Static Credentials At All)

Be explicit with users that static keys are no longer required, full stop -- this is a bigger improvement over raw AWS CLI profiles than the sections above suggest. aws/user identities fall back automatically to a browser OAuth2 PKCE flow against AWS's own sign-in service whenever no static credentials and no keyring entry are configured:

auth:
identities:
dev:
kind: aws/user # no `credentials:` block at all

atmos auth login -i dev opens the default browser, completes AWS's PKCE flow, and caches a refresh token for 12-hour session reuse (credentials auto-refresh every 15 minutes within that window). In non-interactive environments (CI, remote servers) Atmos prints a URL to open manually. This is the same convenience SSO users already had -- IAM users and even root accounts no longer need aws_access_key_id/aws_secret_access_key anywhere.

This changes the migration recommendation: for a user's static-key profiles that aren't break-glass/emergency credentials, prefer pointing them at this zero-config path over migrating the keys at all. Reserve inline credentials: (or atmos auth user configure) for cases that specifically need long-lived, non-interactive credentials -- CI service accounts, break-glass access, or environments where a browser genuinely isn't reachable even for the manual-URL fallback.

Set credentials.webflow_enabled: false to disable this fallback if the user wants strict static-only or keyring-only resolution (e.g., to fail loudly instead of prompting a browser during automation).

Role Chaining (source_profile + role_arn) → via.identity

Before (~/.aws/config):

[profile base]
sso_start_url = https://company.awsapps.com/start
sso_region = us-east-1
sso_account_id = 111111111111
sso_role_name = AdminAccess

[profile prod]
role_arn = arn:aws:iam::999999999999:role/ProductionAdmin
source_profile = base
role_session_name = terraform

After (atmos.yaml):

auth:
identities:
base:
kind: aws/permission-set
via:
provider: company-sso
principal:
name: AdminAccess
account:
id: "111111111111"

prod:
kind: aws/assume-role
via:
identity: base
principal:
assume_role: arn:aws:iam::999999999999:role/ProductionAdmin
session_name: terraform

Multi-hop chains (profile-a → profile-b → profile-c) translate the same way: each identity's via.identity points at the previous hop. via.provider and via.identity are mutually exclusive -- only the first identity in a chain uses via.provider.

MFA-Gated Role Assumption (mfa_serial)

Before: a source_profile/role_arn profile with mfa_serial set.

After: put mfa_arn on the upstream aws/user identity, not on the aws/assume-role identity -- aws/assume-role has no MFA field. The already-MFA'd session from the upstream identity satisfies any aws:MultiFactorAuthPresent condition on the assumed role's trust policy:

auth:
identities:
base:
kind: aws/user
credentials:
access_key_id: !env AWS_ACCESS_KEY_ID
secret_access_key: !env AWS_SECRET_ACCESS_KEY
region: us-east-1
mfa_arn: arn:aws:iam::123456789012:mfa/username # MFA lives here

prod:
kind: aws/assume-role
via:
identity: base
principal:
assume_role: arn:aws:iam::999999999999:role/ProductionAdmin

The same rule applies when the upstream identity is aws/permission-set instead of aws/user -- MFA (if the IdP requires it) happens during the SSO browser login, not as a separate config field.

Translating credential_process

A profile with credential_process runs an external command that prints AWS credentials. Atmos Auth runs the same command with the aws/credential-process identity kind, uses the credentials as returned (no STS call, no MFA prompt from Atmos), and caches them while at least 15 minutes remain before they expire. Atmos runs the command through a shell (like the AWS SDK for Go), while the AWS CLI splits it into arguments, so pipes and environment variable expansion that fail in the AWS CLI work in Atmos. The helper must finish within 1 minute.

# ~/.aws/config
[profile corp]
credential_process = okta-aws-cli web --format=process-credentials --org-domain=example.okta.com --oidc-client-id=0oa1example --aws-iam-idp=arn:aws:iam::111111111111:saml-provider/okta --aws-iam-role=arn:aws:iam::111111111111:role/Admin
region = us-east-1
# atmos.yaml
auth:
identities:
corp:
kind: aws/credential-process
credentials:
credential_process: >-
okta-aws-cli web --format=process-credentials --org-domain=example.okta.com --oidc-client-id=0oa1example --aws-iam-idp=arn:aws:iam::111111111111:saml-provider/okta --aws-iam-role=arn:aws:iam::111111111111:role/Admin
region: us-east-1

Chain aws/assume-role from it with via.identity: corp when the profile was a base session for other roles. If the process only wraps SSO or role assumption (a Leapp, Granted, or saml2aws shim), prefer the native kind it was wrapping -- see the SSO and role-chaining sections above, or from-granted.md / from-aws2saml.md.

To keep aws --profile=<name> working from any directory after migrating, point a profile at Atmos:

[profile app-sandbox-1]
credential_process = atmos --chdir=/path/to/infrastructure aws credential-process --identity=app-sandbox-1

On an older Atmos version without aws/credential-process, use an aws/ambient identity with AWS_PROFILE set to the helper-backed profile so the AWS SDK default credential chain runs the helper. See atmos-auth for recipes and troubleshooting.

Beyond Plain AWS CLI Config: Native Integrations

Plain ~/.aws/config has no notion of these -- worth surfacing during a migration conversation since they often replace scripts the user built by hand.

  • ECR login, automated. Instead of scripting aws ecr get-login-password | docker login --username AWS --password-stdin, wire an aws/ecr integration to an identity and Atmos writes ~/.docker/config.json automatically on atmos auth login:
    auth:
    integrations:
    ecr:
    kind: aws/ecr
    via:
    identity: dev-admin
    spec:
    registry:
    account_id: "123456789012"
    region: us-east-2
  • EKS kubeconfig, automated. Wire an aws/eks integration (requires a linked identity plus spec.cluster.name/spec.cluster.region) and atmos auth login auto-provisions the kubeconfig entry, configuring atmos aws eks token as a kubectl exec-credential plugin using the active identity -- no more manually running aws eks update-kubeconfig and hoping the right profile/role is active:
    auth:
    integrations:
    dev/eks:
    kind: aws/eks
    via:
    identity: dev-admin
    spec:
    cluster:
    name: dev-cluster
    region: us-east-2
  • aws/assume-root -- a capability plain profiles can't express at all. AWS's newer centralized-root-access feature (temporary, task-scoped root credentials via AWS Organizations) has no representation in classic ~/.aws/config -- there's no role_arn for "become root for 15 minutes to run one IAM audit task." Atmos supports it as a first-class identity kind:
    auth:
    identities:
    root-audit:
    kind: aws/assume-root
    via:
    identity: admin-base
    principal:
    target_principal: "123456789012"
    task_policy_arn: arn:aws:iam::aws:policy/root-task/IAMAuditRootUserCredentials
    duration: 15m # AWS-enforced hard max
    Only surface this if the user specifically needs AWS Organizations centralized root access tasks (credential recovery, root password creation/deletion, S3/SQS policy unlocking) -- it's niche, not a general migration target, and requires AWS Organizations centralized root access to be enabled.

Common Gotchas

  • principal.name must be the exact permission set name from IAM Identity Center, not a display name or alias the user made up locally.
  • aws/assume-role has no mfa_arn field. MFA always lives on the upstream aws/user (or is handled transparently during SSO login) -- putting mfa_arn on an aws/assume-role identity is silently ignored.
  • One provider per SSO start URL, not one per profile. Users with a dozen SSO profiles need one aws/iam-identity-center provider and a dozen aws/permission-set identities, not a dozen providers.
  • Translate credential_process explicitly. Atmos does not read it from a legacy ~/.aws/config on its own. Move the command into an aws/credential-process identity.
  • Static keys in atmos.yaml are a downgrade from atmos auth user configure. Steer users away from !env-referenced keys committed to a shared repo when the keyring-backed command achieves the same result more safely.
  • Static keys aren't even required anymore. An aws/user identity with no credentials: block at all falls back to the browser OAuth2 PKCE flow automatically -- don't default to migrating every static-key profile as static keys in Atmos too; ask whether the user actually needs long-lived non-interactive credentials before reaching for credentials: or atmos auth user configure.

Related Skills

Atmos Auth configuration for the full provider/identity schema and atmos auth commands for the command reference; Secrets Configuration if the user wants to store static credentials as a declared secret rather than relying on the keyring.