Skip to content

The Auth Model

Keel uses IAM role assumption with short-lived STS credentials, guarded by MFA. This page explains what keel auth setup builds, what lives on disk, and precisely what a stolen credential can and cannot do.

Access levels

Keel enforces three access levels via IAM roles with least-privilege policies:

LevelIAM RolePermissions
Adminkeel-adminProvision, destroy, manage team, require MFA. Not IAM bootstrap — see below
Developerkeel-developerDeploy, exec, scale, config vars, logs, CodeBuild
Viewerkeel-viewerRead-only: status, logs, dashboard, apps list

Commands check access levels at the start of execution: keel up and keel destroy require Admin, keel deploy requires Developer, keel logs works for all roles including Viewer.

One-time setup

An account admin runs keel auth setup once. It is a guided six-step flow, not a single action:

  1. Take AWS credentials that can create IAM users, roles, and policies — held in memory for the run and never written to disk
  2. Create the three roles (keel-admin, keel-developer, keel-viewer) with least-privilege policies, the per-role assume policies, and the team table
  3. Create an IAM user for you under /keel/ that can assume keel-admin and nothing else
  4. Enrol an MFA device for it — scan a QR code, or type the printed secret
  5. Verify the new identity can assume keel-admin, then switch Keel over to it
  6. Require MFA to assume any Keel role

Steps 3–5 are the part worth understanding: the credentials you start with can administer your whole account; the ones Keel keeps afterwards can do exactly one thing, and only with a code from your phone. Setup does this itself rather than leaving it as a follow-up command, because a follow-up command is one that gets skipped — and skipping it would leave you running Keel on unrestricted credentials forever.

Keep your original AWS credentials safe

They are the way back in if you lose your MFA device — the first admin has nobody else who can reset it for them.

bash
keel auth setup             # admin, one time; needs a terminal for the MFA step
keel auth setup --dry-run   # preview every policy document without touching AWS
keel auth login             # start a session — prompts for a one-time code
keel auth whoami            # check identity and access level

Re-run keel auth setup after upgrading Keel. It publishes new versions of the existing policies rather than recreating them, keeps whatever MFA enforcement is already in place, and resumes rather than restarting — an enrolled device is kept. It needs the elevated credentials again, because keel-admin deliberately cannot rewrite Keel's own policies.

Credential handling

Keel stores two credentials per app+environment in ~/.keel/contexts/<app>/:

FileWhat it isLifetime
base_credentialsA long-lived IAM user access key, stored in plaintext at 0600Until rotated or the user is revoked
credentialsAn STS session from assuming a Keel role8 hours

The base key is deliberately close to useless on its own. The only actions its policy grants are sts:AssumeRole on exactly one keel-* role and reading its own MFA device — and once MFA is enforced, that assume also needs a one-time code. A copy of the file, wherever it ends up, cannot reach your infrastructure.

  • Sessions are not refreshed automatically. When one expires, run keel auth login again; every command that needs credentials says so if they have lapsed
  • The MFA secret is generated on the member's machine, shown once, and never transmitted, stored, or written to Keel's debug log
  • keel auth logout clears the session; --purge also removes the base key
  • OpenTofu receives credentials via environment variables, never written to disk
  • Application containers receive rotating ECS task-role credentials through the AWS SDK credential chain, never an IAM user key
  • Every service has its own runtime IAM role and security group

How access is enforced

LayerRole
IAM assume policy on the member's userThe enforcement point — grants exactly one keel-* role
MFA condition on the role's trust policyMakes the access key insufficient on its own
keel-mfa-enroll-policyHeld only between team add and team activate, never alongside an assume policy
keel-team DynamoDB tableRoster and audit trail (who added whom, when, current status)
Cached STS credentialsWhat Keel's access check inspects on every privileged command

Because the assume policy allows a single role, a member cannot escalate by editing their local config or passing a different --role. Admins can only ever attach one of the three Keel assume policies, or the MFA enrollment policy, to a Keel-managed user — the keel-admin policy constrains iam:AttachUserPolicy with an iam:PolicyARN condition, so keel auth team cannot be used to grant arbitrary permissions.

keel-admin also cannot rewrite Keel's own IAM. It holds read-only access over role/keel-* and policy/keel-* — since policy/keel-* includes keel-admin-policy itself, write access there would let an admin session publish a new version of its own policy granting everything. Changing those documents is a bootstrap act, done by keel auth setup with elevated credentials. The one exception is iam:UpdateAssumeRolePolicy, which keel auth mfa enforce needs; it cannot grant permissions, only change who may assume.

What this does not protect against

MFA makes an exfiltrated key useless — a copy in a backup, a chat message, or terminal scrollback. It does not protect a machine that is already compromised: something running as you can wait for a legitimate login and take the session from credentials, which is plaintext on disk for the life of the session.

Being clear about the limit of the admin boundary too: keel-admin can still create the IAM roles your infrastructure uses, attach AWS-managed policies to them, and pass them to ECS tasks — so it can run code with permissions Keel never granted directly. That is inherent to a tool that deploys infrastructure. What is closed is the direct path from an admin session to account administrator.

Keel — the AWS CLI you've always wanted.