目次
17 章

Admission Controller

K8s API サーバーがマニフェストを etcd に保存する直前の段階で検査・変形する admission のモデルを扱います。Mutating・Validating の2種類、ビルトインコントローラ (LimitRanger・ResourceQuota・PodSecurity など)、Webhook メカニズム、そしてその上に載った2つのポリシーエンジン OPA Gatekeeper (Rego) と Kyverno (YAML) の比較までを一連の流れで整理します。

第14章 RBAC / NetworkPolicy / ResourceQuota で RBAC が K8s API の権限を、NetworkPolicy が Pod 間トラフィックを、ResourceQuota がリソース合計を統制すると整理しました。本章のテーマはその上にもう一層載るポリシーの肌合いです — マニフェスト自体の形を強制するポリシー です。「limits のないコンテナは作れない」「イメージは自社の ECR レジストリからのみ受け取らなければならない」「すべてのワークロードに owner ラベルが必須だ」のような規則は RBAC だけでは表現できません。このような規則が入る場所が K8s API サーバーの Admission 段階 であり、その段階にポリシーエンジンを差し込む2つのツールが OPA Gatekeeper と Kyverno です。

本章の終わりには 「cluster-admin の束を禁止」「limits のないコンテナを拒否」「owner ラベルを強制」のような運用ポリシーをマニフェスト次元で強制する道 が手に入ります。第14章 §「よくある罠 — 広すぎる ClusterRole」で押さえたアンチパターン遮断の本格的なツールが本章で開きます。

Admission 段階 — マニフェストが etcd に入る直前 #

kubectl apply -f my-pod.yaml を打った瞬間からそのマニフェストが etcd に保存されるまでの流れは単純な一行ではありません。K8s API サーバーは次の5つの段階を順に通過させます。

K8s APIサーバーのリクエスト処理の流れ
1. 認証 (Authentication)         — 誰が呼び出したか
2. 権限 (Authorization)          — RBAC検査。呼び出し元がこの動詞・リソースを使えるか
3. Mutating Admission            — マニフェストを変形 (defaulting, sidecar注入等)
4. Validating Admission          — マニフェストがポリシーを満たすか
5. etcd保存

3、4段階が本章のテーマである Admission Controller です。認証と RBAC を通過したリクエストであってもこの段階で拒否されることがあり、保存される前にマニフェスト自体が変形されることがあります。

Mutating vs Validating #

2種類の違いは明確です。

  • Mutating Admission — マニフェストを 変形 します。例: すべての Pod に sidecar コンテナを自動注入、欠けたラベルの自動補完、デフォルト値の適用。同じオブジェクトに複数の mutating controller が順に適用されることがあります。
  • Validating Admission — マニフェストを 検査するだけ です。通過または拒否。変形は起きません。すべての mutating が終わった後の最終マニフェストを見るという点が重要です。

順序は常に mutating → validating です。変形がすべて終わったマニフェストが検査段階に渡されるので、validating ルールは「最終形態がポリシーを満たすか」だけを評価すればよいです。

ビルトイン Admission Controller #

K8s API サーバーの中にはすでに複数の admission controller がコンパイルされています。運用クラスタでよく出会うものを押さえておきます。

コントローラ種類役割
NamespaceLifecycleValidating削除中のネームスペースへのオブジェクト生成を遮断
LimitRangerMutating + ValidatingLimitRange のデフォルト値の適用 + 違反を拒否
ResourceQuotaValidatingResourceQuota の合計超過時に拒否
ServiceAccountMutatingPod に default ServiceAccount を自動付着
PodSecurityValidatingPod Security Standards を強制 (1.25+ stable)
DefaultStorageClassMutatingPVC にデフォルト SC を自動補完

第11章 resources.requests / limits の LimitRange と 第14章 の ResourceQuota が実際に動作する段階がこの admission 段階です。マニフェストが ResourceQuota の合計を超えると ResourceQuota admission controller が4段階で拒否します。ビルトインコントローラは --enable-admission-plugins API サーバーフラグで有効化・無効化されます。

Webhook — 外部から admission 段階に割り込む #

ビルトインコントローラは K8s コードに内蔵されているのでユーザーが定義を変えられません。運用チームが自分だけのポリシーを admission 段階に差し込みたければ Webhook を使います。2種類があります。

  • MutatingWebhookConfiguration — 外部 HTTP サービスにマニフェストを送り、そのサービスが変形されたマニフェストを返します。
  • ValidatingWebhookConfiguration — 外部 HTTP サービスにマニフェストを送り、そのサービスが allow / deny を返します。

K8s API サーバーはこの webhook の呼び出し結果を見てリクエストをそのまま通過させるか変形するか拒否します。OPA Gatekeeper と Kyverno はどちらもこの webhook メカニズムの上に載ったポリシーエンジン です。K8s に新しい admission の種類を追加するのではなく、標準 webhook をうまく使えるように抽象化したツールです。

OPA Gatekeeper — Rego で表現するポリシー #

OPA (Open Policy Agent) は K8s 外でも使われる汎用ポリシーエンジンです。Rego という独自言語でポリシーを書き、OPA エンジンがそのポリシーを評価します。Gatekeeper は OPA を K8s admission webhook で包んだツールです。

Gatekeeper の核心オブジェクトは2つです。

  • ConstraintTemplate — Rego で書いたポリシーの青写真。「こういう種類のポリシーを定義する」
  • Constraint — ConstraintTemplate のインスタンス。「このポリシーをどのリソースにどんなパラメータで適用する」

この2つの分離が Gatekeeper のモデルです。ポリシーの「形」は ConstraintTemplate に一度書いておき、その形にパラメータを入れて何度もインスタンス化する方式です。2つのオブジェクトとも K8s の CRD で実装されているという点は 第18章 CRD と Operator パターン のモデルの上にポリシーエンジンが載った形であることを押さえておきます。

ConstraintTemplate の例 — 必須ラベルの強制 #

constrainttemplate-required-labels.yaml
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8srequiredlabels
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredLabels
      validation:
        openAPIV3Schema:
          type: object
          properties:
            labels:
              type: array
              items:
                type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequiredlabels

        violation[{"msg": msg}] {
          required := input.parameters.labels
          provided := input.review.object.metadata.labels
          missing := required[_]
          not provided[missing]
          msg := sprintf("Missing required label: %v", [missing])
        }

rego ブロックの中のコードが本当のポリシーです。input.review.object は admission 段階のマニフェストで、input.parameters は Constraint から渡したパラメータです。violation[...] が空でなければマニフェストが拒否されます。ConstraintTemplate を適用すると K8s に K8sRequiredLabels という新しい CRD ができます。

Constraint の例 — 上のテンプレートのインスタンス #

constraint-require-owner.yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
  name: namespace-must-have-owner
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Namespace"]
  parameters:
    labels: ["owner", "team"]

この Constraint を適用するとその瞬間から新しく作るすべての Namespace に ownerteam ラベルがなければ admission 段階で拒否されます。

ラベルのないNamespace生成の試み
$ kubectl create ns test
Error from server (Forbidden): admission webhook "validation.gatekeeper.sh" denied the request:
[namespace-must-have-owner] Missing required label: owner
[namespace-must-have-owner] Missing required label: team

Gatekeeper の付加機能 #

Gatekeeper にはポリシー評価のほかにいくつかの運用フレンドリーな機能があります。

  • dry-run / audit モード — Constraint の enforcementAction: dryrun で適用すると拒否せず violation だけを記録します。ポリシーを本番サービスに強制適用する前に影響範囲を測定するのに使います。
  • Config オブジェクトで評価対象を制限kube-system のようなシステムネームスペースを評価から除外できます。
  • 外部データ referrer — Constraint が OPA の data オブジェクトを参照して他の K8s オブジェクトや外部データを見てポリシーを評価できます。

Kyverno — YAML で表現するポリシー #

Kyverno は OPA Gatekeeper と同じカテゴリのツールですがアプローチが違います。新しい言語を学ばずに YAML でポリシーを書く というのが Kyverno の最大の差別化点です。K8s ユーザーはすでに YAML に慣れているので、ポリシー導入の参入障壁が低いです。

Kyverno の3つの動作 #

Kyverno のポリシーは3つのうち1つ (またはそれ以上) を行います。

  • validate — マニフェストが規則を満たすか検査 (Validating Admission)
  • mutate — マニフェストを変形 (Mutating Admission)
  • generate — 他のオブジェクトを自動的に作り出す (Kyverno だけの機能)

generate は admission 段階自体の動作ではありませんが、「Namespace が作られたらその中にデフォルトの NetworkPolicy を自動生成」のようなパターンを1つのポリシーで表現します。第14章 の default-deny + allow-dns の束を新しいネームスペースに自動で敷いておくような運用パターンが一般的な例です。

Validate の例 — limits のないコンテナを拒否 #

policy-require-limits.yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-resource-limits
spec:
  validationFailureAction: Enforce
  rules:
    - name: require-cpu-memory-limits
      match:
        any:
          - resources:
              kinds: ["Pod"]
      validate:
        message: "Pod must have CPU and memory limits."
        pattern:
          spec:
            containers:
              - resources:
                  limits:
                    memory: "?*"
                    cpu: "?*"

pattern の中の ?* は「どんな値でもよいが空であってはならない」という意味です。このポリシーが適用されるとすべての新しい Pod のすべてのコンテナに limits.cpulimits.memory がすべて書かれていなければなりません。第11章 で扱ったリソースモデルを admission 次元で強制するパターンで、LimitRange の defaultRequest / default と対にしておくとマニフェストのリソース表記を強制できます。

Mutate の例 — すべての Pod にラベルを自動追加 #

policy-add-labels.yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: add-default-labels
spec:
  rules:
    - name: add-managed-by
      match:
        any:
          - resources:
              kinds: ["Deployment", "StatefulSet"]
      mutate:
        patchStrategicMerge:
          metadata:
            labels:
              managed-by: platform-team

このポリシーが適用されるとマニフェストに managed-by ラベルがなくても admission 段階で自動的に追加されます。コード1行も変えずにラベル標準を強制する道です。

Gatekeeper vs Kyverno — 2つのうちどちらを使うか #

2つのツールの比較を1つの表に整理します。

次元OPA GatekeeperKyverno
ポリシー言語Rego (新しく学ぶ必要あり)YAML
表現力非常に高い (チューリング完全な Rego)普通 (宣言的パターンマッチング)
学習曲線低い
ポリシー動作validate, mutate (1.0+)validate, mutate, generate, cleanup
K8s 外のポリシーOPA 自体は K8s 外でも使用可能K8s 専用
ポリシーライブラリ豊富 (gatekeeper-library)豊富 (kyverno/policies)

選択の肌合い は普通次の肌合いを辿ります。

  • Rego の学習負担を引き受けられ、同じポリシーエンジンを K8s 外でも使いたいなら Gatekeeper が自然です。大きな組織でポリシーの一貫性を複数のシステムにまたがって持っていくときに有利です。
  • K8s 運用チームがポリシーを直接書いて保守したいなら、ポリシー作成自体の参入障壁が最大のコストなら Kyverno が速いです。導入初月の学習コストの違いが大きいです。

2つのツールとも運用規模で回った実績が十分です。表現力が圧倒的に必要な場合でなければ Kyverno を先に検討し、Rego の表現力が本当に必要になった時点で Gatekeeper へ移る流れも自然です。

運用時に固めておく原則 #

Admission webhook を導入するとき運用面で必ず固めておくべき原則をいくつか押さえます。

1. failurePolicy の2つの選択 — Fail vs Ignore #

webhook を呼び出せないとき (タイムアウト、ネットワーク断、ポリシーエンジン Pod のダウン) API サーバーがどう振る舞うかを定めるフィールドです。

  • failurePolicy: Fail — webhook が応答できなければリクエストを拒否。ポリシーが迂回されることはありませんが、ポリシーエンジンの可用性がクラスタ全体の可用性に直結します。ポリシーエンジンが死ぬと新しいワークロードを起動できません。
  • failurePolicy: Ignore — webhook が応答できなければそのまま通過。可用性はよいですがポリシーが迂回されます。

運用の正攻法は 重要なポリシーは Fail、付随的なポリシーは Ignore に分けておくことです。そしてポリシーエンジン自体を多重化 (replicas 2以上) し、PodDisruptionBudget で保護するのが基本です。第30章 アップグレード戦略 の PDB が本章の webhook 可用性と直接つながります。

2. namespaceSelector でシステムネームスペースを除外 #

kube-systemkube-public のような K8s 自体のワークロードが回るネームスペースは普通ポリシー評価から除外します。クラスタの起動自体がポリシーに阻まれる事故を防ぐ安全装置です。

webhookのnamespaceSelectorの例
namespaceSelector:
  matchExpressions:
    - key: kubernetes.io/metadata.name
      operator: NotIn
      values: ["kube-system", "kube-public", "kube-node-lease"]

3. dry-run で漸進的に導入 #

運用クラスタに新しいポリシーをすぐ enforce モードで適用すると既存ワークロードの update が次々と壊れることがあります。標準の流れは次の通りです。

ポリシー導入の正攻法
1. dry-runモードで適用 (Gatekeeperのdryrun, KyvernoのAudit)
2. 一定期間violationログを収集 → 影響範囲を測定
3. 違反ワークロードを優先的に整理
4. enforceモードへ切り替え

この流れを飛ばすと既存のマニフェストが次々と拒否されて GitOps 同期が止まる事故につながります。ポリシーの意図が正しくても導入手順は漸進的でなければなりません。GitOps との接続パターンは 第20章 GitOps でもう一度扱います。

4. webhook latency の監視 #

Admission webhook はすべてのマニフェスト変更の critical path にあります。ポリシーエンジンが遅くなると kubectl apply も一緒に遅くなります。Gatekeeper / Kyverno ともに自前のメトリクスを公開するので、P99 latency と拒否率を 第19章 可観測性 で扱う可観測性スタックに連動させておくのが標準です。

練習問題 #

  1. 自分のクラスタに適用された admission controller を確認します (kubectl get validatingwebhookconfigurationskubectl get mutatingwebhookconfigurations)。そのうち Kyverno または Gatekeeper があればどんな ClusterPolicy / Constraint が適用されているかを1つの表に整理し、第14章 の RBAC・NetworkPolicy・ResourceQuota とどんな肌合いで違うポリシーかを一段落で比較します。
  2. Kyverno または Gatekeeper をローカルクラスタにインストールし、「すべての Pod のすべてのコンテナに limits.cpu / limits.memory がなければならない」ポリシーを dry-run モードで適用します。limits の抜けた Deployment を apply したとき admission 段階でどんなメッセージが violation として記録されるかをキャプチャし、同じポリシーを enforce モードに変えたとき同じマニフェストがどう拒否されるかを段階別に記録します。第11章 の LimitRange と本章のポリシーの責任がどう違うかを一段落で整理します。
  3. failurePolicy: Fail に設定された webhook が応答できないときのシナリオをシミュレーションで書いてみます — ポリシーエンジン Pod がすべて死んだとき新しい Deployment を apply するとどんなエラーが出るか、そして failurePolicy: Ignore だったらどんな違いが出るか。ポリシーエンジンの可用性がクラスタの可用性とどう連動するかを §「failurePolicy の2つの選択」のモデルで整理します。

一行まとめ: K8s API サーバーはマニフェストを etcd に保存する前の admission 段階で mutating (変形) → validating (検査) の順に通過させる。ビルトインコントローラ (LimitRanger・ResourceQuota・PodSecurity など) のほかに webhook で外部のポリシーエンジンを差し込め、2つの標準が OPA Gatekeeper (Rego, 表現力強) と Kyverno (YAML, 参入障壁低) だ。運用導入は failurePolicy・システムネームスペースの除外・dry-run の漸進的導入・webhook latency の監視の4原則で支える。

次の章 #

本章の Gatekeeper と Kyverno がどちらも K8s の CRD (CustomResourceDefinition) で定義された新しいオブジェクト種類 の上に載っているという点を一度押さえておきました。ConstraintTemplateK8sRequiredLabelsClusterPolicy のようなオブジェクトは K8s 本体の標準オブジェクトではなく、2つのツールが CRD で定義したユーザー定義リソースです。次の章のテーマはその CRD 自体です — K8s API を新しいオブジェクト種類で拡張する道

第18章 CRD と Operator パターン では CustomResourceDefinition で新しいオブジェクト種類を定義するマニフェスト、そのオブジェクトを運用する controller-runtime ベースの Operator パターン、そして運用で出会う代表的な Operator (CloudNativePG・cert-manager・Argo CD など) のモデルまでを一連の流れで扱います。本章までが K8s の標準オブジェクトを扱う深さだったとすれば、次の章は K8s 自体を自分のドメインに合わせて拡張する道の出発点です。

X