Admission Controlとポリシー実行(Webhook/CEL)
危険な設定をクラスタに入る前に止めたい。API サーバーの admission webhook と CEL・OPA/Gatekeeper・Kyverno が、どの順序でリクエストを検証・改変するかを原理から解説。
- 1.admission は認証・認可の後、etcd 保存の直前に走る。mutating(改変)が先、validating(検証)が後で、その間にスキーマ検証が挟まり、validating の後はオブジェクトを変えられない。
- 2.外部 webhook は API サーバーが HTTP で呼ぶ同期処理。failurePolicy・timeout・matchConditions の設計を誤ると、全 API 操作が詰まる。
- 3.ポリシー実行は CEL(API サーバー内蔵)、OPA/Gatekeeper(Rego)、Kyverno(YAML)の3系統。webhook 不要の CEL が最も軽く、複雑な判定ほど外部エンジンが要る。
admission control とは何か
Kubernetes の API サーバーは、クライアントから来たリクエスト(Pod を作る、Deployment を更新する等)を、そのまま etcd に書き込むわけではありません。書き込みの 直前 に、リクエストを横取りして検査・改変する関門があります。これが admission control(受け入れ制御) です。
ここで重要なのは「いつ」走るかです。API サーバーの処理は固定された順序を持ちます。
- 認証(Authentication):誰からのリクエストか確認する。
- 認可(Authorization):その人にこの操作の権限があるか判定する(RBAC など)。
- mutating admission:リクエストの 内容 を改変する(後述)。
- スキーマ検証:改変後のオブジェクトが OpenAPI スキーマに沿うか検証する。
- validating admission:内容を検査して可否を返す(後述)。これを通れば
etcdに保存される。
認可は「操作してよいか(誰が何をできるか)」を見るのに対し、admission は「その内容が妥当か(この Pod は特権コンテナを使っていないか、ラベルが付いているか)」を見ます。RBAC では表現できない、オブジェクトの中身に踏み込んだルール強制がここで可能になります。
admission control が走るのは、状態を変える書き込み系の操作(create / update / delete / connect)だけです。get / list / watch といった読み取りリクエストは admission を通りません。ポリシーで「閲覧を禁止」したい場合は admission ではなく認可(RBAC)の領域になります。
mutating と validating:2段構えとその順序
admission には2種類のフェーズがあり、順序が決まっている ことが設計の根幹です。
- mutating(変更)admission:先に走る。リクエスト中のオブジェクトを 書き換えられる(デフォルト値の注入、サイドカーの追加、ラベルの付与など)。
- validating(検証)admission:後に走る。オブジェクトを 見て可否だけを返す。受理(allow)か拒否(deny)かで、内容は変えない。
なぜ mutating が先なのか。validating は「最終的に保存される姿」を検査する必要があるからです。もし validating の後に mutating が改変したら、検証を通り抜けたオブジェクトが検証後に書き換わり、検証が無意味になります。だから順序は 必ず mutating → validating で固定され、validating フェーズを通過したオブジェクトはもう改変されません。
API サーバー内部では、この2フェーズの間に 再エンコード/再検証 が挟まります。全 mutating プラグインが適用された結果のオブジェクトが、validating に渡される確定形になります。
複数の mutating webhook がある場合、それらの 実行順序は保証されません。webhook A がラベルを足し、webhook B がそのラベルを前提に動く、という依存を組むと壊れます。さらに、ある webhook の出力が別の webhook の入力になるため、相互作用でオブジェクトが意図せぬ形になることがあります。API サーバーは安定化のため mutating を最大で複数回(reinvocation)呼ぶ設定も持ちますが、冪等(何度適用しても同じ結果)に作るのが鉄則です。
webhook の仕組み:API サーバーが外部を呼ぶ
組み込みの admission プラグイン(NamespaceLifecycle など)はコンパイル済みでカーネルに固定ですが、ユーザーが独自ルールを足す主流の手段が admission webhook です。ValidatingWebhookConfiguration / MutatingWebhookConfiguration というリソースで登録します。
動作はシンプルで、しかし危険です。マッチするリクエストが来ると、API サーバーが webhook サーバーに対して同期的に HTTPS POST を送ります。ボディは AdmissionReview オブジェクト(対象リソース・操作種別・ユーザー情報を含む)。webhook は許可/拒否(mutating なら JSON Patch 付き)を AdmissionReview で返します。
この「API サーバーが外部 HTTP を待つ」という構造が、設計上の最大の注意点を生みます。
| 設定項目 | 意味 | 誤ると起きること |
|---|---|---|
| failurePolicy | webhook 応答失敗時に Fail(拒否)か Ignore(許可)か | Fail にして webhook が落ちると、対象 API 操作が全滅する |
| timeoutSeconds | 応答を待つ上限(最大30秒) | 長すぎると API のレイテンシ悪化、短すぎると誤拒否 |
| rules | どの resource/operation を捕まえるか | 広すぎると無関係なリクエストまで webhook を呼ぶ |
| matchConditions | CEL で対象をさらに絞る前段フィルタ | 未設定だと webhook サーバー側に負荷が集中する |
| sideEffects | webhook が外部状態を変えるか宣言 | 誤申告すると dry-run が正しく動かない |
failurePolicy: Fail の webhook が、自分自身の動作に必要なリソース(例:kube-system の Pod)まで捕まえる設定だと、webhook サーバーがダウンしたとき復旧用の Pod すら作れず、クラスタが自己ロックします。回避策は (1) 自分の namespace を namespaceSelector で除外、(2) objectSelector で対象を限定、(3) 重要 namespace を matchConditions で素通しさせる、など。webhook を入れる=API サーバーの可用性に依存先を増やす、と意識してください。
CEL:webhook なしでポリシーを書く
webhook は柔軟ですが、外部サーバーの運用・証明書・可用性という重荷を伴います。これを避けるために、API サーバーに CEL(Common Expression Language) が組み込まれました。ValidatingAdmissionPolicy(および mutating 版)として、外部プロセスなしに API サーバー内でポリシーを評価します。
CEL は安全な式言語で、ループや任意 I/O を持たず、評価コストに上限がある(チューリング完全ではない)よう設計されています。これにより API サーバー内で安全に同期評価でき、webhook のような外部呼び出し・ネットワーク往復・障害点がありません。
# webhook 不要。API サーバー内で CEL を評価
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: replica-limit
spec:
matchConstraints:
resourceRules:
- apiGroups: ["apps"]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["deployments"]
validations:
- expression: "object.spec.replicas <= 5" # replicas が 5 以下のみ許可
message: "replicas は 5 以下にしてください"
CEL は軽量で障害点が増えない一方、表現力に限界があります。外部データ参照(「この Image は脆弱性スキャンを通ったか」を別 DB に問い合わせる等)や複雑なロジックは苦手で、そこは依然 webhook +外部エンジンの出番です。判断軸は「API サーバー内で完結する単純な不変条件は CEL、外部知識や複雑な合成判断は webhook」です。
OPA/Gatekeeper・Kyverno:ポリシーエンジンの3系統
実務では、生の webhook を自作するより ポリシーエンジン を webhook の背後に置くのが一般的です。代表が OPA/Gatekeeper と Kyverno で、CEL を加えた3系統を比べると性格がはっきりします。
| 観点 | CEL(内蔵) | OPA / Gatekeeper | Kyverno |
|---|---|---|---|
| 配置 | API サーバー内蔵(webhook 不要) | validating webhook の背後に常駐 | validating/mutating webhook の背後に常駐 |
| 記述言語 | CEL 式 | Rego(専用宣言型言語) | Kubernetes YAML(CRD) |
| 得意領域 | 単純な不変条件の検証 | 複雑な論理・横断的ルール | K8s 特化、mutate/generate も得意 |
| 学習コスト | 低(式のみ) | 高(Rego の習得が必要) | 中(YAML で書ける) |
| 外部障害点 | なし | webhook サーバーがある | webhook サーバーがある |
- OPA/Gatekeeper:汎用ポリシーエンジン OPA を Kubernetes 用に包んだもの。ルールは Rego で書き、
ConstraintTemplate(ルールの型)とConstraint(適用パラメータ)に分離する設計です。Kubernetes 以外でも使える汎用性が強みですが、Rego の学習コストが高めです。 - Kyverno:Kubernetes 専用に作られ、ポリシーを YAML(CRD) で書きます。新言語を学ばずに済み、検証(validate)だけでなく 改変(mutate) や 生成(generate:namespace 作成時に既定の NetworkPolicy を自動生成等) も同じ枠組みで書けるのが特徴です。
3つとも本質は同じ「admission のタイミングでオブジェクトを検査・改変する」仕組みで、違いは どこで評価するか(内蔵か外部か)と 何で書くか(CEL/Rego/YAML)です。
「mutating と validating はどちらが先か」「admission は認可の前か後か」は頻出です。覚え方は 認証 → 認可 → mutating → validating → 保存 の一本道。admission は書き込み系のみに作用し、読み取りには効きません。CEL を webhook と対比して「外部障害点を持たない内蔵評価」と説明できると上級者向けの加点になります。
配置上の設計指針
admission を入れる際は、可用性とのトレードオフを常に意識します。
- まず CEL を検討:API サーバー内で完結する単純なルール(ラベル必須、replicas 上限、特権コンテナ禁止)は CEL で書き、外部依存を増やさない。
- webhook は対象を絞る:
matchConditions(CEL 前段フィルタ)・namespaceSelector・objectSelectorで、本当に必要なリクエストだけを捕まえる。捕まえる範囲が広いほど API 全体のレイテンシと障害リスクが増えます。 - failurePolicy を意図的に選ぶ:セキュリティ強制系(特権 Pod 拒否など)は
Fail(webhook が落ちたら拒否=安全側)、補助的なラベル付与などはIgnore(落ちても素通し)と、ルールの性質で使い分けます。 - 冪等に作る:mutating は順序保証がなく再呼び出しもあるため、何度適用しても同じ結果になるよう設計します。
admission はサービスメッシュのサイドカー自動注入(/devops/service-mesh/)の正体でもあり、デプロイ戦略(/devops/deployment-strategies/)の安全ガードや、CI/CD(/devops/ci-cd/)でクラスタ手前で弾けない実行時ポリシーの最後の砦としても機能します。「クラスタに入る前」に強制できるからこそ、構成のドリフトを設計段階で封じられるのが admission control の価値です。
まとめ
- admission は 認証・認可の後、
etcd保存の直前 に走り、書き込み系操作の 内容 を検査・改変する関門。 - フェーズは mutating(改変が先)→ validating(検証が後) で固定。validating 通過後はオブジェクトを変えられない。
- webhook は API サーバーが同期 HTTP で外部を呼ぶ ため、
failurePolicy・timeout・対象範囲の設計を誤るとクラスタごと詰まる。 - ポリシー実行は CEL(内蔵・軽量)/OPA・Gatekeeper(Rego)/Kyverno(YAML) の3系統。単純な不変条件は CEL、複雑・外部依存の判断は webhook +エンジンで使い分ける。
DevOps/インフラ Article
Admission Controlとポリシー実行(Webhook/CEL)を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
Kubernetes
比較で見る軸
難易度: advanced / カテゴリ: DevOps/インフラ / タグ数: 5
導入後に効く点
外部 webhook は API サーバーが HTTP で呼ぶ同期処理。failurePolicy・timeout・matchConditions の設計を誤ると、全 API 操作が詰まる。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- DevOps/インフラ
- タグ数
- 5
判断チェックリスト
- 自社の用途が「Kubernetes / Admission Control」に近いか確認する。
- 強みである「admission は認証・認可の後、etcd 保存の直前に走る。mutating(改変)が先、validating(検証)が後で、その間にスキーマ検証が挟まり、validating の後はオブジェクトを変えられない。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。