Centralizing Developer Cloud Access
This guide shows you how to define your organization's cloud authentication configuration once, in
a private central repository, and have it "just work" for every developer who clones any project repo
that imports it — no manually copy-pasted ~/.aws/config profile blocks, no per-developer setup docs to
keep in sync, no risk of someone hand-typing the wrong account ID.
The pattern is the same regardless of cloud — Atmos supports AWS, Azure, and GCP as first-class auth providers. The example below shows all three side by side.
If you've only used Atmos in Terraform repositories, using it here may be unexpected. But Atmos isn't a Terraform wrapper—it's a general-purpose task runner and configuration platform with best-in-class support for Terraform. We recommend using it in every repository to give teams one consistent way to manage commands, toolchains, authentication, secrets, and workflows, whether that repository contains infrastructure code or not.
The Problem
A common way teams distribute AWS SSO access today is a [profile] block passed around in Slack or a
wiki page:
[profile corp-nonprod]
sso_start_url = https://d-xxxxxxxxxx.awsapps.com/start
sso_region = us-east-1
sso_account_id = 111111111111
sso_role_name = ReadOnlyAccess
This works, but it doesn't scale or govern well:
- Every developer's
~/.aws/configis a hand-rolled, ungoverned copy — nothing catches copy-paste mistakes (and it costs your team time supporting it). - Every new team member goes through the same onboarding song-and-dance, usually capped off with a Slack message asking how to configure their AWS credentials.
- Making any changes requires coordinating the updates across the entire team (unsustainable)
- There's no single source of truth to audit or version-control.
- If your organization is multi-cloud, this ad hoc pattern doesn't generalize — AWS profiles,
az loginconventions, andgcloudconfigurations all look different, so you end up maintaining a separate, differently-shaped solution per cloud instead of one consistent pattern.
The Solution: One Central, Private Config Repo
Atmos lets you define your auth: configuration once in a private repository and import: it from the
atmos.yaml of every project repo. Developers only need to clone a project and run atmos auth login —
they never see or manage the SSO block themselves.
1. Create the central config repo
Create a private repository — for example github.com/acme-corp/atmos-config — and organize it by
cloud, then by the group of developers (or team) the file grants access to. A simple starting layout:
atmos-config/
├── aws/
│ └── developers/
│ └── auth.yaml
├── azure/
│ └── developers/
│ └── auth.yaml
└── gcp/
└── developers/
└── auth.yaml
The import syntax, private-repo access, and atmos auth workflow are identical across tabs — only the
path (aws/, azure/, or gcp/) and the providers:/identities: block inside auth.yaml change.
Use the path and block for the cloud you're setting up:
- AWS
- Azure
- GCP
# aws/developers/auth.yaml (in the private acme-corp/atmos-config repo)
auth:
providers:
acme-sso:
kind: aws/iam-identity-center
region: us-east-1
start_url: https://d-xxxxxxxxxx.awsapps.com/start
identities:
nonprod:
kind: aws/permission-set
default: true # makes this the default identity
via:
provider: acme-sso
principal:
name: ReadOnlyAccess # the SSO permission set / role name
account:
id: "111111111111" # quote it — it's a string, not a number
# azure/developers/auth.yaml (in the private acme-corp/atmos-config repo)
auth:
providers:
azure-cli:
kind: azure/cli
identities:
nonprod:
kind: azure/subscription
default: true
via:
provider: azure-cli
principal:
subscription_id: "00000000-0000-0000-0000-000000000000"
location: eastus
# gcp/developers/auth.yaml (in the private acme-corp/atmos-config repo)
auth:
providers:
gcp-adc:
kind: gcp/adc
identities:
nonprod:
kind: gcp/service-account
default: true
via:
provider: gcp-adc
principal:
service_account_email: terraform@acme-nonprod.iam.gserviceaccount.com
project_id: acme-nonprod
Tag releases (e.g. v1.0.0) so downstream repos can pin to a known-good version instead of tracking a
moving branch. A repo that needs more than one cloud isn't limited to a single provider — it can import
multiple provider files side by side (e.g. aws.yaml and azure.yaml).
2. Import it from every project repo
In each project's own atmos.yaml, add a remote import: pointing at that file, pinned to a tag:
# atmos.yaml (in any project repo)
import:
- "git::https://github.com/acme-corp/atmos-config.git//aws/developers/auth.yaml?ref=v1.0.0"
That's the entire integration. Every project that adds this one line inherits the same providers and
identities — add an account or rotate a role name once in the central repo, tag a new release, and bump
the ref across projects (or leave them tracking a branch if you'd rather changes roll out immediately).
By default this import is re-resolved (a fresh shallow clone) on every single atmos command in the
project, not just auth commands — so every command depends on network reachability to the central repo.
Set imports: { ttl: ... } once in atmos.yaml to cache the clone across commands instead (see
Caching Remote Imports).
Import only what a project needs
A project doesn't have to pull in the entire org's auth: config just to get one identity. Extend the
same <cloud>/<team>/auth.yaml layout with more teams as they need their own identities:
atmos-config/
└── aws/
├── developers/auth.yaml # broad, mostly-read access — imported by most repos
├── platform/auth.yaml # platform team's more privileged identities
└── data/auth.yaml # data team's identities
A platform-team repo then imports only its own file, not the whole org's config:
# atmos.yaml (in a platform-team project repo)
import:
- "git::https://github.com/acme-corp/atmos-config.git//aws/platform/auth.yaml?ref=v1.0.0"
This composes the same way whether the split is by team, by environment (nonprod/auth.yaml/
prod/auth.yaml), or by cloud provider — you're not limited to one monolithic file imported everywhere.
3. Private repo access — no token setup needed
Because atmos-config is private, fetching it needs authentication. This git:: import is cloned by
Git itself under the hood, and Atmos resolves a token for that clone in this order:
ATMOS_PRO_GITHUB_TOKENenvironment variable (set automatically if you use Atmos Pro's GitHub integration)ATMOS_GITHUB_TOKENenvironment variableGITHUB_TOKENenvironment variablegh auth token, if the GitHub CLI is installed and the developer has already rungh auth login
For most developers, step 4 means there's nothing to configure at all — gh auth login is already a
common onboarding step, and Atmos reuses that session automatically for this import too.
Developer Workflow
With the import wired up, a new developer's entire setup is:
git clone git@github.com:acme-corp/some-project.git
cd some-project
atmos auth login # auto-uses the default identity; pass a bare --identity to force a selector
Then, to actually use the credentials:
# Option A: isolated subshell — credential env vars are scoped to this child
# shell and go away when it exits (the underlying credential files on disk
# aren't revoked; they just expire on their own normal schedule)
atmos auth shell
# Option B: run one command with credentials injected
atmos auth exec -- aws s3 ls
# Option C: make credentials ambient in the current shell
eval $(atmos auth env)
atmos auth env is safe to add to ~/.zshrc/~/.bashrc unconditionally — it only prints (and, via
eval, exports) environment variables from cached credentials; it never triggers a login prompt on its
own. A new shell starts in $HOME, though, not inside your project checkout, so Atmos won't find the
atmos.yaml (and its import) unless you point it there explicitly with --chdir:
eval $(atmos auth env --chdir=/path/to/your/checkout)
What's Actually Zero-Setup (and What's Optional)
Install Atmos once; use it on every repo in the organization. For a private central repo, that also means
being authenticated with GitHub — most developers already are, via gh auth login (see
step 3 above for the exact resolution order). From there:
clone a repo, run atmos auth login, then atmos auth shell or atmos auth exec — no profile block to
copy, no account ID to transcribe.
The one thing that isn't automatic is ambient parity with a manually managed [profile] block — a
bare aws s3 ls, or an IDE extension finding credentials, with no atmos auth wrapper involved at all.
Atmos deliberately doesn't write to ~/.aws/credentials/~/.aws/config; credentials go to Atmos-managed
files instead, exposed only to processes that inherit AWS_SHARED_CREDENTIALS_FILE/AWS_CONFIG_FILE/
AWS_PROFILE. This is a security default, not an oversight — it avoids silently overwriting a
developer's own credentials, and it means a tool (or an AI agent) isn't automatically signed in to AWS
just by existing in your shell; it only gets credentials if something explicitly runs
atmos auth exec/shell or has eval'd atmos auth env.
Want that ambient parity anyway? Add eval $(atmos auth env --chdir=...) to your shell profile (see
Developer Workflow) — optional, and most repo-scoped work doesn't need it.
Either way, updates are centrally managed rather than re-broadcast: add an account or rotate a role once
in the central repo and tag a release. Projects tracking a branch pick up the change immediately; projects
pinned to a tag (the pattern this guide recommends) pick it up the next time they bump their ref — still
a one-line change in one file, not a wiki post and a round of developers hand-editing ~/.aws/config.
Troubleshooting
atmos auth login doesn't find the identity — a failed import is non-fatal by design: a typo'd ref,
an unreachable repo, or a private repo Git can't authenticate to all produce an empty auth: section and
exit 0, not an error. Run atmos auth list first to confirm the import actually resolved anything. If
it's empty, look for a WARN failed to resolve import line in the command's output — Atmos logs it at
the default log level, so it shows up without setting ATMOS_LOGS_LEVEL. That line names the real reason
(bad ref, 403, DNS failure, etc.).
That warning shows an authentication error — confirm gh auth status shows an active session (or
that ATMOS_PRO_GITHUB_TOKEN/ATMOS_GITHUB_TOKEN/GITHUB_TOKEN is set — see
step 3 for the full resolution order), and that the
account has read access to the central config repo.
AWS CLI/Terraform outside of Atmos can't find credentials — you're missing eval $(atmos auth env)
in your shell profile, or the tool was launched before you ran it in that shell session.
See Also
- Imports — remote import syntax and pinning
- Auth Providers — full provider configuration reference
atmos authcommands — login, shell, exec, env, whoami