Credentials & secrets

Cloud creds without leaking them.

Advanced12 min · lesson 10 of 12

Atlantis runs Terraform, which needs cloud credentials — and centralizing those on the server is a feature (off laptops) and a risk (one place holds them). The right pattern is short-lived, scoped credentials the server obtains at run time, not long-lived keys baked into it: on AWS, run Atlantis on a node/pod with an instance role or IRSA so Terraform assumes a role per run; elsewhere, use workload identity. The server should hold as little durable secret material as possible.

deployment (IRSA example)
# Atlantis pod runs as a ServiceAccount bound to an IAM role via IRSA
# Terraform then assumes per-environment roles from that base identity
serviceAccountName: atlantis
# provider "aws" { assume_role { role_arn = "arn:aws:iam::...:role/atlantis-prod" } }
# no static AWS keys stored on the server

Secrets in variables and state

Two more secret surfaces: the Terraform variables Atlantis passes (keep secret vars out of the repo — pull them from a secret manager at run time, and mark them sensitive), and the state Atlantis writes (which can contain secrets — lock down and encrypt the backend, as the Terraform/Terragrunt courses cover). Also protect the VCS token Atlantis uses and the webhook secret; both are credentials that grant control over the workflow.

workflow step
plan:
steps:
- env:
name: TF_VAR_db_password
command: 'vault kv get -field=password secret/prod/db' # fetch at run time
- init
- plan
# the secret is fetched per run from Vault, not stored in the repo or the server image
Long-lived cloud keys on the server are the worst-case blast radius
Baking static, broad cloud credentials into the Atlantis server means a single server compromise hands an attacker durable, wide access to your cloud. Use short-lived assumed roles (IRSA/instance role/workload identity) scoped per environment, fetch Terraform secrets at run time from a manager, and protect the VCS/webhook secrets. Minimize what durable secret material the server holds, because it is the highest-value target you run.