KyvernoによるKubernetesセキュリティポリシー:本番環境でのAdmission Controlの適用

Security tutorial - IT technology blog
Security tutorial - IT technology blog

課題:Kubernetesの設定不備が生む見えない混乱

8つのエンジニアリングチーム、450以上のPodが稼働する3つの本番クラスタにおいて、私たちのデプロイ速度は非常に高速でした。しかし、セキュリティのガードレールは実質的に皆無の状態でした。ある定期監査において、root権限で実行されている14のワークロード、完全なprivileged: trueホストアクセスを持つ2つのトラブルシューティング用Pod、そしてCPUおよびメモリ制限が完全に欠落している多数のDeploymentが発見されたのです。

Kubernetesでアドミッション制御(Admission Control)を設定しないまま運用することは、インターネットに向けてrootのSSHログインを公開しているようなものです。プルリクエストのレビューや手動のチェックリストだけに頼る運用は、チームが1日に30件ものデプロイを実行するようになれば破綻します。設定の不備は必然的にすり抜けてしまいます。私たちは、リスクのある設定がワーカーノードに到達する前にAPIサーバーの境界で即座に拒否する、自動化されたガードレールを必要としていました。

当初はOpen Policy Agent(OPA)Gatekeeperを検証しました。機能としては優れていたものの、Rego言語でポリシーを作成・保守することは、開発者やプラットフォームエンジニアにとって余計な学習コストとなりました。その摩擦がきっかけとなり、私たちはKyvernoの導入へと舵を切ることになりました。

基本概念:なぜKyvernoはネイティブなKubernetesワークフローに適しているのか

Kyvernoはクラスタ内で動的アドミッションコントローラーとして動作します。Kubernetes APIサーバーのValidatingAdmissionWebhookおよびMutatingAdmissionWebhookエンドポイントに登録され、リソースの作成、更新、削除リクエストのたびにマニフェストを検査します。

ドメイン固有言語(DSL)を必要とする他のエンジンとは異なり、Kyvernoポリシーは標準的なKubernetesのカスタムリソース定義(CRD)です。チームがYAMLでPodスペックを書く方法を知っていれば、すでにKyvernoポリシーの書き方も理解していると言えます。

4つのポリシーモード

  • Validate(検証): 流入するマニフェストをルールに照らし合わせて評価します。Enforceモードでは非準拠のリクエストをブロックし、Auditモードでは警告をログに記録しながら許可します。
  • Mutate(変更): リソースが永続化される前に動的に変更を加えます。デフォルトのセキュリティコンテキストの挿入、コストセンター用ラベルの付与、サイドカーの追加などが代表的なユースケースです。
  • Generate(生成): トリガーイベントに応じて補助リソースを自動作成します。例えば、Namespaceが作成された際にデフォルトのNetworkPolicyやRoleBindingを自動プロビジョニングします。
  • Verify Images(イメージ検証): アドミッション時にCosign/Sigstoreキーに照らしてコンテナ署名を検証し、SBOM(ソフトウェア部品表)のアテストをチェックします。

実践ガイド:Kyvernoのデプロイとクラスタのセキュリティ保護

クラスタ全体で特権コンテナを排除し、非rootでの実行を強制するために私たちが実際にデプロイした構成とポリシーセットを以下に示します。

ステップ1:HelmによるKyvernoのインストール

公式のHelmチャートを使用して、Kyvernoを専用の名前空間にインストールします。本番環境では、クラスタのアップグレード中も高可用性を維持するために3つのレプリカを実行します。

# KyvernoのHelmリポジトリを追加および更新
helm repo add kyverno https://kyverno.github.io/kyverno/
helm repo update

# 高可用性(HA)レプリカ構成でKyvernoをデプロイ
helm install kyverno kyverno/kyverno \
  --namespace kyverno \
  --create-namespace \
  --set replicaCount=3

コントローラーのPodが正常に稼働し、Webhookが登録されていることを確認します。

kubectl get pods -n kyverno
kubectl get validatingwebhookconfigurations,mutatingwebhookconfigurations

ステップ2:特権コンテナの遮断(バリデーションルール)

privileged: trueを設定すると、コンテナの分離機構が無効化され、ホストカーネルへのほぼ完全なアクセス権が付与されてしまいます。以下のClusterPolicyは、クラスタ全体で特権コンテナをブロックします。

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: disallow-privileged-containers
  annotations:
    policies.kyverno.io/title: 特権コンテナの禁止
    policies.kyverno.io/category: Pod Security Standards
    policies.kyverno.io/severity: high
    policies.kyverno.io/description: >-
      特権コンテナはホストOSとroot権限を共有します。
      このポリシーはコンテナが特権モードで実行されないように制限します。
spec:
  validationFailureAction: Enforce
  background: true
  rules:
    - name: validate-privileged
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        message: "特権モードでの実行は固く禁じられています。securityContext.privileged を false に設定してください。"
        pattern:
          spec:
            containers:
              - =(securityContext):
                  =(privileged): "false"

クラスタにポリシーを適用します。

kubectl apply -f disallow-privileged-containers.yaml

ステップ3:非root実行を強制するためのリソースの自動変更(ミューテーション)

開発者がセキュリティコンテキストの宣言を忘れるたびにデプロイを拒否するのではなく、ミューティングポリシーを活用します。このポリシーは、フィールドが存在しない場合に自動的にrunAsNonRoot: trueを挿入します。

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: mutate-non-root-execution
spec:
  rules:
    - name: set-run-as-non-root
      match:
        any:
          - resources:
              kinds:
                - Pod
      mutate:
        patchStrategicMerge:
          spec:
            securityContext:
              runAsNonRoot: true

ステップ4:リアルタイムでのポリシー適用のテスト

ホスト特権を設定したテスト用Podをデプロイしてみて、ポリシーの適用状況を確認します。

apiVersion: v1
kind: Pod
metadata:
  name: rogue-priv-pod
spec:
  containers:
    - name: alpine-test
      image: alpine:latest
      command: ["sleep", "3600"]
      securityContext:
        privileged: true

kubectlを使用してマニフェストを送信します。

kubectl apply -f rogue-priv-pod.yaml

APIサーバーは即座にアドミッションをブロックし、設定したカスタムエラーメッセージを返します。

Error from server: error when creating "rogue-priv-pod.yaml": admission webhook "validate.kyverno.svc" denied the request:

policy Pod/default/rogue-priv-pod for resource violation:

disallow-privileged-containers:
  validate-privileged: 特権モードでの実行は固く禁じられています。securityContext.privileged を false に設定してください。

ステップ5:PolicyReportによる既存ワークロードの監査

Kyvernoは、リアルタイムのAPI呼び出しをインターセプトするだけでなく、稼働中のワークロードに対する定期的なバックグラウンドスキャンも実行します。PolicyReportカスタムリソースを使用して、クラスタのコンプライアンス状況を直接確認できます。

kubectl get clusterpolicyreports -o wide
kubectl describe policyreport -n default

このレポートはポリシー適用前にデプロイされた非準拠のワークロードを特定するため、チームは予期せぬシステム停止を引き起こすことなく、設定の乖離(ドリフト)を段階的に修正できます。

本番環境で6か月運用した振り返り

過去6か月間で、Kyvernoはクラスタ全体で20万件以上のアドミッションリクエストを処理し、平均Webhookレイテンシは4ミリ秒未満を維持しました。その間、ランタイムに達する前に47件の無効または特権設定を検出し、遮断することに成功しました。

ポリシーが標準的なKubernetes YAMLで記述されているため、開発者はアドミッション拒否の理由を理解するために独自のDSLを学習する必要がありません。エラーメッセージを確認し、デプロイマニフェストを修正して作業を続行できます。運用のオーバーヘッドなしに堅牢なクラスタガバナンスを実現したい場合、Kyvernoはまさに最適な選択肢となります。

Share: