パイプライン外で起きるインフラ変更:ドリフト、ポリシー、実践的なガバナンス
こんな状況を想像してみてください。あなたは午前2時にオンコール対応中です。本番環境でインシデントが発生し、チームの誰かが接続問題をデバッグするために、一時的にセキュリティグループのポートを開放する必要があります。その人はクラウドコンソールにログインして変更を行い、インシデントは解決されました。全員が安堵の息をつきます。
3週間後、定例のセキュリティ監査中に、そのポートがまだインターネット全体に開放されたままであることが判明します。誰も閉じるのを忘れていたのです。誰も変更を記録していません。そして、あなたのInfrastructure as Code(IaC)パイプラインは、そのセキュリティグループがロックダウンされたままであると認識しています。
これがインフラストラクチャドリフトです。これは実際のシステムを運用するすべての組織で発生します。問題はそれが起こるかどうかではなく、起こったときにどう対処するかです。
手動変更を禁止してもうまくいかない理由
明白な解決策は「すべての手動変更を禁止する。すべての変更はパイプラインを通さなければならない。例外は認めない」ということのように思えます。
実際には、このアプローチは3つの理由で失敗します。
第一に、緊急事態は発生します。本番システムがダウンしているときに、15分かかるパイプラインの実行を待つことは許容できません。エンジニアは直接変更を行う方法を見つけますし、それができるべきです。
第二に、すべての変更が同じではありません。リソースにタグを追加したり、説明を更新したりすることは、データベースのセキュリティグループを変更することとは根本的に異なります。これらを同列に扱うと、リスクの低い変更に対して不必要な摩擦が生じます。
第三に、強制は困難です。クラウドコンソールにアクセスできる人がボタンをクリックするのを物理的に防ぐことはできません。そして、コンソールアクセスを完全に削除すると、正当なトラブルシューティングのボトルネックが生まれます。
より良いアプローチは、手動変更を禁止することではなく、それをガバナンスすることです。
ポリシーアズコード:自己強制するルール
ほとんどの組織にはインフラ変更に関するポリシーがあります。それらは通常、どこかのドキュメントに「本番環境へのすべての変更は変更管理プロセスを経由しなければならない」と書かれています。しかし、ドキュメントは何も強制しません。ただそこにあるだけです。
ポリシーアズコードはこれを変えます。Open Policy Agent(OPA)やHashiCorp Sentinelのようなツールを使用すると、ルールをコードで記述し、それを強制ポイントにアタッチできます。誰かがクラウドコンソールを通じてリソースを変更しようとしたり、APIコールが直接送られてきた場合、ポリシーエンジンはリクエストをルールに照らして評価し、許可するかどうかを判断します。
具体的な例を示します。「承認されたパイプラインからの変更でない限り、どのセキュリティグループもポート22を0.0.0.0/0に開放してはならない」というポリシーを記述します。インシデント発生時にパニックになったエンジニアがAWSコンソールからSSHを全世界に開放しようとすると、ポリシーがその変更をブロックします。あるいは最低限、その試行をログに記録し、追加の承認を要求します。
例えば、以下はHashiCorp Sentinelポリシーで、すべてのリソースに managed-by タグを必須とし、パイプライン外の変更を追跡可能にします。
# すべてのリソースに "managed-by" タグを必須とする
import "tfplan/v2" as tfplan
# 作成または更新されるすべてのリソースを取得
all_resources = tfplan.resource_changes.all
# ルール: すべてのリソースに "managed-by" タグが必要
mandatory_tag = "managed-by"
main = rule {
all all_resources as _, rc {
rc.applied.tags[mandatory_tag] else null != null
}
}
このポリシーはCI/CDパイプラインにガードとして統合されます。タグなしでリソースがデプロイされるとパイプラインが失敗し、追跡されていない変更が本番環境に到達するのを防ぎます。
このアプローチは2つの利点をもたらします。第一に、人間の規律に依存しない明確な境界。第二に、自動監査証跡です。すべてのポリシー決定が記録されます。誰が、いつ、どこから、何を変更しようとし、それが許可されたか拒否されたかが記録されます。
プレッシャー下でも機能するポリシーの設計
よくある間違いは、ポリシーを硬直的にしすぎることです。すべての手動変更を例外なくブロックするポリシーは、エンジニアが完全にバイパスする方法を見つける状況を生み出します。あるいはさらに悪いことに、実際の緊急時に行動することを恐れるようになります。
解決策は、運用の現実を考慮したポリシーを設計することです。
1つのパターンは、ブレイクグラス(緊急時突破)メカニズムです。特定の緊急事態において、エンジニアはポリシーをオーバーライドできます。オーバーライドは理由とともに記録され、インシデント後にチームはその変更をIaCに取り込むかロールバックするかをレビューします。これにより、麻痺することなく安全性を確保できます。
別のパターンは、リスクによる変更の分類です。タグの追加、説明の更新、重要でない設定の変更などの低リスク変更は自由に許可します。ネットワークアクセス、セキュリティポリシー、データベース設定の変更などの高リスク変更は、必ずパイプラインを通さなければなりません。ポリシーエンジンがこの区別を自動的に強制するため、毎回人間が判断する必要はありません。
ポリシーとドリフト検出の連携
ポリシーとドリフト検出は、連携することで最も効果を発揮します。実際の流れは次のようになります。
ドリフトスキャナーが定期的に実行され、IaC定義と実際のインフラの差異を検出します。システムはすべての差異を問題としてフラグする代わりに、各差異をポリシーに照らしてチェックします。
次の図は、ポリシー適用とドリフト検出が継続的なガバナンスループでどのように相互作用するかを示しています。
変更が承認されたポリシー例外を通じて行われた場合、「既知かつ許可済み」としてマークされます。変更がポリシーに違反している場合、即時是正のためにフラグが立てられます。変更がいずれのポリシールールにも一致しない場合、手動レビューのキューに入れられます。
これにより、チームのドリフトの見方が変わります。ドリフトはもはや修正すべき単なるミスではありません。解釈すべきシグナルです。これはまだコードに取り込まれていない正当な緊急変更でしょうか?ポリシー違反でしょうか?パイプラインを通るべきだったが通らなかった変更でしょうか?
ポリシーとガバナンスを導入することで、各変更を手動で調査することなく、これらのケースを区別できます。そして、ポリシーはコードとして記述されているため、他のコードと同様にレビュー、バージョン管理、テストが可能です。共有フォルダに眠る埃をかぶったドキュメントではありません。
ポリシー駆動型ガバナンスの実践的チェックリスト
インフラ変更のためのポリシーとガバナンスを設定する場合、以下のチェックリストを検討してください。
- 環境内で最もリスクの高い変更の種類を特定する(セキュリティグループ、データベース設定、IAMロールなど)
- それらの変更をパイプライン外でブロックするポリシーを記述し、明確な例外パスを設ける
- 緊急時用のブレイクグラスメカニズムを実装し、インシデント後のレビューを必須とする
- ポリシーエンジンをドリフト検出ツールに接続する
- 変更をリスクレベルで分類し、それに応じて異なるルールを適用する
- すべてのポリシー決定に対して自動監査ログを設定する
- ポリシー例外を定期的にレビューし、IaCに取り込むかロールバックする
まとめ
インフラストラクチャドリフトは、一度解決すれば終わりの問題ではありません。継続的に管理すべき状態です。目標はすべての手動変更を排除することではなく、それらを把握し、ガバナンスし、どれをインフラの恒久的な一部とするかを決定することです。
ポリシーアズコードは、正当な作業を妨げることなく境界を強制する方法を提供します。ドリフト検出は、実際に何が起こっているかを可視化します。これらが連携することで、インフラ管理は、午前2時に何かがうまくいかなくなった場合でも信頼できるシステムへと変わります。