Atlantis Cheat Sheet
Overview
Atlantis is an open-source, self-hosted application that automates Terraform workflows via pull requests. When a pull request modifying Terraform files is opened, Atlantis automatically runs terraform plan and posts the output as a comment. Team members review the plan in the PR, and when approved, use a comment command (atlantis apply) to execute the changes. This workflow ensures all infrastructure changes go through code review and creates an auditable trail of every change.
Atlantis supports GitHub, GitLab, Bitbucket Cloud, and Bitbucket Server with webhook-based integration. It handles multiple Terraform workspaces, custom workflows, parallel planning, locking to prevent concurrent modifications to the same state, and server-side repository configuration for enforcing organizational standards. By running Terraform operations server-side, Atlantis eliminates the need for developers to have cloud credentials locally and ensures consistent execution environments.
Installation
Docker
# Run Atlantis with Docker
docker run -d \
--name atlantis \
-p 4141:4141 \
-e ATLANTIS_GH_USER="atlantis-bot" \
-e ATLANTIS_GH_TOKEN="github-pat-token" \
-e ATLANTIS_GH_WEBHOOK_SECRET="webhook-secret" \
-e ATLANTIS_REPO_ALLOWLIST="github.com/your-org/*" \
-e ATLANTIS_ATLANTIS_URL="https://atlantis.example.com" \
-e AWS_ACCESS_KEY_ID="your-key" \
-e AWS_SECRET_ACCESS_KEY="your-secret" \
ghcr.io/runatlantis/atlantis:latest \
server
# With persistent data
docker run -d \
--name atlantis \
-p 4141:4141 \
-v atlantis-data:/atlantis-data \
-e ATLANTIS_DATA_DIR="/atlantis-data" \
-e ATLANTIS_GH_USER="atlantis-bot" \
-e ATLANTIS_GH_TOKEN="github-pat-token" \
-e ATLANTIS_GH_WEBHOOK_SECRET="webhook-secret" \
-e ATLANTIS_REPO_ALLOWLIST="github.com/your-org/*" \
ghcr.io/runatlantis/atlantis:latest \
server
Kubernetes via Helm
# Add Atlantis Helm repo
helm repo add atlantis https://runatlantis.github.io/helm-charts
helm repo update
# Install Atlantis
helm install atlantis atlantis/atlantis \
--namespace atlantis \
--create-namespace \
--values atlantis-values.yaml
# Minimal values file
cat > atlantis-values.yaml << 'EOF'
orgAllowlist: "github.com/your-org/*"
github:
user: atlantis-bot
token: github-pat-token
secret: webhook-secret
atlantisUrl: https://atlantis.example.com
# AWS credentials
environmentSecrets:
- name: AWS_ACCESS_KEY_ID
secretKeyRef:
name: aws-credentials
key: access-key-id
- name: AWS_SECRET_ACCESS_KEY
secretKeyRef:
name: aws-credentials
key: secret-access-key
ingress:
enabled: true
host: atlantis.example.com
replicaCount: 1
resources:
requests:
memory: 256Mi
cpu: 100m
limits:
memory: 1Gi
cpu: 500m
EOF
Binary Installation
# Download binary
curl -fsSL https://github.com/runatlantis/atlantis/releases/latest/download/atlantis_linux_amd64.zip -o atlantis.zip
unzip atlantis.zip
sudo mv atlantis /usr/local/bin/
# Run server
atlantis server \
--gh-user="atlantis-bot" \
--gh-token="github-pat-token" \
--gh-webhook-secret="webhook-secret" \
--repo-allowlist="github.com/your-org/*" \
--atlantis-url="https://atlantis.example.com" \
--port=4141
Core Commands — PR Comments
Plan and Apply
# In a GitHub/GitLab pull request comment:
# Run plan for all modified projects
atlantis plan
# Plan a specific project
atlantis plan -p myproject
# Plan a specific directory
atlantis plan -d terraform/production
# Plan with a specific workspace
atlantis plan -w production
# Plan with extra Terraform flags
atlantis plan -- -var="environment=production"
# Plan with a specific var file
atlantis plan -- -var-file=production.tfvars
# Apply after reviewing plan
atlantis apply
# Apply a specific project
atlantis apply -p myproject
# Apply a specific directory
atlantis apply -d terraform/production
# Apply a specific workspace
atlantis apply -w production
# Unlock a project (discard pending plan)
atlantis unlock
# Check Atlantis version
atlantis version
# Import a resource
atlantis import -d terraform/production ADDRESS ID
Lock Management
# View locks via web UI
# Navigate to https://atlantis.example.com
# Unlock via PR comment
atlantis unlock
# Force unlock via API
curl -X DELETE "https://atlantis.example.com/api/locks?id=LOCK_ID"
# List all locks
curl -s "https://atlantis.example.com/api/locks" | jq '.'
Configuration
Server-Side Repo Configuration (atlantis.yaml)
# atlantis.yaml — Place in repository root
version: 3
automerge: false
delete_source_branch_on_merge: true
parallel_plan: true
parallel_apply: true
projects:
- name: production-vpc
dir: terraform/vpc
workspace: production
terraform_version: v1.7.0
autoplan:
when_modified:
- "*.tf"
- "*.tfvars"
- "modules/**/*.tf"
enabled: true
apply_requirements:
- approved
- mergeable
workflow: default
- name: staging-vpc
dir: terraform/vpc
workspace: staging
terraform_version: v1.7.0
autoplan:
when_modified:
- "*.tf"
- "staging.tfvars"
enabled: true
- name: production-eks
dir: terraform/eks
workspace: production
terraform_version: v1.7.0
autoplan:
enabled: true
apply_requirements:
- approved
- mergeable
depends_on:
- production-vpc
- name: production-rds
dir: terraform/rds
workspace: production
autoplan:
enabled: true
apply_requirements:
- approved
- mergeable
Custom Workflows
# atlantis.yaml with custom workflows
version: 3
projects:
- name: production
dir: terraform/production
workflow: production-workflow
apply_requirements:
- approved
- mergeable
workflows:
production-workflow:
plan:
steps:
# Custom init with backend config
- init:
extra_args: ["-backend-config=production.backend.hcl"]
# Run tflint before planning
- run: tflint --init && tflint
# Run checkov security scan
- run: checkov -d . --quiet --compact
# Standard plan
- plan:
extra_args: ["-var-file=production.tfvars"]
# Show cost estimate
- run: |
infracost breakdown --path . --format table
apply:
steps:
- apply
# Terragrunt workflow
terragrunt-workflow:
plan:
steps:
- env:
name: TERRAGRUNT_TFPATH
command: 'which terraform'
- run: terragrunt plan -input=false -out=$PLANFILE
apply:
steps:
- run: terragrunt apply $PLANFILE
Server-Side Configuration (repos.yaml)
# repos.yaml — Server-side config to enforce policies across all repos
repos:
# Default settings for all repos
- id: /.*/
allowed_overrides:
- workflow
- apply_requirements
- delete_source_branch_on_merge
apply_requirements:
- approved
- mergeable
allowed_workflows:
- default
- custom-with-checks
allow_custom_workflows: false
# Specific repo overrides
- id: github.com/your-org/infrastructure
allowed_overrides:
- workflow
- apply_requirements
apply_requirements:
- approved
- mergeable
allow_custom_workflows: true
# Restrict certain repos
- id: github.com/your-org/production-infra
apply_requirements:
- approved
- mergeable
allowed_overrides: []
allow_custom_workflows: false
workflows:
custom-with-checks:
plan:
steps:
- init
- run: tflint
- plan
apply:
steps:
- apply
Helm Values (Full Example)
# atlantis-values.yaml
orgAllowlist: "github.com/your-org/*"
atlantisUrl: "https://atlantis.example.com"
github:
user: atlantis-bot
token: ghp_xxxxxxxxxxxx
secret: webhook-secret-123
# Server-side repo config
repoConfig: |
---
repos:
- id: /.*/
apply_requirements: [approved, mergeable]
allowed_overrides: [workflow, apply_requirements]
allow_custom_workflows: true
# Environment variables for cloud credentials
environmentSecrets:
- name: AWS_ACCESS_KEY_ID
secretKeyRef:
name: aws-credentials
key: access-key-id
- name: AWS_SECRET_ACCESS_KEY
secretKeyRef:
name: aws-credentials
key: secret-access-key
- name: INFRACOST_API_KEY
secretKeyRef:
name: infracost-key
key: api-key
# Default Terraform version
defaultTFVersion: "1.7.0"
# Resource limits
resources:
requests:
memory: 512Mi
cpu: 200m
limits:
memory: 2Gi
cpu: 1000m
# Persistence
dataStorage: 10Gi
# Ingress
ingress:
enabled: true
ingressClassName: nginx
host: atlantis.example.com
tls:
- secretName: atlantis-tls
hosts:
- atlantis.example.com
Advanced Usage
Conftest Policy Checking
# atlantis.yaml — Run conftest policies
workflows:
policy-checked:
plan:
steps:
- init
- plan
- run: |
terraform show -json $PLANFILE > plan.json
conftest test plan.json --policy policy/ --no-color
Multi-Environment Promotion
# atlantis.yaml — Promote through environments
version: 3
projects:
- name: dev
dir: terraform/app
workspace: dev
autoplan:
enabled: true
- name: staging
dir: terraform/app
workspace: staging
apply_requirements: [approved]
depends_on: [dev]
- name: production
dir: terraform/app
workspace: production
apply_requirements: [approved, mergeable]
depends_on: [staging]
Webhook Configuration
# GitHub webhook setup
# URL: https://atlantis.example.com/events
# Content type: application/json
# Secret: your-webhook-secret
# Events: Pull requests, Pull request reviews, Issue comments, Pushes
# GitLab webhook
# URL: https://atlantis.example.com/events
# Secret: your-webhook-secret
# Triggers: Push events, Comments, Merge request events
# Test webhook
curl -X POST "https://atlantis.example.com/events" \
-H "Content-Type: application/json" \
-H "X-GitHub-Event: ping" \
-d '{"zen": "test"}'
Troubleshooting
| Issue | Cause | Solution |
|---|---|---|
| Atlantis not commenting on PR | Webhook not configured | Verify webhook URL and secret in GitHub settings |
| Plan failing with auth error | Missing cloud credentials | Set AWS/GCP/Azure credentials as environment variables |
| Lock conflict | Another PR holds the lock | Merge or close the conflicting PR, or force unlock |
| Autoplan not triggering | Files outside when_modified pattern | Update when_modified to include changed files |
| Apply requirements not met | PR not approved or not mergeable | Get PR approval and resolve merge conflicts |
| Custom workflow not found | Workflow name mismatch | Verify workflow name in atlantis.yaml matches project config |
| Slow plans | Large state file | Use state file splitting or -target flag |
| Atlantis pod OOMKilled | Insufficient memory for large plans | Increase memory limit in Helm values |
# Check Atlantis health
curl https://atlantis.example.com/healthz
# View Atlantis logs
kubectl logs -n atlantis deploy/atlantis --tail=100
# Check webhook deliveries (GitHub)
# Go to repo Settings > Webhooks > Recent Deliveries
# Debug: view active locks
curl -s https://atlantis.example.com/api/locks | jq '.'
# Force unlock all
curl -X DELETE "https://atlantis.example.com/api/locks?id=LOCK_ID"
# Test connectivity from Atlantis to Git
kubectl exec -n atlantis deploy/atlantis -- git ls-remote https://github.com/org/repo.git
# Verify Terraform version
kubectl exec -n atlantis deploy/atlantis -- terraform version