Atlantis

Atlantis 完全ガイド: Terraform Pull Request 自動化プラットフォーム


目次

  1. はじめに
  2. Atlantis の概要とアーキテクチャ
  3. サポートされる VCS プラットフォーム
  4. インストールとデプロイメント
  5. サーバー設定 (Server Configuration)
  6. リポジトリレベル設定 (atlantis.yaml)
  7. サーバーサイドリポジトリ設定 (repos.yaml)
  8. カスタムワークフロー
  9. Autoplan と Automerge
  10. ロック機構
  11. コマンドリファレンス
  12. Apply 要件とアクセス制御
  13. ポリシーチェック (Conftest 連携)
  14. Pre/Post ワークフローフック
  15. Terraform Cloud / Enterprise 連携
  16. API エンドポイント
  17. セキュリティ
  18. 高度な設定と運用パターン
  19. トラブルシューティング
  20. まとめ

1. はじめに

1.1 本ドキュメントの目的

本ドキュメントでは、Terraform Pull Request 自動化ツールである Atlantis (https://www.runatlantis.io) の機能、アーキテクチャ、設定方法について包括的に解説する。Atlantis は、Infrastructure as Code (IaC) のワークフローにおいて、Pull Request ベースの Terraform オペレーションを自動化するオープンソースツールであり、チームでの安全かつ効率的なインフラストラクチャ管理を実現する。

1.2 Atlantis が解決する課題

従来の Terraform 運用では、以下のような課題が存在していた:

  1. ローカル実行のリスク: 各開発者がローカル環境で terraform plan / terraform apply を実行する場合、実行環境の差異や認証情報の管理が困難
  2. レビュープロセスの欠如: Terraform のコード変更に対して、plan 結果をレビューする標準的なプロセスが確立しにくい
  3. 並行変更の衝突: 複数のエンジニアが同じ State に対して同時に変更を加えると、State の破損や意図しない変更が発生する可能性がある
  4. 可視性の不足: 誰がいつどのような変更をインフラに加えたかの追跡が困難
  5. CI/CD パイプラインとの統合: 汎用 CI/CD ツールで Terraform を実行する場合の複雑なセットアップ

Atlantis はこれらの課題を、Pull Request 駆動のワークフローによって解決する。

1.3 Atlantis の基本哲学

Atlantis は以下の設計哲学に基づいている:

  • Pull Request がすべての起点: インフラ変更は必ず Pull Request を通じて行う
  • 自動化による一貫性: plan と apply のプロセスを自動化し、人為的ミスを削減
  • コラボレーションの促進: plan 結果を Pull Request のコメントとして共有し、チームでのレビューを容易にする
  • 最小権限の原則: 個人の開発者がクラウド認証情報を持つ必要をなくし、Atlantis サーバーが一元的に認証を管理する

2. Atlantis の概要とアーキテクチャ

2.1 Atlantis とは

Atlantis は、Go 言語で開発されたシングルバイナリのアプリケーションであり、VCS (Version Control System) プラットフォームからの Webhook を受信して Terraform コマンドを実行する。CNCF (Cloud Native Computing Foundation) のランドスケープにも含まれており、広く利用されている。

2.2 アーキテクチャ概要

Atlantis のアーキテクチャは以下のコンポーネントで構成される:

┌─────────────────────────────────────────────────────────┐
│                    VCS プラットフォーム                      │
│  (GitHub / GitLab / Bitbucket / Azure DevOps / Gitea)   │
│                                                          │
│  ┌──────────┐    ┌──────────┐    ┌──────────┐           │
│  │   PR 作成  │    │ コメント   │    │   Push    │           │
│  └─────┬────┘    └─────┬────┘    └─────┬────┘           │
│        │               │               │                 │
│        └───────────────┼───────────────┘                 │
│                        │                                 │
│                   Webhook                                │
└────────────────────────┼─────────────────────────────────┘
                         │
                         ▼
┌─────────────────────────────────────────────────────────┐
│                   Atlantis サーバー                       │
│                                                          │
│  ┌──────────────────────────────────────────────┐       │
│  │              Webhook ハンドラー                 │       │
│  │  - リクエスト検証 (Webhook Secret)             │       │
│  │  - イベントパース                              │       │
│  └──────────────────┬───────────────────────────┘       │
│                     │                                    │
│  ┌──────────────────▼───────────────────────────┐       │
│  │            コマンドルーター                     │       │
│  │  - plan / apply / unlock / import            │       │
│  │  - approve_policies                           │       │
│  └──────────────────┬───────────────────────────┘       │
│                     │                                    │
│  ┌──────────────────▼───────────────────────────┐       │
│  │           プロジェクトディスカバリー              │       │
│  │  - atlantis.yaml パース                       │       │
│  │  - 変更ファイルの検出                          │       │
│  │  - Terraform プロジェクトの特定                 │       │
│  └──────────────────┬───────────────────────────┘       │
│                     │                                    │
│  ┌──────────────────▼───────────────────────────┐       │
│  │            ロックマネージャー                    │       │
│  │  - BoltDB / Redis                             │       │
│  │  - ディレクトリ + ワークスペース単位             │       │
│  └──────────────────┬───────────────────────────┘       │
│                     │                                    │
│  ┌──────────────────▼───────────────────────────┐       │
│  │            Terraform 実行エンジン               │       │
│  │  - init → plan → (policy check) → apply      │       │
│  │  - カスタムワークフローステップ                  │       │
│  └──────────────────┬───────────────────────────┘       │
│                     │                                    │
│  ┌──────────────────▼───────────────────────────┐       │
│  │            VCS コメント投稿                     │       │
│  │  - Plan 結果のフォーマット                     │       │
│  │  - ステータスチェックの更新                    │       │
│  └──────────────────────────────────────────────┘       │
│                                                          │
│  ┌──────────────┐  ┌──────────────┐                     │
│  │  データディレクトリ │  │  Web UI      │                     │
│  │  (Plan ファイル)  │  │  (ロック一覧)  │                     │
│  └──────────────┘  └──────────────┘                     │
└─────────────────────────────────────────────────────────┘
                         │
                         ▼
┌─────────────────────────────────────────────────────────┐
│              クラウドプロバイダー / State Backend          │
│  (AWS / GCP / Azure / Terraform Cloud)                  │
└─────────────────────────────────────────────────────────┘

2.3 基本的なワークフロー

Atlantis を使用した標準的な Terraform ワークフローは以下の通り:

  1. 開発者が Pull Request を作成: Terraform コードの変更を含むブランチから PR を作成
  2. Atlantis が自動で plan を実行: Webhook 経由で PR の作成を検知し、自動的に terraform plan を実行
  3. plan 結果が PR にコメントとして投稿: チームメンバーがインフラ変更の内容をレビュー可能
  4. レビューと承認: コードレビューと plan 結果の確認後、PR を承認
  5. atlantis apply の実行: PR のコメントで atlantis apply と入力して変更を適用
  6. PR のマージ: apply が成功したら PR をマージ
開発者          VCS (GitHub 等)        Atlantis          Cloud Provider
  │                  │                    │                    │
  │── PR 作成 ──────>│                    │                    │
  │                  │── Webhook ────────>│                    │
  │                  │                    │── git clone ──────>│
  │                  │                    │── terraform init ─>│
  │                  │                    │── terraform plan ─>│
  │                  │<── Plan 結果 ──────│                    │
  │<── Plan 表示 ────│                    │                    │
  │                  │                    │                    │
  │── レビュー&承認 ->│                    │                    │
  │                  │                    │                    │
  │── "atlantis      │                    │                    │
  │    apply" ──────>│── Webhook ────────>│                    │
  │                  │                    │── terraform apply >│
  │                  │<── Apply 結果 ─────│                    │
  │<── 結果表示 ─────│                    │                    │
  │                  │                    │                    │
  │── PR マージ ─────>│                    │                    │
  │                  │── Webhook ────────>│                    │
  │                  │                    │── ロック解除 ──────│

2.4 データストレージ

Atlantis は外部データベースを必要としない。Plan ファイルとロック情報はローカルディスクに保存される:

  • BoltDB (デフォルト): ロック情報の永続化に使用
  • Redis (オプション): 分散環境でのロック管理に使用可能
  • ファイルシステム: Terraform plan ファイルの保存

このため、Kubernetes にデプロイする場合は StatefulSet の使用が推奨される。Pod が再起動しても plan ファイルが失われないよう、永続ボリュームの設定が重要である。


3. サポートされる VCS プラットフォーム

Atlantis は以下の VCS プラットフォームをサポートしている:

プラットフォームWebhook サポートステータスチェックコメント投稿備考
GitHub (github.com)完全対応対応対応GitHub App にも対応
GitHub Enterprise完全対応対応対応--gh-hostname で設定
GitLab (gitlab.com)完全対応対応対応Merge Request ベース
GitLab Enterprise完全対応対応対応--gitlab-hostname で設定
Bitbucket Cloud完全対応対応対応App Password 使用
Bitbucket Server完全対応対応対応--bitbucket-base-url で設定
Azure DevOps完全対応対応対応Basic 認証ベース
Gitea完全対応対応対応--gitea-base-url で設定

3.1 GitHub 設定例

atlantis server \
  --gh-user="atlantis-bot" \
  --gh-token="ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  --gh-webhook-secret="your-random-secret-string" \
  --repo-allowlist="github.com/myorg/*" \
  --atlantis-url="https://atlantis.example.com"

GitHub App を使用する場合

atlantis server \
  --gh-app-id="12345" \
  --gh-app-key-file="/path/to/private-key.pem" \
  --gh-app-slug="my-atlantis-app" \
  --gh-webhook-secret="your-random-secret-string" \
  --repo-allowlist="github.com/myorg/*"

3.2 GitLab 設定例

atlantis server \
  --gitlab-user="atlantis-bot" \
  --gitlab-token="glpat-xxxxxxxxxxxxxxxxxxxx" \
  --gitlab-webhook-secret="your-random-secret-string" \
  --repo-allowlist="gitlab.com/mygroup/*"

3.3 Azure DevOps 設定例

atlantis server \
  --azuredevops-user="atlantis@myorg.com" \
  --azuredevops-token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  --azuredevops-webhook-user="webhook-user" \
  --azuredevops-webhook-password="webhook-password" \
  --repo-allowlist="dev.azure.com/myorg/*"

3.4 Gitea 設定例

atlantis server \
  --gitea-user="atlantis-bot" \
  --gitea-token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  --gitea-webhook-secret="your-random-secret-string" \
  --gitea-base-url="https://gitea.example.com" \
  --repo-allowlist="gitea.example.com/myorg/*"

4. インストールとデプロイメント

4.1 デプロイメント方式の概要

方式推奨度特徴
Kubernetes Helm Chart推奨公式 Helm Chart。最も簡単
Kubernetes Manifest推奨StatefulSet での永続化対応
Dockerシンプルな単一コンテナ運用
AWS Fargateサーバーレスコンテナ
Google Cloud Runサーバーレス対応
GKE / GCEGoogle Cloud 上の Kubernetes
Azure AKS / ACIAzure 上のコンテナサービス
バイナリ直接実行開発/テスト用途

4.2 Kubernetes Helm Chart によるデプロイ

helm repo add runatlantis https://runatlantis.github.io/helm-charts
helm inspect values runatlantis/atlantis > values.yaml

values.yaml の主要設定:

orgWhitelist: "github.com/myorg/*"
github:
  user: "atlantis-bot"
  token: "ghp_xxxxxxxxxxxxxxxxxxxx"
  secret: "your-webhook-secret"
persistence:
  enabled: true
  storageClassName: "standard"
  accessModes: ["ReadWriteOnce"]
  size: 5Gi
resources:
  requests:
    memory: "256Mi"
    cpu: "100m"
  limits:
    memory: "1Gi"
    cpu: "1000m"
ingress:
  enabled: true
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-prod
  hosts:
    - host: atlantis.example.com
      paths: [/]
  tls:
    - secretName: atlantis-tls
      hosts: [atlantis.example.com]
repoConfig: |
  ---
  repos:
  - id: /.*/
    apply_requirements: [approved, mergeable]
    allowed_overrides: [apply_requirements, workflow]
    allow_custom_workflows: true
helm install atlantis runatlantis/atlantis -f values.yaml

4.3 Kubernetes StatefulSet によるデプロイ

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: atlantis
spec:
  serviceName: atlantis
  replicas: 1
  selector:
    matchLabels:
      app: atlantis
  template:
    metadata:
      labels:
        app: atlantis
    spec:
      securityContext:
        fsGroup: 1000
      containers:
      - name: atlantis
        image: ghcr.io/runatlantis/atlantis:v0.28.0
        env:
        - name: ATLANTIS_REPO_ALLOWLIST
          value: "github.com/myorg/*"
        - name: ATLANTIS_GH_USER
          valueFrom:
            secretKeyRef:
              name: atlantis-secrets
              key: gh-user
        - name: ATLANTIS_GH_TOKEN
          valueFrom:
            secretKeyRef:
              name: atlantis-secrets
              key: gh-token
        - name: ATLANTIS_GH_WEBHOOK_SECRET
          valueFrom:
            secretKeyRef:
              name: atlantis-secrets
              key: gh-webhook-secret
        - name: ATLANTIS_DATA_DIR
          value: "/atlantis-data"
        - name: ATLANTIS_PORT
          value: "4141"
        ports:
        - name: atlantis
          containerPort: 4141
        resources:
          requests: { memory: "256Mi", cpu: "100m" }
          limits: { memory: "1Gi", cpu: "1000m" }
        livenessProbe:
          httpGet: { path: /healthz, port: 4141 }
          periodSeconds: 60
        readinessProbe:
          httpGet: { path: /healthz, port: 4141 }
          periodSeconds: 60
        volumeMounts:
        - name: atlantis-data
          mountPath: /atlantis-data
  volumeClaimTemplates:
  - metadata:
      name: atlantis-data
    spec:
      accessModes: ["ReadWriteOnce"]
      storageClassName: "standard"
      resources:
        requests:
          storage: 5Gi

4.4 Docker によるデプロイ

docker run -d --name atlantis -p 4141:4141 \
  -v /var/atlantis-data:/atlantis-data \
  ghcr.io/runatlantis/atlantis:v0.28.0 server \
  --atlantis-url="https://atlantis.example.com" \
  --gh-user="atlantis-bot" \
  --gh-token="ghp_xxxxxxxxxxxxxxxxxxxx" \
  --gh-webhook-secret="your-secret" \
  --repo-allowlist="github.com/myorg/*" \
  --data-dir="/atlantis-data"

カスタム Docker イメージ

FROM ghcr.io/runatlantis/atlantis:v0.28.0
USER root
ARG TERRAGRUNT_VERSION=0.55.0
RUN curl -Lo /usr/local/bin/terragrunt \
    "https://github.com/gruntwork-io/terragrunt/releases/download/v${TERRAGRUNT_VERSION}/terragrunt_linux_amd64" \
    && chmod +x /usr/local/bin/terragrunt
USER atlantis

4.5 AWS Fargate によるデプロイ

module "atlantis" {
  source  = "terraform-aws-modules/atlantis/aws"
  version = "~> 4.0"
  name = "atlantis"
  cidr            = "10.20.0.0/16"
  azs             = ["ap-northeast-1a", "ap-northeast-1c"]
  private_subnets = ["10.20.1.0/24", "10.20.2.0/24"]
  public_subnets  = ["10.20.101.0/24", "10.20.102.0/24"]
  atlantis_github_user       = "atlantis-bot"
  atlantis_github_user_token = "ghp_xxxxxxxxxxxxxxxxxxxx"
  atlantis_repo_allowlist    = ["github.com/myorg/*"]
  route53_zone_name = "example.com"
  certificate_arn   = "arn:aws:acm:..."
}

5. サーバー設定 (Server Configuration)

5.1 設定の優先順位

コマンドラインフラグ  >  環境変数  >  設定ファイル (YAML)

環境変数の命名規則: --gh-userATLANTIS_GH_USER

YAML 設定ファイル例

# config.yaml
gh-user: "atlantis-bot"
gh-token: "ghp_xxxxxxxxxxxxxxxxxxxx"
gh-webhook-secret: "your-secret"
repo-allowlist: "github.com/myorg/*"
atlantis-url: "https://atlantis.example.com"
port: 4141
data-dir: "/var/atlantis"
log-level: "info"

5.2 コアサーバー設定

フラグ環境変数デフォルト説明
--portATLANTIS_PORT4141リッスンポート
--atlantis-urlATLANTIS_ATLANTIS_URLhttp://$(hostname):$port外部 URL
--data-dirATLANTIS_DATA_DIR~/.atlantisデータディレクトリ
--log-levelATLANTIS_LOG_LEVELinfoログレベル
--repo-allowlistATLANTIS_REPO_ALLOWLISTなし (必須)許可リポジトリパターン
--allow-fork-prsATLANTIS_ALLOW_FORK_PRSfalseフォーク PR への応答
--allow-draft-prsATLANTIS_ALLOW_DRAFT_PRSfalseドラフト PR への応答

5.3 Plan / Apply 関連設定

フラグデフォルト説明
--autoplan-file-list**/*.tf,**/*.tfvars,**/*.tfvars.jsonAutoplan トリガーパターン
--autoplan-modulesfalseモジュール依存関係トレース
--disable-autoplanfalse自動 plan 無効化
--disable-apply-allfalseプロジェクト指定必須化
--automergefalse自動マージ
--parallel-planfalse並列 plan
--parallel-applyfalse並列 apply
--parallel-pool-size15並列最大数

5.4 Terraform 関連設定

フラグデフォルト説明
--default-tf-versionなしデフォルト Terraform バージョン
--default-tf-distributionterraformterraform or opentofu
--tf-downloadtrue自動ダウンロード許可
--use-tf-plugin-cachetrueプラグインキャッシュ

5.5 セキュリティ関連設定

フラグデフォルト説明
--api-secretなしAPI 認証シークレット
--web-basic-authfalseWeb UI Basic 認証
--ssl-cert-fileなしSSL 証明書パス
--ssl-key-fileなしSSL 秘密鍵パス
--var-file-allowlistデータディレクトリtfvars ディレクトリ制限

5.6 ロック管理設定

フラグデフォルト説明
--locking-db-typeboltdbロックバックエンド
--redis-hostなしRedis ホスト
--redis-port6379Redis ポート
--redis-tls-enabledfalseRedis TLS
--disable-repo-lockingfalseロック無効化

5.7 通知・UI 関連設定

フラグデフォルト説明
--hide-prev-plan-commentsfalse以前の plan コメント非表示
--hide-unchanged-plan-commentsfalse変更なし plan 削除
--disable-markdown-foldingfalsedetails タグ無効化
--enable-diff-markdown-formatfalsediff カラーコーディング
--slack-tokenなしSlack 通知トークン
--enable-policy-checksfalseポリシーチェック有効化
--enable-regexp-cmdfalse正規表現コマンド許可
--markdown-template-overrides-dir~/.markdown_templates/テンプレートディレクトリ

6. リポジトリレベル設定 (atlantis.yaml)

6.1 概要

atlantis.yaml はリポジトリのルートに配置する設定ファイル。オプションであり、デフォルト設定で多くのケースに対応可能。

重要: Atlantis は PR ブランチatlantis.yaml を使用する。カスタムワークフローが許可されている場合、PR を作成できる人が Atlantis サーバー上で任意のコードを実行できる可能性がある。

6.2 基本構造

version: 3  # 必須
automerge: false
delete_source_branch_on_merge: false
parallel_plan: false
parallel_apply: false
abort_on_execution_order_fail: false
projects: []
workflows: {}
allowed_regexp_prefixes: []

6.3 プロジェクト設定

version: 3
projects:
  - name: networking
    dir: infrastructure/networking
    workspace: default
    terraform_version: "1.7.0"
    terraform_distribution: terraform
    workflow: custom-workflow
    execution_order_group: 1
    autoplan:
      enabled: true
      when_modified:
        - "*.tf"
        - "*.tfvars"
        - ".terraform.lock.hcl"
        - "../modules/networking/**/*.tf"
    apply_requirements:
      - approved
      - mergeable
    plan_requirements:
      - undiverged
  - name: compute
    dir: infrastructure/compute
    workspace: default
    execution_order_group: 2
    depends_on:
      - networking

6.4 プロジェクトフィールド

フィールドデフォルト説明
namestring-プロジェクト名
dirstring必須ディレクトリパス
workspacestringdefaultワークスペース名
terraform_versionstring-Terraform バージョン
terraform_distributionstringterraformterraform or opentofu
workflowstring-ワークフロー名
execution_order_groupint0実行順序
depends_onarray-依存プロジェクト
branchstring-ベースブランチ正規表現

6.5 Autodiscovery

version: 3
autodiscover:
  mode: auto       # auto / enabled / disabled
  ignore_paths:
    - "test/**"
    - "examples/**"

6.6 リポジトリロック

version: 3
repo_locks:
  mode: on_plan    # on_plan / on_apply / disabled

6.7 完全な設定例 (マルチ環境)

version: 3
automerge: false
parallel_plan: true
abort_on_execution_order_fail: true

projects:
  - name: dev-networking
    dir: environments/dev/networking
    terraform_version: "1.7.0"
    workflow: dev
    execution_order_group: 1
    autoplan:
      enabled: true
      when_modified: ["*.tf", "*.tfvars", "../../../modules/networking/**/*.tf"]

  - name: dev-compute
    dir: environments/dev/compute
    terraform_version: "1.7.0"
    workflow: dev
    execution_order_group: 2
    depends_on: [dev-networking]

  - name: prod-networking
    dir: environments/prod/networking
    terraform_version: "1.7.0"
    workflow: production
    execution_order_group: 1
    apply_requirements: [approved, mergeable]

  - name: prod-compute
    dir: environments/prod/compute
    terraform_version: "1.7.0"
    workflow: production
    execution_order_group: 2
    depends_on: [prod-networking]
    apply_requirements: [approved, mergeable]

workflows:
  dev:
    plan:
      steps:
        - init
        - plan:
            extra_args: ["-var-file", "dev.tfvars"]
    apply:
      steps: [apply]

  production:
    plan:
      steps:
        - init
        - plan:
            extra_args: ["-var-file", "prod.tfvars"]
    apply:
      steps:
        - run: ./scripts/notify-slack.sh "Production deployment starting"
        - apply
        - run: ./scripts/notify-slack.sh "Production deployment completed"

7. サーバーサイドリポジトリ設定 (repos.yaml)

7.1 概要

repos.yaml はサーバーサイド設定ファイルで、リポジトリごとの動作を中央集権的に制御する。

atlantis server --repo-config=/etc/atlantis/repos.yaml

7.2 トップレベル構造

repos:
  - id: /.*/
    # リポジトリ設定
workflows:
  custom:
    plan:
      steps: [init, plan]
    apply:
      steps: [apply]
policies:
  owners:
    users: ["admin-user"]
  policy_sets:
    - name: security-policy
      path: /policies/security/
      source: local

7.3 リポジトリ設定の詳細

repos:
  - id: /.*/
    branch: /.*/
    plan_requirements: [approved]
    apply_requirements: [approved, mergeable]
    import_requirements: [approved]
    workflow: default
    allowed_overrides: [apply_requirements, workflow]
    allowed_workflows: [default, custom-plan]
    allow_custom_workflows: false
    delete_source_branch_on_merge: false
    repo_locks:
      mode: on_plan
    policy_check: true
    autodiscover:
      mode: auto

  - id: github.com/myorg/infrastructure-prod
    apply_requirements: [approved, mergeable, undiverged]
    allowed_overrides: []
    allow_custom_workflows: false

  - id: /github.com\/myorg\/infra-.*/
    workflow: infra-team
    allowed_overrides: [workflow]
    allowed_workflows: [infra-team, infra-team-with-validation]

7.4 マッチング規則

複数パターンがマッチする場合、後に定義されたものが優先。未定義キーは以前のマッチから継承。

7.5 Pre/Post ワークフローフック

repos:
  - id: /.*/
    pre_workflow_hooks:
      - run: ./scripts/generate-atlantis-config.sh
        description: "Dynamic config generation"
        commands: plan
    post_workflow_hooks:
      - run: ./scripts/cleanup.sh
        description: "Post-workflow cleanup"
        commands: plan, apply

8. カスタムワークフロー

8.1 ワークフロー構造

workflows:
  my-workflow:
    plan:
      steps: [...]
    apply:
      steps: [...]
    import:
      steps: [...]
    state_rm:
      steps: [...]

8.2 ステップの種類

ビルトインコマンド

steps:
  - init
  - plan
  - apply

ビルトインコマンド + 追加引数

steps:
  - init:
      extra_args: ["-upgrade"]
  - plan:
      extra_args: ["-lock=false", "-var-file", "production.tfvars"]

カスタム run コマンド

steps:
  - run: echo "Hello, World!"
  - run:
      command: terraform plan -out=$PLANFILE
      shell: bash
      shellArgs: ["-eo", "pipefail", "-c"]
      output: show  # show / hide / strip_refreshing / filter_regex

環境変数設定

steps:
  - env:
      name: AWS_REGION
      value: "ap-northeast-1"
  - env:
      name: ENVIRONMENT
      command: 'basename $(pwd)'
  - multienv:
      command: ./scripts/generate-vars.sh
      output: hide

8.3 組み込み環境変数

変数名説明
WORKSPACETerraform ワークスペース名
DIRプロジェクトディレクトリ絶対パス
PLANFILEplan ファイル出力パス
SHOWFILEshow ファイル出力パス
BASE_REPO_NAME / BASE_REPO_OWNERベースリポジトリ情報
HEAD_REPO_NAME / HEAD_REPO_OWNERヘッドリポジトリ情報
HEAD_BRANCH_NAME / BASE_BRANCH_NAMEブランチ情報
HEAD_COMMITコミット SHA
PROJECT_NAMEプロジェクト名
PULL_NUM / PULL_URL / PULL_AUTHORPR 情報
USER_NAMEコマンド実行者
COMMENT_ARGS追加引数
ATLANTIS_TERRAFORM_VERSIONTerraform バージョン

8.4 実践的なワークフロー例

Terragrunt 連携

workflows:
  terragrunt:
    plan:
      steps:
        - env:
            name: TERRAGRUNT_TFPATH
            command: 'echo "terraform${ATLANTIS_TERRAFORM_VERSION}"'
        - run: terragrunt plan -input=false -out=$PLANFILE
    apply:
      steps:
        - env:
            name: TERRAGRUNT_TFPATH
            command: 'echo "terraform${ATLANTIS_TERRAFORM_VERSION}"'
        - run: terragrunt apply $PLANFILE

tflint バリデーション

workflows:
  validated-plan:
    plan:
      steps:
        - init
        - run:
            command: tflint --init && tflint
            output: show
        - plan

Infracost コスト見積もり

workflows:
  with-cost-estimate:
    plan:
      steps:
        - init
        - plan
        - run:
            command: |
              infracost breakdown --path=$PLANFILE \
                --format=json --out-file=/tmp/infracost.json
              infracost output --path=/tmp/infracost.json \
                --format=github-comment --out-file=/tmp/infracost-comment.md
              cat /tmp/infracost-comment.md
            output: show

9. Autoplan と Automerge

9.1 Autoplan

Autoplan は PR 作成時・コミットプッシュ時に自動で terraform plan を実行する。

アルゴリズム:

  1. 変更ファイルを検出
  2. .tf ファイルをフィルタ
  3. 該当ディレクトリを特定
  4. modules/ 配下でなければ plan 実行
  5. modules/ 配下の場合、親ディレクトリに main.tf があれば親で plan
# サーバーレベル制御
atlantis server --autoplan-file-list="**/*.tf,**/*.tfvars"
atlantis server --disable-autoplan
atlantis server --disable-autoplan-label="no-autoplan"
atlantis server --autoplan-modules=true

9.2 Automerge

全プロジェクトの apply 成功後に PR を自動マージ:

version: 3
automerge: true
delete_source_branch_on_merge: true

10. ロック機構

10.1 目的

  1. State 一貫性保護: apply は PR マージ前に実行されるため、ロックで他の PR からの変更を防止
  2. Plan 有効性保証: 他の PR の apply による plan 無効化を防止

10.2 粒度

ロックは ディレクトリ + ワークスペース 単位。リポジトリ全体ではない。

10.3 ライフサイクル

  • PR マージ/クローズ → 自動解除
  • atlantis unlock コメント → 手動解除
  • Web UI → "Discard Plan and Unlock"

10.4 Terraform State ロックとの関係

項目Atlantis ロックTerraform State ロック
粒度ディレクトリ + ワークスペースState ファイル
目的PR 間の競合防止同時実行防止
スコープPR ライフサイクルコマンド実行中
保存先BoltDB / RedisState Backend

10.5 Redis 分散ロック

atlantis server \
  --locking-db-type=redis \
  --redis-host="redis.example.com" \
  --redis-port=6379 \
  --redis-password="your-redis-password" \
  --redis-tls-enabled=true

11. コマンドリファレンス

コマンド説明
atlantis plan全プロジェクトの plan
atlantis plan -d <dir>特定ディレクトリの plan
atlantis plan -p <project>特定プロジェクトの plan
atlantis plan -w <workspace>特定ワークスペースの plan
atlantis plan -- -var="key=value"追加引数付き plan
atlantis apply全プロジェクトの apply
atlantis apply -d <dir>特定ディレクトリの apply
atlantis apply -p <project>特定プロジェクトの apply
atlantis unlock全ロック解除
atlantis import <addr> <id>リソースインポート
atlantis state rm <addr>State からリソース削除
atlantis approve_policiesポリシー違反承認
atlantis versionバージョン表示

チームベースの制限

atlantis server --gh-team-allowlist="platform-team:plan,platform-team:apply,dev-team:plan"

12. Apply 要件とアクセス制御

12.1 要件の種類

要件説明
approvedPR が承認済み
mergeablePR がマージ可能
undivergedベースブランチから分岐なし

12.2 設定方法

# repos.yaml
repos:
  - id: /.*/
    plan_requirements: [approved]
    apply_requirements: [approved, mergeable]
    import_requirements: [approved]
# atlantis.yaml (repos.yaml で allowed_overrides に含まれている場合のみ)
version: 3
projects:
  - dir: .
    apply_requirements: [approved, mergeable, undiverged]

12.3 重要な注意点

apply 要件が満たされると、PR にコメントできる全ユーザーが atlantis apply を実行可能。 より厳格な制御には:

atlantis server --gh-team-allowlist="infra-team:apply,dev-team:plan"

13. ポリシーチェック (Conftest 連携)

13.1 概要

Conftest (OPA ベース) と統合して plan 結果をポリシーチェック。セキュリティリスクや非準拠リソースを plan 段階で検出・ブロック。

13.2 セットアップ

atlantis server --enable-policy-checks
# repos.yaml
policies:
  owners:
    users: [policy-admin]
    teams: [security-team]
  approve_count: 1
  policy_sets:
    - name: security-policies
      path: /opt/atlantis/policies/security/
      source: local
      owners:
        users: [security-lead]
        teams: [security-team]
    - name: cost-policies
      path: /opt/atlantis/policies/cost/
      source: local
      approve_count: 2
      prevent_self_approve: true

13.3 Rego ポリシー例

null_resource 使用禁止:

package main

deny[msg] {
  resource := input.resource_changes[_]
  resource.type == "null_resource"
  resource.change.actions[_] == "create"
  msg := sprintf("null_resource の作成は禁止: %s", [resource.address])
}

必須タグの強制:

package main

required_tags := {"Environment", "Team", "CostCenter"}

deny[msg] {
  resource := input.resource_changes[_]
  resource.change.actions[_] == "create"
  tags := object.get(resource.change.after, "tags", {})
  missing := required_tags - {key | tags[key]}
  count(missing) > 0
  msg := sprintf("リソース %s に必須タグがありません: %v", [resource.address, missing])
}

インスタンスタイプ制限:

package main

allowed_instance_types := {"t3.micro", "t3.small", "t3.medium", "t3.large", "m5.large", "m5.xlarge"}

deny[msg] {
  resource := input.resource_changes[_]
  resource.type == "aws_instance"
  resource.change.actions[_] == "create"
  not allowed_instance_types[resource.change.after.instance_type]
  msg := sprintf("インスタンスタイプ '%s' は許可されていません", [resource.change.after.instance_type])
}

13.4 違反時のワークフロー

  1. plan 完了後に自動ポリシーチェック
  2. 違反がある場合、PR コメントで報告
  3. 違反がある限り apply 不可
  4. コード修正 or atlantis approve_policies で承認

14. Pre/Post ワークフローフック

14.1 概要

メインワークフロー前後に実行されるスクリプト。出力は PR コメントに非表示。

repos:
  - id: /.*/
    pre_workflow_hooks:
      - run: ./scripts/generate-atlantis-config.sh
        description: "Dynamic config generation"
        commands: plan
    post_workflow_hooks:
      - run: ./scripts/notify-completion.sh
        commands: apply

14.2 利用可能な環境変数

BASE_REPO_NAME, BASE_REPO_OWNER, HEAD_BRANCH_NAME, HEAD_COMMIT, PULL_NUM, PULL_URL, PULL_AUTHOR, DIR, USER_NAME, COMMAND_NAME, OUTPUT_STATUS_FILE

14.3 フック失敗時

atlantis server --fail-on-pre-workflow-hook-error  # 失敗時にワークフロー停止

15. Terraform Cloud / Enterprise 連携

15.1 モード

  1. リモート State ストレージ (無料): TFC を State 保存先として使用
  2. リモート実行 (有料): plan/apply を TFC/TFE で実行

15.2 設定

atlantis server \
  --tfe-token="your-terraform-cloud-token" \
  --gh-user="atlantis-bot" \
  --gh-token="ghp_xxxxxxxxxxxxxxxxxxxx" \
  --repo-allowlist="github.com/myorg/*"

# プライベート TFE
atlantis server --tfe-hostname="tfe.internal.example.com"

# ローカル実行モード
atlantis server --tfe-local-execution-mode

15.3 制限事項

  • カスタム run ステップで plan/apply を置き換え不可
  • Team Token に "Manage Workspaces" 権限が必要

16. API エンドポイント

16.1 認証付きエンドポイント

atlantis server --api-secret="your-api-secret"

# Plan
curl -X POST https://atlantis.example.com/api/plan \
  -H "X-Atlantis-Token: your-api-secret" \
  -H "Content-Type: application/json" \
  -d '{"Repository":"myorg/myrepo","Ref":"feature","Type":"Github","PR":42}'

# Apply
curl -X POST https://atlantis.example.com/api/apply \
  -H "X-Atlantis-Token: your-api-secret" \
  -H "Content-Type: application/json" \
  -d '{"Repository":"myorg/myrepo","Ref":"feature","Type":"Github","PR":42}'

16.2 パブリックエンドポイント

エンドポイント説明
GET /api/locksアクティブロック一覧
GET /statusサーバーステータス
GET /healthzヘルスチェック
GET /debug/pprofプロファイリング

17. セキュリティ

17.1 主要な脅威

  1. 悪意のある Terraform コード: external データソース等で plan 時に任意コード実行
  2. Local-exec プロビジョナー: 認証情報の外部送信
  3. atlantis.yaml の悪用: カスタムワークフロー経由の任意コマンド実行
  4. 未認証 Webhook: 偽リクエストによる plan/apply トリガー

17.2 推奨対策

# repos.yaml - セキュアな設定
repos:
  - id: /.*/
    allow_custom_workflows: false
    allowed_overrides: []
    apply_requirements: [approved, mergeable]
    policy_check: true
# 必須セキュリティ設定
atlantis server \
  --gh-webhook-secret="$SECRET" \
  --allow-fork-prs=false \
  --web-basic-auth=true \
  --web-username="admin" \
  --web-password="$(openssl rand -base64 32)" \
  --ssl-cert-file="/path/to/cert.pem" \
  --ssl-key-file="/path/to/key.pem" \
  --var-file-allowlist="/allowed/path"

17.3 セキュリティチェックリスト

項目優先度
Webhook Secret 設定必須
--repo-allowlist 設定 (* 禁止)必須
--allow-fork-prs=false必須
allow_custom_workflows: false
SSL/TLS 有効化
Web UI 認証
Egress 制限
ポリシーチェック有効化

18. 高度な設定と運用パターン

18.1 実行順序の制御

version: 3
abort_on_execution_order_fail: true
projects:
  - name: vpc
    dir: infrastructure/vpc
    execution_order_group: 0
  - name: subnets
    dir: infrastructure/subnets
    execution_order_group: 1
    depends_on: [vpc]
  - name: ecs-cluster
    dir: infrastructure/ecs
    execution_order_group: 2
    depends_on: [subnets]

18.2 正規表現コマンド

atlantis server --enable-regexp-cmd
# PR コメント例:
# atlantis plan -p "networking-.*"
# atlantis apply -p "dev-.*"

18.3 複数 Atlantis サーバー構成

# Server A (開発用)
atlantis server --vcs-status-name="atlantis/dev"

# Server B (本番用)
atlantis server --vcs-status-name="atlantis/prod"

18.4 OpenTofu サポート

atlantis server --default-tf-distribution=opentofu
version: 3
projects:
  - dir: .
    terraform_distribution: opentofu
    terraform_version: "1.6.0"

18.5 Markdown テンプレートカスタマイズ

atlantis server --markdown-template-overrides-dir="/etc/atlantis/templates/"

18.6 メトリクス

atlantis server --stats-namespace="atlantis"

19. トラブルシューティング

19.1 よくある問題

問題確認事項
Webhook が届かないサーバーアクセス可能性、URL、Secret 一致、ファイアウォール
Plan が自動実行されない--repo-allowlist--autoplan-file-list--disable-autoplan
Apply が拒否されるPR 承認状態、マージ可能性、ポリシー違反
ロック競合atlantis unlock または Web UI で解除
バージョン不一致terraform_version--tf-download=true
認証エラートークン有効期限、権限スコープ

19.2 デバッグ

atlantis server --log-level=debug
atlantis server --enable-profiling-api  # http://atlantis:4141/debug/pprof

19.3 ヘルスチェック

curl https://atlantis.example.com/healthz
curl https://atlantis.example.com/status
# {"shutting_down":false,"in_progress_operations":2,"version":"v0.28.0"}

20. まとめ

20.1 主要な利点

利点説明
PR ベースのワークフロー変更の可視性とトレーサビリティ向上
自動化plan 自動実行で即座に確認
セキュリティ認証情報の一元管理
コラボレーションplan 結果の PR コメント共有
ロック機構並行変更による State 破損防止
ポリシー強制Conftest でガバナンス確保
柔軟性カスタムワークフロー対応
マルチ VCSGitHub/GitLab/Bitbucket/Azure DevOps/Gitea

20.2 ベストプラクティス

  1. Webhook Secret を必ず設定
  2. --repo-allowlist を適切に設定 (* 禁止)
  3. カスタムワークフロー許可を制限
  4. apply 要件に最低 approved を設定
  5. 永続ストレージ確保 (StatefulSet + PVC)
  6. ポリシーチェックを活用
  7. VCS トークンの定期ローテーション
  8. /healthz と Prometheus メトリクスでモニタリング
  9. Docker イメージバージョン固定 (:latest 禁止)

20.3 参考リンク

リソースURL
公式サイトhttps://www.runatlantis.io
GitHub リポジトリhttps://github.com/runatlantis/atlantis
Helm Charthttps://github.com/runatlantis/helm-charts
CNCF Slack (#atlantis)https://cloud-native.slack.com
Terraform Module (AWS)https://registry.terraform.io/modules/terraform-aws-modules/atlantis/aws

本ドキュメントは Atlantis v0.28.x 時点の情報に基づいている。最新の情報は公式ドキュメント (https://www.runatlantis.io/docs) を参照のこと。