OPA(Open Policy Agent)とRegoをパイプラインに組み込む際、「どこに置くか」と「いつ評価させるか」という2つの問いに先に答えを出さないと、ポリシーが形骸化するか、逆にデプロイの障害になるかのどちらかに行き詰まります。本記事では、コード化対象の絞り込みからエンジン選定、評価タイミングの設計、違反ハンドリング、更新フロー、複数チームのガバナンスまで、構築担当者が押さえるべき設計判断の軸を整理します。
ポリシーをコード化する対象の選定と除外基準の設計
コード化に適したポリシーの3条件
ポリシーをコードとして管理するメリットは、レビュー可能・差分追跡可能・自動評価可能になることです。この3つが揃わない場合は、コード化のコストに見合いません。コード化に向くのは「評価基準が論理的に記述できる」「繰り返し評価される」「チームを横断して適用する」の3条件が揃う場合です。たとえば「KubernetesリソースにsecurityContextを設定する」「S3バケットにパブリックACLを付けない」といったルールはこの条件を満たします。一方で、属人的な判断や文脈依存度の高いルール、例えば「このサービスの特性上パフォーマンスを優先する」といった判断はコード化に向きません。
除外すべきポリシーの判断軸
コード化から除外すべきポリシーの第一基準は「変更頻度と複雑度の積」です。変更頻度が高くかつ複雑なポリシーは、コードの陳腐化リスクとメンテナンスコストが高くなります。想定例として、月に3回以上業務要件が変わるルールを厳格なポリシーコードで管理すると、ポリシー変更のリードタイムが設定変更の2倍以上になりやすく、現場が迂回手段を探し始める悪循環が生まれます。除外の第二基準は「評価の主体が人間であること」です。セキュリティインシデントへの対応方針や新規サービスの設計レビューのような判断はコードで表現できません。これらは別のドキュメント管理や承認フローに任せるのが適切です。
ポリシー棚卸しの進め方とコード化率の目安
既存の規約・チェックリスト・レビュー指摘の過去ログを素材に、「自動判断できるか」「全環境に共通適用できるか」「変更頻度は月1回以下か」の3軸でスコアリングします。3軸すべて満たすものをフェーズ1のコード化対象にし、2軸以下は様子見にとどめます。一般的には、既存のセキュリティチェックリストの30〜40%程度がコード化対象として絞り込まれます。残りの60〜70%を無理にコード化しようとすると、ポリシーリポジトリの複雑度が増すだけで自動評価の恩恵が薄れます。
OPA・Sentinel・CUEのポリシーエンジン比較表
エンジン選定の前提条件と先行すべき確認事項
エンジンを選ぶ前に、「誰がポリシーを書くか」「どのインフラツールと統合するか」「評価をリアルタイムで行うか」の3点を確定させます。この前提が曖昧なままエンジンを選ぶと、後から別の評価タイミングを追加しようとしたときにアーキテクチャを作り直すことになります。特にRegoの習得コストは見落とされやすい落とし穴です。宣言的な論理プログラミング言語であるRegoは、手続き型言語に慣れた担当者にとって直感に反する挙動を取ることがあります。チームにRego経験者がゼロの場合、習得に2〜4週間の学習コストを見込んでおく必要があります。
エンジン比較表
| 比較項目 | OPA(Rego) | Sentinel(HashiCorp) | CUE |
|---|---|---|---|
| 言語 | Rego(宣言的論理言語) | 独自DSL(Sentinelポリシー言語) | CUE(制約記述言語) |
| 主な統合先 | Kubernetes・OCI・HTTP API | Terraform Cloud・Vault・Consul | Kubernetes CRD・設定ファイル検証 |
| 評価タイミング | 柔軟(CI〜ランタイム) | 主にデプロイ前(Terraformプラン時) | 主に静的検証(スキーマ整合) |
| 学習コスト | 高(Rego固有の記法) | 中(直感的なDSL) | 中(Go開発者には馴染みやすい) |
| テスト機能 | 組み込み(opa test) | 組み込み(mock+assert) | 組み込み(eval/export) |
| ライセンス | OSS(Apache 2.0) | 商用(Terraform Cloud前提) | OSS(Apache 2.0) |
| 向いているケース | マルチツール・汎用ポリシーゲート | Terraform中心のインフラ管理 | 設定スキーマ検証・型定義の強制 |
選定後のアーキテクチャ上の注意点
OPAをHTTPサイドカーとして動作させる場合、評価レイテンシが増します。高トラフィック環境で毎リクエストに評価をかける設計にすると、応答時間に影響が出ます。評価対象のデータ量が大きくなるとメモリ使用量も増えるため、ランタイム評価はポリシーの種類を絞るか非同期評価に切り替える設計を検討します。Sentinelはすでにterraform cloudを利用している環境では統合コストが低い半面、ロックインが強くなります。CUEはスキーマ検証には優れますが、ランタイムポリシーゲートとして使うには追加の設計が必要です。
評価タイミング(PR・CI・デプロイ前・ランタイム)の設計判断
PR時評価とCI評価の役割分担
PR時評価はポリシー違反を最も早い段階で検出できますが、全ポリシーをここに集中させると開発フローが重くなります。PR時に置くべきは「コード化されたリソース定義の静的違反」、具体的にはTerraformのtfファイルやKubernetesマニフェストへの機械的なルール適用です。実行時の状態に依存するポリシーはPR時に評価できないため対象外にします。CIパイプラインでの評価は「ビルド済みアーティファクトやプランファイルへの評価」に向いています。Terraformならterraform planの出力に対してconftestやOPA CLIで評価し、プランに含まれる変更セットが許容範囲かを確認します。
デプロイ前評価のゲート設計
デプロイゲートとしてOPAを配置する場合、評価のタイムアウト設定が重要です。デプロイパイプライン全体のSLAを崩さないために、ポリシー評価に割り当てる時間を明示的に設計します。一般的な目安として、デプロイ前評価のタイムアウトは30秒以内に収めることが推奨されます。これを超える場合はポリシーの複雑度を見直すか、評価対象のデータを分割します。ポリシー評価の結果はデプロイログに残し、後からどのポリシーがどの理由でデプロイを通過・阻止したか追跡できる設計にします。
ランタイム評価の適用判断
ランタイム評価(OPA SidecarまたはEnvoy external authorization)は、動的なコンテキスト(JWTクレーム・リクエストヘッダ・現在の環境変数)に基づく判断が必要な場合に適しています。静的なルール(「このリソースタグは必須」)はランタイム評価に持ち込まず、デプロイ前で完結させます。ランタイム評価はポリシーの更新を動的に反映できる反面、OPAのバンドル配信の遅延(数秒〜数十秒)を設計上の制約として認識しておく必要があります。バンドルの更新頻度と遅延許容度を事前に決め、ランタイム評価を導入するかどうかの判断基準にします。
Regoテストの書き方とカバレッジ目標の設計
テスト設計の基本方針
Regoポリシーのテストは、「許可されるべきケース」と「拒否されるべきケース」の両方を同数程度書くことが基本方針です。拒否ケースだけのテストでは、ポリシーが「常に拒否する壊れた実装」になっていても通過してしまいます。これはよくあるつまずきです。テストデータは実際のリソース定義から抜粋・匿名化したものを使うと、現実に近いケースを確認できます。架空のシンプルすぎるテストデータでは、実際のJSONスキーマの入れ子構造でRegoの参照が失敗するケースを見逃しやすくなります。
カバレッジ目標の設定方針
OPAにはopa test –coverageオプションがあり、ルールのカバレッジを数値で確認できます。カバレッジ目標はポリシーの重要度に応じて変えることが合理的です。セキュリティ系ポリシー(IAMロール・パブリックアクセス・暗号化設定)は80%以上、運用系ポリシー(タグ付与・命名規則)は60%以上を目安に設定するパターンが一般的です。100%を一律に目指すと、テストのためのテストになりやすくメンテナンスコストが跳ね上がります。目標値はチームで合意したうえでCIに組み込み、下回った場合はビルドを警告扱いにするところから始めます。
Regoテストの落とし穴
Regoのテストで特に注意すべきは、「undefinedとfalseを混同すること」です。OPAではルールがundefinedを返す場合とfalseを返す場合で挙動が異なります。allow := falseとallow { false }は同じではなく、テストが意図しない方向で通過することがあります。ポリシー設計の初期段階でデフォルト値(default allow := false)を明示することでこの混乱を避けられます。もう一つの落とし穴は、Regoのimport文の解決順序です。パッケージ分割が複雑になるとimportのパスが意図せずオーバーライドされることがあり、テスト環境でのみ再現するバグの原因になります。
ポリシー違反の扱い方(blocking vs warning)設計
blocking/warningの選択基準
ポリシー違反をblockingにするかwarningにするかは、「この違反がシステムの安全性・コンプライアンスに直接関わるか」で判断します。セキュリティグループのポート開放ルール、IAMポリシーのワイルドカード付与、パブリックバケットの作成禁止はblockingが妥当です。一方でタグの命名規則違反やリソース上限の推奨値超過はwarningから始め、段階的に強化します。よくあるつまずきとして、新規ポリシーを最初からblockingにして既存リソースが大量に違反していることが発覚しデプロイが止まるケースがあります。新規ポリシーの追加は原則warningから始め、違反件数を計測したうえでblockingに昇格させるフローを標準にします。
blocking昇格の条件と判断フロー
新規ポリシーのblocking昇格は「violation数がゼロになってから」ではなく「警告が一定件数以下になり既知の例外を整理したうえで移行する」という基準で設計します。警告件数をゼロにしてから移行しようとすると、既存リソースの修正が追いつかずにblocking化が無期限延期になりがちです。想定例として「warning期間2週間・未対応違反が全対象リソースの5%以内」という数値基準を昇格条件として設けることで、ポリシー強化の意思決定を迷わず進められます。
- 新規ポリシーはwarningで開始する
- warning期間中に違反件数・違反理由を記録する
- 例外リストに含める違反と修正すべき違反を分類する
- 既知の例外をポリシーコードに明示的に記述する
- 昇格条件(期間・違反率)を定義し関係チームに通知する
- 条件を満たした時点でblockingに切り替え、翌デプロイで動作を確認する
違反ログの活用設計
ポリシー違反のログはOPAのdecision logとして収集できます。このログを単なる記録として扱うのではなく、ポリシーの実効性測定に使います。警告が長期間放置されているポリシーは「実際には不要なポリシーである可能性」のシグナルです。逆に特定のチームで違反が集中している場合は、ポリシーの適用範囲や例外処理の設計を見直すきっかけになります。decision logは構造化データとして出力できるため、ダッシュボードに取り込んでポリシー別の違反傾向を可視化する設計にするとガバナンス管理が楽になります。
ポリシーの更新フローとレビュー承認の設計
変更トリガーと承認ルートの設計
ポリシーコードの変更トリガーは大きく3種類です。「コンプライアンス要件の改定」「インフラ構成の変更に伴うポリシー追加」「違反ログ分析による見直し」です。それぞれ重要度が異なるため、承認ルートも分けて設計します。コンプライアンス起因の変更はセキュリティ担当のレビューを必須にし、運用調整は変更内容に応じてチームリードのみで承認できる設計にするとリードタイムを短縮できます。PRテンプレートに「変更の種別(コンプライアンス/運用/緊急)」のフィールドを設け、CIで自動的に承認ルートを振り分ける設計が有効です。
ロールバック設計
ポリシーのロールバックは通常のアプリケーションデプロイよりも即時性が求められる場合があります。誤ったblockingポリシーがデプロイされると、パイプライン全体が止まるためです。OPAのバンドル管理では、以前のバンドルバージョンをすぐに参照できる設計にしておきます。Gitタグによるバージョン管理と合わせて、バンドルのイミュータブルなバージョニングを設計の前提にします。ロールバック手順は手動操作を最小化し、CIパイプラインから旧バージョンのバンドルを即座に再デプロイできる仕組みを用意します。
バージョン管理と後方互換性の設計
ポリシーを更新する際は、適用対象のインフラ定義との後方互換性を確認します。KubernetesマニフェストのフィールドやTerraformプロバイダーの属性名が変わった場合に、Regoの参照パスが無効になります。これはテストでは検出しにくく、ステージング環境での事前評価をポリシー更新フローに組み込みます。ポリシーのセマンティックバージョニング(MAJOR.MINOR.PATCH)を導入し、破壊的変更はメジャーバージョンアップとして扱うと変更の影響範囲を関係者が把握しやすくなります。
複数チームがポリシーを共有する際のガバナンス設計
ポリシーの所有権モデルの設計
複数チームがポリシーを共有する場合、「共通ポリシー」と「チーム固有ポリシー」を階層で分離する設計が有効です。共通ポリシーはプラットフォームチームが所有し、全チームに強制適用されます。チーム固有ポリシーは各チームが管理し、共通ポリシーの範囲内であればチームの判断で追加・削除できます。この二層構造にすることで、全社的なセキュリティ基準を維持しながら各チームの自律性を確保できます。ポリシーリポジトリを単一の中央リポジトリで管理するか各チームのリポジトリに分散するかも設計判断です。一般的には中央リポジトリに共通ポリシーを集め、チーム固有ポリシーは各リポジトリに持たせる「ハイブリッド型」が採用されるケースが多いです。
チーム間の依存関係の整理
ポリシーが複数チームにまたがる場合、あるポリシーの変更が別チームのデプロイに影響することがあります。特に共通ポリシーをblockingで強化する場合は、影響を受けるチームへの事前通知と移行期間の設計が必要です。変更の影響範囲を可視化するために、OPAのbundleを環境(dev/staging/prod)ごとに分け、まずdevに適用してから順に昇格させるフローを設計します。変更通知のチャネルも設計に含め、ポリシーリポジトリのPRが作成されたタイミングで影響を受けるチームにSlackやメールで通知する自動化を入れると、見逃しを防げます。
ガバナンス崩壊のアンチパターン
複数チームのポリシー管理で特に注意すべきアンチパターンが3つあります。第一は「例外が積み重なりポリシーが形骸化すること」です。例外はコード(例外リストのポリシーファイル)として管理し、理由と有効期限を明示することで無期限の例外が蓄積するのを防ぎます。第二は「ポリシー所有者が不明確になること」です。誰もレビューしないPRが増えるとポリシーコードの品質が低下します。CODEOWNERSでポリシーファイルのレビュー担当を明示することが有効です。第三は「ポリシーリポジトリが実インフラと乖離すること」です。ポリシーと適用対象のバージョン対応表を管理し、四半期に一度など定期的な棚卸しサイクルを設けることで、参照されなくなった死んだポリシーの蓄積を防げます。
▶ 手を動かして本番まで到達する
脱属人化の第一歩は「読める・書けるスクリプト」から始まります
ここまでの設計判断は、読めば腹に落ちます。ですが「自分の手で本番まで通しきる自信」は、それとは別の話になります。
自動化の設計を、手を動かして身につける2日間です。手順書に閉じ込めた構築を、他人が読めて再現できる形へ変えていきます。
ポリシーのコード管理設計をスクリプトで実践するシェルスクリプト実践コースへ →
シェルスクリプトマスターセミナー|自動化の設計を手で身につける2日間