Configure AWS SSO for the CLI
How to get aws and Terraform working against our AWS accounts through AWS SSO
(IAM Identity Center). This replaces the deprecated alma-iam users and their
long-lived access keys.
Prerequisites: AWS CLI v2 (aws --version), and membership in an
IAM AWS-SSO Marketplaces-Mobility-* group. Terraform is not required — step 4 only uses
it as an example of a tool that reads AWS_PROFILE. Don’t have the group yet? Start from
the access guide in Confluence (MONE). It covers who to ask and how long it takes. This
page is only the mechanics.
1. Generate your ~/.aws/config
Section titled “1. Generate your ~/.aws/config”The generator lives in this site’s own repo, so clone it first. Nothing is installed — the script is Python 3.8+ standard library only.
git clone https://github.com/alma-mobility-marketplaces/docs.ajomark.dev.gitcd docs.ajomark.dev
./tools/aws-sso/generate-aws-config.py --stdout # see what you would get./tools/aws-sso/generate-aws-config.py # write it into ~/.aws/configThe HTTPS URL asks for GitHub credentials. If your GitHub SSH key is set up, clone
git@github.com:alma-mobility-marketplaces/docs.ajomark.dev.git instead.
--stdout prints and changes nothing, so run it first if you want to look before you
let anything near your config. Don’t want a clone at all? Skip to the copy-paste
alternative below.
The write step produces one profile per account and role, named <role>@<account>:
# >>> alma-mobility AWS SSO profiles (generated) >>># Do not edit inside this block - regenerate with tools/aws-sso/generate-aws-config.py
[sso-session alma-sso]sso_start_url = https://alma-sso.awsapps.com/startsso_region = eu-west-1sso_registration_scopes = sso:account:access
[profile readonly@ajo-mark-dev]sso_session = alma-ssosso_account_id = 226023431967sso_role_name = ReadOnlyregion = eu-west-1
# ... one more profile per account and role ...# <<< alma-mobility AWS SSO profiles (generated) <<<Those markers matter: keep your own profiles outside the block and they survive
regeneration. What it writes
has the detail. If you already had a ~/.aws/config, the previous version is kept as
~/.aws/config.bak.
Two flags are worth knowing while you are here: --roles ReadOnly gives you read-only
profiles only, and --environment nonprod leaves the prod accounts out. Everything the
script can do is in
The AWS SSO config generator.
Prefer to copy-paste? tools/aws-sso/aws-config
is the same output, committed. Paste the whole file into ~/.aws/config, marker
comments included — keeping them lets the generator take over later without duplicating
everything.
Account IDs come from
tools/aws-sso/accounts.json, which is where you add or remove an account — never in your local config.
2. Log in
Section titled “2. Log in”aws sso login --sso-session alma-ssoA browser tab opens and asks you to Allow botocore-client-alma-sso to access your
data. That is the AWS CLI itself: botocore is its SDK layer, and alma-sso is the
session name from step 1, so the prompt is naming your own CLI rather than a third
party. “Applications and AWS accounts” is the sso:account:access scope your generated
config asks for.
Choose Allow access. When the tab reports that your credentials were shared successfully, the CLI has its token and you can close it.
One login covers every profile in the session — you do not log in per account.
The role credentials the CLI hands to each command last about an hour, and it renews
them from the cached access token for you, so expiry is not something you track. The
cached token itself lives as long as the Identity Center session. When that session ends,
commands start failing with ExpiredToken and you run the same login command again. How long that session lasts is an Identity Center setting, not something
you configure locally.
3. Verify
Section titled “3. Verify”aws sts get-caller-identity --profile readonly@ajo-mark-devYour own name should appear in the ARN:
{ "UserId": "AROAEXAMPLEPRINCIPAL:your.name@almamedia.fi", "Account": "226023431967", "Arn": "arn:aws:sts::226023431967:assumed-role/AWSReservedSSO_ReadOnly_<id>/your.name@almamedia.fi"}Two things to look for: assumed-role/AWSReservedSSO_…, which means the credentials came
from SSO rather than from a static key, and your own address at the end. Note that the
SSO identity uses @almamedia.fi even if your mail is @almamedia.net.
4. Use it
Section titled “4. Use it”# per commandaws s3 ls --profile readonly@ajo-mark-dev
# or for a shell, Terraform, CDK, or any AWS SDKexport AWS_PROFILE=devadmin@ajo-mark-devterraform planTwo habits worth having:
- Default to
readonly@. Switch todevadmin@only when you are changing something. Having both profiles is what makes that easy. One read-only task needsdevadmin@anyway: ReadOnly has nossm:StartSessionin any account, so port-forwarding to a database cannot start a session. - In prod, most of us only have
readonly@— and it covers logs, metrics and nearly all debugging. Prod write access lives in a separate, deliberately small group.
Make one profile the default
Section titled “Make one profile the default”A command with no --profile and no AWS_PROFILE uses the [default] profile. Give it
one, so that case is harmless rather than a surprise:
./tools/aws-sso/generate-aws-config.py --default-profile readonly@ajo-mark-devThat writes a [default] profile with those settings inside the managed block. Keep the
flag on later runs — regenerating without it takes the [default] away again.
You lose nothing by setting one, because the order of precedence is --profile, then
AWS_PROFILE, then [default]. Overriding for a single command still works:
AWS_PROFILE=devadmin@ajo-mark-dev terraform planreadonly@ajo-mark-dev is the right choice for a default: the worst a forgotten
--profile can then do is read from dev.
Exporting AWS_PROFILE from your shell startup file does the same job in one line, and
without repeating the account settings. The tradeoff is reach — it only applies to
processes started from that shell, while ~/.aws/config is also what IDEs and other
tools read.
5. Retire your old credentials
Section titled “5. Retire your old credentials”SSO replaces the old two-hop setup entirely, so nothing in it needs to survive — see what SSO replaced if the names below are unfamiliar.
Delete the access key in IAM first. Sign in at
https://alma-iam.signin.aws.amazon.com/console/, then IAM → Users → your
firstname.lastname user → Security credentials, and delete the access key. Deleting
your local copy only hides the key; until you remove it here it still works from
anywhere, for anyone who has it.
Then clear the local entries in ~/.aws/credentials:
- The
alma-iamkey is usually the[default]block —aws_access_key_id,aws_secret_access_key, and an MFA device ARN pointing at142020163350. - Any block with an
aws_session_tokenholds temporary credentials, typically anaws-mfaleftover. They expire within hours, so an old one grants nothing — theget-caller-identitycheck below returnsExpiredTokenand you can delete it. - If the file ends up empty, delete it.
Check what a block is before you delete it, rather than assuming:
aws sts get-caller-identity --profile <block-name>An account that is not one of the twelve is not part of this migration, and SSO will not give you access to it. Find out what it is for before removing the only credential you have for it.
A leftover [default] in ~/.aws/credentials is a classic source of “why am I in the
wrong account”, because it answers for every command that names no profile. With AWS CLI
v2, a [default] profile in ~/.aws/config that uses sso_session does take precedence
over static keys in ~/.aws/credentials — but if you have no [default] in your config,
those static keys are simply what gets used.
If a repo tells you to use access keys
Section titled “If a repo tells you to use access keys”Some repos still carry pre-SSO setup instructions, and so does Confluence. Ignore them: what SSO replaced describes the old way and why none of it applies.
The clearest example in a repo is infra. Its
README.md asks you to fill aws_access_key and aws_secret_key into
deployment/terraform.tfvars, and pins AWS CLI 1.x. Ignore those instructions. We
no longer issue static access keys. The [sso-session] block this page uses, and
aws sso login --sso-session, both require AWS CLI v2.
What to do instead when you work in one of those repos:
aws sso login --sso-session alma-ssoexport AWS_PROFILE=devadmin@<target-account>Terraform, the AWS SDKs and the bin/ helper scripts (deploy-terraform, param,
ecs-run-task) all read AWS_PROFILE, so nothing else needs changing. Leave the two
key lines out of your local terraform.tfvars. If the file holds other variables, keep
it and omit just those two. Don’t commit a modified terraform.tfvars — it is
gitignored for a reason.
For unattended builds, use the per-account GitHub OIDC role rather than any personal profile. CI must not depend on a human’s SSO session.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Cause / fix |
|---|---|
Error loading SSO Token, ExpiredToken |
Session expired: aws sso login --sso-session alma-sso |
The config profile (...) could not be found |
Typo, or ~/.aws/config is missing the [sso-session alma-sso] block. Re-run the generator. |
| An account is missing from the portal | Refresh https://alma-sso.awsapps.com/start/#/?tab=accounts. Still missing → you are not a member of the group yet. Being an owner of a group grants no access on its own. |
| Just got added, still nothing | Group membership sync takes 1–3 hours. |
AccessDenied with a devadmin@ prod profile |
Expected unless you are in the prod write group. |
| Resources “not found” that clearly exist | Wrong region — every profile should be eu-west-1. |
sso-session not recognised, or aws sso login --sso-session fails |
AWS CLI v1. The [sso-session] block needs v2 — install it. |
found the start marker but not the end marker |
A previous edit truncated the generated block in ~/.aws/config. Delete the partial block and re-run. |
A command with no --profile lands in the wrong account |
Check echo $AWS_PROFILE first — an export left over from an earlier task overrides [default]. Otherwise ~/.aws/credentials still has a [default] with static keys and your config has no [default] at all. See step 5 and Make one profile the default. |
--default-profile '...' is not one of the profiles being written |
Typo in the profile name, or --roles / --environment filtered that account out of this run. The error lists the valid names. |
Related
Section titled “Related”- The AWS SSO config generator — every flag, and what the script does to your files
- Why AWS access is split into four groups — the reasoning
- Access requests, group owners and the current owner list — Confluence space MONE
- Alma-wide SSO documentation — https://almamedia.cloud/aws/iam/sso_introduction (requires GitHub login)