AWS Access
AWS account: 696081601609 (region us-east-1).
This doc explains how to authenticate to AWS day-to-day, what each identity is for, and the 2026-09-05 migration that moved us off root credentials.
TL;DR β daily use
aws sso login # opens browser, approve, done. Creds last ~8h.aws sts get-caller-identity# β arn:aws:sts::696081601609:assumed-role/AWSReservedSSO_AdministratorAccess_.../larryYour default profile is IAM Identity Center (SSO). When the CLI says credentials
are expired, run aws sso login again and re-approve in the browser. That is the
only recurring step. Nothing stores a long-lived key on disk.
Access portal (browser console sign-in): https://d-90667c73d1.awsapps.com/start
β username larry + password + MFA. Click the account tile β AdministratorAccess.
The three ways to authenticate
| Identity | Use it for | How | Credential type |
|---|---|---|---|
IAM Identity Center (SSO) β user larry | Everything day-to-day (CLI + console) | aws sso login / access portal | Temporary (~8h), MFA-gated |
Root user β [email protected] | ~Never. Only root-only account tasks (see below) | Console sign-in as βRoot userβ + MFA | Password + MFA (no access keys) |
cdk-deployer IAM user (accessible profile) | Break-glass only, if SSO is ever unavailable | --profile accessible | Long-lived access key (the only one left) |
CI/CD does not use any of these β GitHub Actions authenticates via OIDC (below).
Local profiles (~/.aws/config / ~/.aws/credentials)
[default]and[profile accessible-sso]β SSO,AdministratorAccess, us-east-1.[profile accessible]βcdk-deployerstatic key (break-glass).[sso-session anglinai]β start URLhttps://d-90667c73d1.awsapps.com/start.
Root-only tasks (the rare reasons to sign in as root)
AdministratorAccess (your SSO role) can do essentially everything. A small set of account-level actions are reserved to root and cannot be granted to any IAM/SSO identity:
- Change the root email, root password, or account name
- Close the AWS account
- Change or cancel the AWS Support plan
- Restore access after an IAM/policy lockout
- Toggle IAM access to billing data
- Enable S3 MFA Delete on a bucket
- Register as a Reserved Instance Marketplace seller; sign up for GovCloud
For these: sign in as root with MFA, do the one task, sign out. Root has no access keys and must never have any.
Note: enabling Identity Center also created an AWS Organization with this account as the management account. There are no Service Control Policies (SCPs) today, so the SSO admin role is effectively equal to root for daily work. If SCPs are ever added they constrain IAM/SSO principals but never the management accountβs root β root remains the ultimate backstop.
CI/CD authentication (GitHub OIDC)
Workflows (deploy-aws.yml, rotate-secrets.yml) assume an IAM role via GitHubβs
OIDC provider β no AWS keys are stored in GitHub.
- OIDC provider:
token.actions.githubusercontent.com(audiencests.amazonaws.com) - Role:
github-actions-deploy, trust scoped torepo:LarryAnglin/theaccessible-platform:*,AdministratorAccessattached - Repo secrets:
AWS_DEPLOY_ROLE_ARN(the role ARN) andAWS_ACCOUNT_ID. Neither is a live credential.
Workflows need permissions: id-token: write and use:
- uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: ${{ secrets.AWS_DEPLOY_ROLE_ARN }} aws-region: us-east-1deploy-aws.yml auto-runs on push to main under a path filter
(workers/**, infra/cdk/**, services/**, select packages/**). Changes to
.github/** alone do not trigger it β dispatch manually to test:
gh workflow run deploy-aws.yml.
What we did β 2026-09-05 migration off root
Before: root had active access keys sitting in the local default CLI profile,
and CI used static AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY repo secrets. A
leaked root key = unscoped, unrevocable total account compromise. We moved to the
AWS-recommended model: root has zero keys, humans use SSO temporary creds, CI uses
OIDC.
- CI β OIDC. Created the GitHub OIDC provider +
github-actions-deployrole; rewireddeploy-aws.ymlandrotate-secrets.ymltorole-to-assume(PR #2679). Verified with a full production deploy, then deleted the staticAWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEYrepo secrets. - Humans β IAM Identity Center (SSO). Enabled Identity Center (us-east-1,
single region), created user
larry+ anAdministratorAccesspermission set (8h sessions) assigned to the account. Repointed the localdefaultprofile to SSO and removed the root key from~/.aws/credentials. Enforced MFA in Identity Center settings. - Deleted the root access keys. Root can hold up to two β deleted both (an old
inactive one was easy to miss). Confirmed
AccountAccessKeysPresent: 0,AccountMFAEnabled: 1. Root login/password/MFA retained as break-glass. - Rotated the break-glass key. Replaced
cdk-deployerβs long-lived key with a fresh one so no credential predates the migration.
End state
- Root: zero access keys, MFA on, console-only.
- Humans: SSO temporary creds, MFA enforced.
- CI: OIDC temporary creds, no stored secrets.
- One long-lived key remains by design:
cdk-deployerbreak-glass.
Troubleshooting
- βThe security token included in the request is expiredβ / SSO errors β
aws sso login(session lapsed; ~8h TTL). - Locked out of SSO β use the break-glass profile:
aws ... --profile accessible. If that key is also lost, sign in as root (console) and re-mint a key or fix Identity Center. - A deploy didnβt fire after merging to
mainβ check the path filter; if the change was outside it, rungh workflow run deploy-aws.ymlmanually. - Rotate the break-glass key (driven from an SSO admin session so it isnβt
self-dependent):
Terminal window export AWS_PROFILE=accessible-ssoaws iam create-access-key --user-name cdk-deployer # put new key in [accessible]# verify: aws sts get-caller-identity --profile accessibleaws iam delete-access-key --user-name cdk-deployer --access-key-id <OLD_ID>