Badges only render publicly once this repo is public (or you're viewing it while logged into GitHub) — private-repo badges need auth to display for outside visitors. The Scorecard badge specifically only populates after
scorecard.ymlhas run at least once against the public repo. No coverage badge yet; wiring one up needs a Codecov (or similar) account and token, tracked as a follow-up.
Ephemeral AWS multi-account credential manager, built on IAM Identity Center (SSO).
No long-lived access keys. No static credentials sitting in ~/.aws/credentials.
Log in once via your org's Identity Center portal, then run commands or open a
shell against any account/role you're granted — with short-lived, auto-expiring
credentials and a local audit trail.
Most teams either hand out long-lived IAM user keys (bad) or make people
click through the AWS SSO web console and copy-paste temporary credentials
by hand every hour (annoying). orgctl automates the second option: it
drives the same Identity Center device-authorization flow the console uses,
caches the resulting short-lived credentials locally, and exposes a simple
CLI (exec, shell) for using them.
- SSO-only. Uses the AWS SSO OIDC device-authorization grant — the same
flow the
aws sso loginCLI command uses. There is no code path that accepts or stores a long-lived access key. - Account/role registry (
orgs.yaml) — give your accounts human-friendly aliases instead of memorizing 12-digit IDs. orgctl exec -a <account> -r <role> -- <command>— run a one-off AWS CLI (or any) command with the right credentials exported into that process's environment only.orgctl shell -a <account> -r <role>— drop into a subshell with credentials exported, prompt tagged with the active account/role so you always know where you are.- Local guardrails (
guardrails.yaml) — optional deny-patterns and "protected account" list to stop an obviously wrong command (or a fat-fingered wrong terminal tab) before it reaches AWS. This is a client-side speed bump, not a replacement for IAM permission boundaries or SCPs. - Local audit log (
~/.orgctl/audit.log) — everyexec/shellinvocation is appended as a JSON line: who, when, which account/role, what command. Never uploaded anywhere; it's for your own review. - Nothing persisted insecurely. Cached tokens/credentials live under
~/.orgctl/cachewith owner-only permissions and their own expiry check on every read. - Native
credential_processsupport (orgctl creds-process) — wire it into~/.aws/configandaws/terraform/boto3 work with plain--profile, no wrapper needed. - Configurable session cap (
max_session_hours) — force re-auth sooner than the SSO token's own expiry, independent of what your org issues. - Advisory IAM policy pre-check (
orgctl check-policy,--check-actiononexec) — ask the IAM policy simulator whether a role's identity-based policies allow an action before you rely on it. Does not evaluate SCPs or resource policies (AWS exposes no simulator API for those). - Shell completion —
orgctl completion bash|zsh|fish. orgctl whoami— quick STS identity check for an account/role.- CI on every push/PR — ruff lint + format check, mypy, pytest across Python 3.11/3.12.
- Typed — ships a
py.typedmarker; mypy-checked in CI. orgctl sync-aws-config— writes acredential_processprofile into~/.aws/configfor every account (or every account/role with--all-roles) in your registry. Backs up the existing file first and never touches profiles it didn't create.- OS keychain for SSO tokens — with the
keyringextra installed and a working backend (macOS Keychain, Windows Credential Manager, Secret Service/KWallet), the SSO token itself is stored there instead of a plain file. Falls back to the existing 0600-file cache automatically when no backend is available. --jsonoutput onaccounts,list-remote, andaudit-log— for piping intojqor other tooling.orgctl export-env— printsexport AWS_...(or--powershell$env:...) lines foreval "$(orgctl export-env -a prod -r admin)"in your current shell, as an alternative toorgctl shell's subshell — useful in scripts and CI steps.- Session-expiry heads-up —
orgctl shellprints how long the credentials have left, and a warning if it's under 15 minutes.
git clone https://github.com/DustyStudy/aws-orgctl.git
cd aws-orgctl
python3 -m pip install -e .If you just want the orgctl command available globally without managing a
virtualenv yourself:
pipx install git+https://github.com/DustyStudy/aws-orgctl.gitA formula isn't published yet — once there's a tagged release, a
Formula/orgctl.rb pulling from the release tarball can be added to a
personal tap (brew tap DustyStudy/aws-orgctl && brew install orgctl). Tracked as a
follow-up; pipx is the easiest path in the meantime.
python3 -m pip install -e ".[keyring]"With this installed and a working backend (macOS Keychain, Windows
Credential Manager, Secret Service/KWallet on Linux), the SSO token is
stored there instead of a plain file under ~/.orgctl/cache. If no backend
is available (common on headless Linux), orgctl automatically falls back
to the existing file-based cache — nothing else changes.
orgctl completion bash # or zsh / fishprints the line to add to your shell profile (built on Click's native completion support — no extra dependency).
# 1. Create your local account registry from the example
orgctl init
$EDITOR ~/.orgctl/orgs.yaml # add your SSO start URL + account IDs/roles
# 2. Sanity-check everything
orgctl doctor
# 3. Log in (opens your browser for Identity Center approval)
orgctl login
# 4. See what's in your registry
orgctl accounts
# 5. See what Identity Center actually grants you right now
orgctl list-remote
# 6. Run something
orgctl exec -a prod -r read-only -- aws s3 ls
# 7. Or work interactively
orgctl shell -a prod -r read-only# Use as a native AWS credential provider — no `orgctl exec` wrapper needed.
# Add to ~/.aws/config:
# [profile prod]
# credential_process = orgctl creds-process --account prod --role read-only
orgctl creds-process -a prod -r read-only
# Quick "who am I right now" check for an account/role
orgctl whoami -a prod -r read-only
# Filter your registry by tag
orgctl accounts --tag security
# Attach a justification to a command or session (recorded in the local
# audit log only — see note below on why this isn't an AWS-side session tag)
orgctl exec -a prod -r admin --reason "JIRA-1234" -- terraform apply
orgctl shell -a prod -r admin --reason "JIRA-1234"
# Advisory pre-check: would this role's identity-based policies allow an
# action, before you actually run something relying on it
orgctl exec -a prod -r deploy --check-action s3:DeleteObject --check-resource "arn:aws:s3:::my-bucket/*" -- ./destroy.sh
orgctl check-policy -a prod -r deploy --action s3:DeleteObject --resource "arn:aws:s3:::my-bucket/*"
# Push recent audit-log entries to CloudWatch Logs (requires
# cloudwatch_log_group set in orgs.yaml and logs:PutLogEvents on whatever
# credentials are active in this shell)
orgctl audit-log --push-cloudwatch
# One-time setup: write a credential_process profile into ~/.aws/config
# for every account (one per account by default; --all-roles for one
# profile per account/role instead). Then just use --profile like normal.
orgctl sync-aws-config
aws --profile prod s3 ls
# Get credentials into your CURRENT shell instead of spawning a subshell —
# handy in scripts/CI steps that need to keep running in the same process
eval "$(orgctl export-env -a prod -r admin)"
# PowerShell:
orgctl export-env -a prod -r admin --powershell | Invoke-Expression
# JSON output for scripting
orgctl accounts --json | jq '.[] | .alias'
orgctl audit-log --json -n 50 | jq '.[] | select(.result == "blocked")'On --reason: recorded in your local audit log only. AWS SSO's
GetRoleCredentials API (what this tool uses to fetch short-lived
credentials) has no session-tagging parameter — real STS session tags
require a direct sts:AssumeRole call against a role ARN instead. So this
is a local justification trail, not an AWS-side session tag.
On --check-action/check-policy: calls iam:SimulatePrincipalPolicy
against the role's identity-based policies only. AWS exposes no API that
simulates Service Control Policies or resource-based policies, so a passing
result here is necessary but not sufficient — a real SCP can still deny the
call. Treat it as a fast local sanity check, not a guarantee.
On sync-aws-config: each section it writes is tagged internally so a
later run can tell "orgctl created this" apart from "this profile name
already existed." If a profile name from your registry collides with a
section you already had (from aws configure, hand-editing, etc.), that
section is left completely alone and reported back as a conflict — nothing
about it is overwritten. A .bak copy of ~/.aws/config is made before
any real write. Re-run it any time your orgs.yaml changes.
See config/orgs.example.yaml. No secrets live
here — just your Identity Center start URL/region and a map of aliases to
account IDs and role names. Two optional top-level fields:
max_session_hours(default 8) — force a fresh browser login after this many hours, independent of the SSO token's own server-side expiry.cloudwatch_log_group— set this to enableorgctl audit-log --push-cloudwatch. Each push resends the lastnlocal entries with no "since last push" tracking, so calling it repeatedly with overlapping history produces duplicate CloudWatch events — push right after each command, or dedupe downstream, if that matters for your use case.
See config/guardrails.example.yaml. Lets
you mark accounts as protected (block all ad-hoc commands) and add
deny/require-confirmation glob patterns on top of the built-in defaults
(blocks things like organizations leave-organization, close-account,
recursive s3 rm, etc.).
- Credentials are always short-lived (from AWS SSO's
GetRoleCredentials), scoped to exactly the account/role requested, and expire on their own. - Nothing is ever written to a shell's exported
AWS_*variables outside the child process spawned byexec/shell— your parent shell's environment is untouched. orgctl logoutclears every cached token/credential immediately.- Guardrails and the audit log are local-only conveniences, not a substitute for IAM permission boundaries, SCPs, or CloudTrail.
See docs/THREAT_MODEL.md for the full breakdown —
assets, trust boundaries, per-scenario mitigations and residual risk, and
what's explicitly out of scope.
python3 -m pip install -e ".[dev]"
ruff check src tests
ruff format src tests
mypy src
pytest -v --cov=orgctl --cov-report=term-missingSee CONTRIBUTING.md for the full workflow (including
optional pre-commit hooks) and SECURITY.md for
the vulnerability-reporting process and which areas get the most scrutiny.
MIT — see LICENSE.