プロンプトとコンテキスト
プラットフォームチームは、外部の mutating webhook を維持することなく、Pod 作成時にデフォルトのセキュリティコンテキストとオブザーバビリティラベルを注入する必要があります。Kubernetes MutatingAdmissionPolicy を使用して、ポリシー、バインディング、競合処理、監査、およびロールバック計画を設計してください。
Kubernetes v1.36 では MutatingAdmissionPolicy が安定版(GA)となりました。これは API サーバー内で CEL を使用してマッチングとミューテーションを記述し、ApplyConfiguration または JSONPatch を使用して受信オブジェクトを変更できます。ポリシー定義とバインディングは分離されています。この面接では、単に webhook マニフェストを書き直すだけでなく、監査可能で可逆的なアドミッションチェーンに宣言的ミューテーションを組み込めるかどうかが評価されます。
面接官が評価するポイント
面接官は、ポリシーとバインディングの明確な境界、ApplyConfiguration と JSONPatch の意図的な使い分け、明示的なフィールド所有権を持つ冪等なミューテーション、failurePolicy、スコープ、順序付け、競合、自己保護、アップグレード、ロールバックの処理、および監査イベントとメトリクスによる根拠を評価します。
明確化のための質問
対象オブジェクトとデフォルト値
Pod のみが対象か、それとも Deployment や Job も対象に含まれるか、どのフィールドが必須のデフォルト値か、どのユーザー値が優先されるか、そしてサービスアカウント、名前空間、ラベルセレクターがどのように変更を制限するかを確認します。
バージョンとランタイムの境界
クラスターが v1.36 であること、admissionregistration.k8s.io/v1 が有効化されていること、既存の webhook がチェーン内に残るかどうか、およびポリシーをクラスター間で再利用する必要があるかどうかを確認します。
リスクとロールバック
保護対象のセキュリティフィールド、許容される障害モード、監査の保持期間、変更ウィンドウ、およびポリシーを無効化した際の既存オブジェクトと新規リクエストへの影響を特定します。
30秒の回答
「ポリシー内でマッチングと冪等なミューテーションを定義し、バインディングを使用して名前空間、リソース、パラメーターのスコープを設定します。ApplyConfiguration は単純な構造化デフォルト値を処理し、JSONPatch は正確な配列操作のために使用します。不一致の場合はスキップされ、ミューテーションエラーは failurePolicy に従います。自己マッチングを防ぎ、RBAC を制限し、ドライラン、狭いバインディング、監査メトリクスを通じてロールアウトします。ロールバック時はバインディングを削除し、バージョン管理されたポリシーを復元します。既存のオブジェクトを勝手に書き直すことはありません。」
ステップバイステップの解決策
ステップ 1: ポリシーとバインディングの分離
ポリシーにはルール、変数、マッチ条件、ミューテーション式を保存します。バインディングはリソースと名前空間を選択し、パラメーターを提供できます。したがって、段階的なロールアウト中に、テナントや環境ごとに異なるバインディングを使用して 1 つのポリシーを再利用できます。
ステップ 2: ミューテーション表現の選択
ApplyConfiguration は、オブジェクトモデルに近い構造化デフォルト値を表現します。JSONPatch は正確なパスの挿入や削除を処理しますが、配列のインデックスと JSON Pointer のエスケープが正確である必要があります。これらを暗黙の上書き戦略に混在させてはならず、すべてのフィールドに所有権と優先順位のルールが必要です。
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingAdmissionPolicy
metadata:
name: pod-default-observability
spec:
matchConstraints:
resourceRules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE"]
resources: ["pods"]
mutations:
- applyConfiguration:
expression: >-
Object{metadata: Object{labels: {"observability.example.com/enabled": "true"}}}
---
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingAdmissionPolicyBinding
metadata:
name: pod-default-observability-binding
spec:
policyName: pod-default-observability
matchResources:
namespaceSelector:
matchLabels:
platform.example.com/enabled: "true"ステップ 3: ミューテーションを冪等かつ非破壊的にする
明示的なユーザー値を保持し、フィールドが存在しない場合にのみデフォルト値を書き込みます。リストについては、キーに基づくマージまたはリスト全体の置換を定義します。再試行、アドミッションの反復、更新によって重複が追加されてはなりません。ミューテーション後のオブジェクトの評価によって同じルールが再びトリガーされ、自己増幅ループが発生しないか確認します。
ステップ 4: マッチングの制限とポリシーの保護
apiGroups、resources、operations、namespaceSelector、objectSelector を使用してスコープを絞り込みます。MutatingAdmissionPolicy は自身やそのバインディングとマッチしてはならず、ポリシーが自身の構成を回復不能な状態に変更するのを防ぎます。ユーザーが提供した CEL パラメーターによって書き込み権限が拡大しないよう、高リスクなフィールドには明示的な許可リストを使用します。
ステップ 5: エラーと順序付けの定義
不一致、空の式結果、ミューテーションエラー、API サーバーの一時的な障害を区別します。failurePolicy で Fail または Ignore を選択し、アラートと組み合わせます。ミューテーター間の暗黙的な順序に依存しないでください。ポリシーが同一フィールドに書き込む可能性がある場合は、フィールドの所有権を分離するか、決定を一元化します。
ステップ 6: Webhook の移行とバージョン管理
シャドウフェーズまたは監査専用フェーズで古い webhook の結果と新しいポリシーを比較し、その後ポリシーを少数の名前空間セットにバインドします。ポリシーバージョン、リクエスト UID、元のオブジェクトのサマリー、およびミューテーションの理由を記録します。競合が把握された後、webhook を段階的に削除し、比較とロールバックのためにバージョン管理されたマニフェストを保持します。
ステップ 7: ロールバックとオブザーバビリティ
緊急ロールバックの場合は、新しいリクエストの変更を停止するためにバインディングを一時停止または削除し、前のポリシーバージョンを復元します。バインディングを削除しても、既存のオブジェクトは逆ミューテーションされません。クリーンアップには、承認された個別のコントローラーまたはバッチプロセスが必要です。アドミッションレイテンシ、拒否率、ミューテーション数、式エラー、名前空間ごとのヒット率を監視します。
模範回答
ポリシーをバージョン管理されたルールとして扱い、バインディングをロールアウトと権限の境界として扱います。選択した名前空間での Pod CREATE にスコープを絞り、不足しているラベルとセキュリティフィールドにのみ冪等なデフォルト値を適用します。正確な配列パスにはテスト済みの JSONPatch を使用します。ロールアウト前に failurePolicy、フィールド許可リスト、RBAC、自己保護を定義します。新旧の結果を比較し、小さな名前空間セットにバインドし、監査、レイテンシ、エラーメトリクスを使用して展開を拡大します。ロールバックではバインディングを削除して以前のポリシーを復元します。既存のオブジェクトは自動的にロールバックされないため、クリーンアップは個別の監査済みプロセスとして行います。
よくある間違い
- 間違い: オブジェクト全体を置き換える。 → 失敗の理由: ユーザーの明示的な構成が消去され、所有権の競合が発生します。 → 修正方法: 不足しているフィールドのみを書き込み、リストのマージルールを定義します。
- 間違い: バインディングを削除すれば古いオブジェクトが復元されると思い込む。 → 失敗の理由: アドミッションはリクエストに影響を与えるものであり、逆ミューテーションを提供するものではありません。 → 修正方法: 独立した監査済みのクリーンアッププロセスを使用し、既存オブジェクトの動作を明記します。
- 間違い: ポリシー間の固定された順序に依存する。 → 失敗の理由: アドミッションの順序変更によって結果が変わる可能性があります。 → 修正方法: フィールドの所有権を分離するか、決定を一元化します。
- 間違い: 本番環境の webhook を即座に置き換える。 → 失敗の理由: ピーク負荷時に式による差異が顕在化する可能性があります。 → 修正方法: まずシャドウイングを行い、名前空間ごとに段階的にロールアウトし、バージョン管理されたマニフェストを保持します。
フォローアップの質問と回答
ApplyConfiguration と JSONPatch のどちらをどのように選びますか?
構造化されたデフォルト値と意図の明確化には ApplyConfiguration を使用します。正確な挿入、削除、またはエスケープされたパスには JSONPatch を使用します。いずれの形式でも、繰り返しの実行と配列の競合をテストしてください。
failurePolicy は常に Fail にすべきですか?
セキュリティベースラインやコンプライアンスフィールドでは、通常 Fail が好まれます。重要度の低いオブザーバビリティラベルでは、明示的なアラートと補償を伴う Ignore を使用できます。この決定は、影響度、可用性目標、監査の根拠に結び付けてください。
ポリシーがオブジェクトを破壊しないことをどのようにテストしますか?
サーバーのドライラン、固定入力スナップショット、アドミッションの反復、名前空間ラベル、事前設定されたユーザーフィールド、空のリスト、式エラーを含むマトリックスを構築し、古い webhook と新しいポリシーの結果を比較します。
代わりにコントローラーを作成しないのはなぜですか?
アドミッションは永続化される前にリクエストをブロックまたは変更するため、デフォルト値の設定や侵入時の制約に適しています。コントローラーは非同期でリコンサイルし、既存のオブジェクトを修復します。これらは相互に補完できますが、コントローラーは侵入時のセキュリティポリシーの代わりにはなりません。