Kubernetesセキュリティ:PSSとAdmission Controllersでルートコンテナを排除する

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

ルート権限で実行されるコンテナのリスク

6ヶ月以上の本番環境でのKubernetes(K8s)運用の末、一般的な脆弱性に気づきました。RedHatのレポートによると、K8sのセキュリティインシデント의 53%は設定ミス(misconfiguration)に起因しています。その多くは複雑な攻撃によるものではなく、コンテナに過剰な権限を与えてしまっていることが原因です。

導入当初、多くのエンジニアは Permission Denied エラーを避けるために privileged: true を設定しがちです。しかし、これは **Container Breakout**(コンテナ脱出)の手がかりとなります。権限を奪取されたコンテナから、攻撃者は物理ノードへ権限昇格し、クラスター全体を制御できるようになります。この問題を解決するため、私は Pod Security Standards (PSS) と Admission Controllers を組み合わせて適用しました。

適切なPodセキュリティツールの選択

Pod Security Policies (PSP) がバージョン1.25で完全に廃止されて以来、主に2つの代替案があります。それぞれの方法には、システムの規模に応じたメリットとデメリットがあります。

1. Pod Security Admission (PSA) – 標準統合ソリューション

PSAは、Kubernetes 1.23以降で標準搭載されている機能です。これは定義済みの PSS 標準セットに基づいて動作します。

  • メリット: 導入が非常に速く、リソースを消費せず、Namespaceにラベルを付与するだけで機能します。
  • 制限: 3つの固定レベル(Privileged, Baseline, Restricted)しかありません。特定のニーズに合わせた独自のルールをカスタマイズすることはできません。

2. Admission Controllers (Kyverno または OPA Gatekeeper)

これらは API Server のリクエスト受信プロセスに直接介入する Webhook です。

  • メリット: 絶対的な柔軟性。すべてのイメージを内部レジストリから取得するように強制したり、作成前にリソース制限(Resource Limit)をチェックしたりできます。
  • 制限: API Server のレイテンシが増加します(1リクエストあたり約10-20ms)。また、クラスター内で追加の中間コンポーネントを管理する必要があります。

実践的なアドバイス: PSAを基盤となる保護レイヤー(baseline)として使用し、複雑なビジネスロジックを処理するために Kyverno を補完として追加してください。

実践的な Pod Security Standards (PSS) の導入

PSSはセキュリティを3つのレベル(Profiles)に分類します。実際のプロジェクトでは、通常のアミプリケーションには Baseline を、機密データを処理するサービスには Restricted を適用することが多いです。

Namespace での PSA の有効化

production-apps という名前空間を保護する必要があるとします。アプリケーションの各YAMLファイルを修正する代わりに、名前空間に直接ラベルを付与してポリシーを強制します。

# 名前空間にRestrictedレベルを適用する
kubectl label --overwrite ns production-apps \
  pod-security.kubernetes.io/enforce=restricted \
  pod-security.kubernetes.io/enforce-version=v1.28

このコマンドを実行すると、API Server はセキュリティ標準に違反する Pod の作成リクエストを即座に拒否するようになります。

検証:安全でない Pod のブロックテスト

特権権限(privileged)で実行される設定の bad-pod.yaml ファイルを作成します。

apiVersion: v1
kind: Pod
metadata:
  name: root-pod
  namespace: production-apps
spec:
  containers:
  - name: nginx
    image: nginx
    securityContext:
      privileged: true # Restrictedレベルに違反

kubectl apply を実行すると、システムは詳細なエラーを返します。この仕組みにより、開発チームはデプロイの最初の段階からセキュリティ設定を標準化せざるを得なくなります。

Kyverno によるセキュリティの最適化

PSAは時として硬直的すぎることがあります。アプリケーションにいくつかの特別な権限が必要な一方で、他のリスクはブロックしなければならないケースがあります。ここで Kyverno が威力を発揮します。

私は、使い慣れた YAML 形式を使用しているため Kyverno を選択しました。これにより、DevOpsチームは OPA の複雑な Rego 言語を学習することなく、ポリシーをコードとして(Policy as Code)簡単に管理できます。

Read-Only Root Filesystem の使用を強制するポリシー

Root Filesystemを read-only モードに強制することで、攻撃者による実行ファイルの書き換えを防ぐことができます。以下は、私がよく適用する実際のポリシーです。

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: enforce-read-only-root-fs
spec:
  validationFailureAction: Enforce
  background: true
  rules:
  - name: check-read-only-root-fs
    match:
      any:
      - resources:
          kinds:
          - Pod
    validate:
      message: "安全確保のために readOnlyRootFilesystem: true の設定が必要です!"
      pattern:
        spec:
          containers:
          - securityContext:
              readOnlyRootFilesystem: true

導入戦略:システムの停止を避ける

最大の失敗は、稼働中のクラスターで即座に Enforce モードを有効にすることです。これにより、多数の Pod が削除され、再起動できなくなり、ダウンタイムが発生する可能性があります。

安全な4つのステップ:

  1. Audit/Warnモード: warn=restricted ラベルを使用して、Podをブロックせずに違反を記録します。
  2. ログ分析: Kyverno または PSA からのログを監視し、標準を満たしていないアプリケーションを特定します。
  3. 設定の標準化: 各チームの Helm Chart または Deployment の securityContext を更新します。
  4. 強制 (Enforce): すべてのアプリケーションが準拠した後にのみ、完全にブロックするモードに切り替えます。

安全な Pod のための標準的な SecurityContext テンプレート

以下は、実際のプロジェクトで私がよく使用する最適な Pod 設定です。

spec:
  securityContext:
    runAsNonRoot: true # rootユーザー(UID 0)をブロック
    runAsUser: 1000    # 特定のユーザーIDで実行
    fsGroup: 2000      
  containers:
  - name: my-app
    image: my-app:v1.0.0
    securityContext:
      allowPrivilegeEscalation: false # 権限昇格をブロック
      capabilities:
        drop: ["ALL"] # 不要なすべての<a href="https://itfromzero.com/ja/security-ja/linux%e3%81%a8docker%e3%82%b3%e3%83%b3%e3%83%86%e3%83%8a%e3%81%aeseccomp%e3%83%97%e3%83%ad%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab%e8%a8%ad%e5%ae%9a%ef%bc%9a%e3%82%b7%e3%82%b9%e3%83%86%e3%83%a0%e3%82%b3.html">Linuxケーパビリティを削除</a>
      readOnlyRootFilesystem: true   # 読み取り専用ファイルシステム

結論

Kubernetes セキュリティは継続的なプロセスです。Pod Security Standards を組み合わせて基盤を構築し、Admission Controllers で詳細を微調整することで、強固な防御層が形成されます。

今日、あなたの Namespace を再確認してください。もしすべてが Privileged 権限で動作しているなら、それは時限爆弾のようなものです。安全で信頼性の高い K8s システムを構築できることを願っています!

Share: