インフラのCI/CDは、アプリのCI/CDの流儀をそのまま持ち込むと事故ります。planとapplyの分離、承認ゲート、CIの権限設計という三点を押さえた「型」を、実在の一次情報を引きながら整理します。

01アプリのCIとインフラのCIは、そもそも別物です

アプリケーションのCIは「ビルドしてテストが通ればマージ」で完結します。成果物はアーティファクトで、失敗しても再ビルドすればよい。ところがインフラのCIは、パイプラインの実行そのものが本番のクラウドリソースを作り替えます。terraform applyは取り消せない操作を含み、順序を誤ればステートが壊れ、権限を広く持たせすぎればパイプラインが最強の攻撃対象になります。

つまりインフラのパイプラインで守るべきは「テストが通ること」ではなく、変更内容が人間の目でレビューされ、承認され、正しい権限で、正しい環境に適用されることです。この差を理解しないままon: pushapplyを回すと、レビューされていない差分が本番に流れ込みます。

現場のコツ:「CIが緑なら安全」というアプリの直感を、インフラに持ち込まないことです。インフラでは「planを人が読んで承認したか」が安全の実体です。緑は前提条件にすぎません。

02plan と apply を分ける — これが型の中心です

インフラCI/CDの背骨は、terraform planterraform applyを明確に分離することです。planはPR(プルリクエスト)の段階で自動実行し、その出力をPRのコメントとして貼り出す。applyはマージ後、あるいは承認後に別ステップとして実行する。この分離が、レビューと適用の間に人間の判断を挟む余地を作ります。

HashiCorpのHCP Terraform(旧Terraform Cloud)は、この型を製品として実装しています。VCS連携ワークスペースでは、PRが開かれるとspeculative plan(投機的プラン)を自動実行し、その結果へのリンクをPRに投稿、PRが更新されれば再実行します。speculative planはplanのみでapplyはできず、レビュー専用として設計されています(公式ドキュメント)。

Atlantisも同じ思想です。PRにコメントでatlantis planと書けば該当ディレクトリにterraform planが走り、出力がPRに返る。レビューが済んだらatlantis applyで適用し、対象ディレクトリはPRにロックされて他のPRからの競合を防ぎます(Using Atlantis)。ツールは違えど、「planはPRに出す、applyは分ける、ロックで競合を防ぐ」という骨格は共通です。

開発者がPR作成 .tf を変更 CIが plan 自動実行 出力をPRに貼付 人がplanを レビュー・承認 マージ / 承認ゲート 手動 or 自動 apply 実行 短命クレデンシャル クラウド環境が実際に変更される 承認後
図:planはPRで自動実行しレビューへ、applyは承認ゲートの後段に分離する。

03apply のゲート — 手動承認と自動適用の線引き

applyをどう守るか。ここが環境ごとの設計判断になります。選択肢は大きく二つ、手動承認ゲート自動適用(auto-apply)です。

手動承認の実装は、GitHub Actionsのenvironment機能が分かりやすい例です。environmentにrequired reviewersを設定すると、そのenvironmentを参照するジョブは指定した人・チームの承認なしには進めません。承認が下りるまで、そのジョブはenvironmentのシークレットにもアクセスできません。さらにself-review防止を有効にすれば、デプロイを起動した本人は承認できなくなり、必ず二人以上の目を通せます(Deployments and environments)。

一方で自動適用は、planに問題がなければ承認を待たずにapplyまで走らせる方式です。HCP Terraformでもワークスペースのauto-apply設定で選べます。ただし運用上は、本番は必ず手動承認、開発・サンドボックスは自動適用という環境ごとの使い分けが現実的です。DORAのState of DevOps研究も、デプロイ自動化は本番リスクを減らす基盤である一方、「認証情報を持つ者が任意のバージョンを任意の環境に投入できる」状態を前提に語っており、その裏返しとして誰が何を適用できるかの統制が要ることを示唆しています(DORA: Deployment automation)。

現場のコツ:承認ゲートは「誰でも承認できる」では意味が薄れます。self-review禁止と、承認者をコードオーナーやSREに限定する設定をセットで入れて、はじめてゲートが機能します。

04環境ごとにパイプラインを分ける

dev / staging / prod を一本のパイプラインで貫くと、本番だけ承認を厳しくする、といった差をつけにくくなります。実務では環境ごとにワークスペース(あるいはstateとパイプライン)を分け、環境が上がるほどゲートを厳しくするのが定石です。

環境間でどうコードを昇格させるかは、それ自体が設計テーマです。同じモジュールを変数で切り替えるのか、環境ごとにディレクトリを分けるのか——このあたりは環境昇格(dev→staging→prod)の設計で掘り下げます。stateをどう分割するかはIaCのstate管理とも密接に関わります。

05plan 出力のレビュー — 何を見るか

planをPRに貼るところまでは自動化できます。しかしplanを読むのは人間の仕事です。レビューで見るべき勘所を挙げます。

件数が多すぎるplanは、そもそもレビュー不能です。1PRあたりの変更を小さく保つ、モジュール境界を意識する、といったPR設計そのものが、レビュー可能性を左右します。ブランチ戦略との相性はGitHub Flow / GitLab Flow / トランクベースで扱っています。

06CI のクレデンシャル — ここが最大の急所

パイプラインは本番を書き換える権限を持ちます。ここに長命のアクセスキーをシークレットとして置くのは、最も避けたい構成です。鍵が漏れれば、そのままクラウド全体への侵入経路になります。

現在の一次情報が推す方式は、OIDC(OpenID Connect)による短命クレデンシャルです。GitHub Actionsは、ジョブ実行時にクラウドプロバイダからそのジョブ限りで有効な短命トークンを直接発行してもらえます。長命の認証情報を保存する必要がなくなります(GitHub Docs: OpenID Connect)。

AWS連携では、IAMにGitHubのOIDCプロバイダ(token.actions.githubusercontent.com)を登録し、aws-actions/configure-aws-credentialsでロールをassumeします。ワークフローにはpermissions: id-token: writeが必要です。そしてAWS側の推奨は、ロールの信頼ポリシーでsubクレームを評価し、どのリポジトリ・どのブランチ・どの環境からのassumeを許すかを絞ることです(Configuring OpenID Connect in AWS)。

現場のコツ:OIDCを入れても、信頼ポリシーのsub条件をrepo:org/*のように緩くすると意味が半減します。repo:org/repo:environment:productionまで絞り、本番applyロールはprod用environmentからしかassumeできない形にするのが要点です。権限最小化の実態はIAM最小権限の現実もご参照ください。

加えて、planに使うロールとapplyに使うロールを分ける設計も有効です。planは基本的に読み取り中心、applyは書き込み権限が要る。ロールを分ければ、レビュー段階のパイプラインに過剰な書き込み権限を与えずに済みます。

07ツールの選択肢 — Atlantis / HCP Terraform / 自前CI

型が同じでも、実装手段は複数あります。代表的な三択を、実務判断の軸で整理します。

どれを選ぶかは、運用リソース・既存基盤・統制要件で決まります。マルチアカウント環境で統一的に回すなら、アカウント横断の統制設計と併せて考える必要があります(マルチアカウント統制)。ポリシーをコードで強制したいなら、planに対するPolicy as Codeをパイプラインに組み込む選択もあります。

まとめ

インフラのCI/CDは、アプリのCIの延長では設計できません。守るべきは「テストが緑」ではなく、planが人にレビューされ、承認され、適切な短命権限で、正しい環境に適用されることです。

この型は、Atlantisでも、HCP Terraformでも、自前CIでも実装できます。手段はどれでも構いません。大事なのは、planとapplyの分離・承認ゲート・権限設計という三点を、自社の制約に合わせて確実に組み込むことです。ハンズオンでの設計支援については手が動かせるコンサルという立ち位置もご覧ください。

参考(一次情報)

パイプライン設計や承認フローの整備でお困りの際は、お問い合わせください。現場の制約に合わせた型づくりをご一緒します。

相談する
← ブログ一覧へ戻る