TT Lab
はじめる
学ぶ 学習パス コース

KCSA — Kubernetesセキュリティアソシエイト

Pod Security Admissionをラベルで掛ける

TT Labで続きを見る

目標

ネームスペースのラベルだけでPodのセキュリティポリシーを適用し、restrictedに違反するPodが実際に拒否されることと その拒否メッセージを確認し、最後に等級を上げても、すでに動いているPodは追い出されないという PSAの核心的な性質を、自分で観察します。

なぜ重要なのか

PSPが失敗した理由は、機能が足りなかったからではなく、デバッグが不可能だったからです。 複数のPSPが一致したときにどれが適用されたのかがわかりにくく、mutatingだったために、自分が書いたスペックと 実行されるスペックが違っていました。使われないセキュリティ機能は、セキュリティではありません。

PSAは、その教訓から作られました。ラベル1つでポリシーになり、拒否メッセージに違反したフィールドがすべて出ます。 表現力を失った代わりに運用しやすさを得たトレードオフであり、このトレードオフがなぜ正しかったのかを理解することが、 KCSAでよく問われるポイントです。

ステップ7が、このラボのハイライトです。PSAはアドミッション時にしか動作しないため、 enforceをrestrictedに上げても、すでに動いているPodはそのまま生き残ります。何も起きていないように 見えますが、次のロールアウトやノードの入れ替えのときにPodが起動せず、問題が表面化します。 ポリシーの変更と事故の間には時間差があることを手で確認しておくと、移行を設計するときに違いが出ます。

ステップ

  1. ネームスペースkcsa-psa-baselineを作成し、ラベルを4つ付けます。pod-security.kubernetes.io/enforce=baseline、pod-security.kubernetes.io/enforce-version=v1.30、pod-security.kubernetes.io/audit=restricted、pod-security.kubernetes.io/warn=restrictedです。
  2. ネームスペースkcsa-psa-restrictedを作成し、ラベルを4つ付けます。pod-security.kubernetes.io/enforce=restricted、pod-security.kubernetes.io/enforce-version=v1.30、pod-security.kubernetes.io/audit=restricted、pod-security.kubernetes.io/warn=restrictedです。
  3. kcsa-psa-restrictedに、privilegedコンテナを持つPodbadの作成を試みます。拒否されるはずなので、その拒否メッセージ全体を/root/kcsa-psa/reject.txtに保存します。Podbadは、最後まで作成されていない状態である必要があります。
  4. kcsa-psa-baselineにPodapp-baselineを作成します。イメージはnginx:1.27-alpineで、securityContextは何も指定しません。Runningまで進めます。
  5. kcsa-psa-restrictedにPodapp-restrictedを作成します。イメージはnginx:1.27-alpine、PodレベルにsecurityContext.runAsNonRoot: trueとsecurityContext.seccompProfile.type: RuntimeDefault、コンテナレベルにallowPrivilegeEscalation: false、capabilities.drop: ["ALL"]、runAsUser: 1000を設定します。
  6. /root/kcsa-psa/exempt.yamlにAdmissionConfigurationを書きます。plugins[0].nameはPodSecurity、configuration.kindはPodSecurityConfiguration、defaults.enforceはbaseline、exemptions.namespacesの最初の項目はkube-systemにします。そして/root/kcsa-psa/exempt-note.txtに、PSAの適用除外の3つの軸を1行ずつ、正確にusernames、runtimeClasses、namespacesと書きます。
  7. kcsa-psa-baselineのenforceラベルだけをrestrictedに変更します。そのうえで(a)既存のPodapp-baselineの現在の状態を確認して、/root/kcsa-psa/upgrade.txtにexisting-pod=<상태>の形で書き(プレースホルダーは状態です)、(b)ステップ4と同じスペックのPodapp-baseline2を作成してみて拒否されることを確認したうえで、同じファイルにnew-pod=rejectedの行を追加します。Podapp-baseline2は、作成されていない状態である必要があります。

参考

baselineのネームスペースを作成する

ネームスペースkcsa-psa-baselineを作成し、ラベルを4つ付けてください。pod-security.kubernetes.io/enforce=baseline、pod-security.kubernetes.io/enforce-version=v1.30、pod-security.kubernetes.io/audit=restricted、pod-security.kubernetes.io/warn=restrictedです。

PSAは、ネームスペースのラベルだけで動作します。モードは3つ(enforce/audit/warn)で、これにバージョンを固定するラベルが1つ加わります。enforceは実際に遮断する等級、audit/warnは「上げると何が壊れるか」をあらかじめ見る等級であることを考えながら、値を決めてください。

restrictedのネームスペースを作成する

ネームスペースkcsa-psa-restrictedを作成し、ラベルを4つ付けてください。pod-security.kubernetes.io/enforce=restricted、pod-security.kubernetes.io/enforce-version=v1.30、pod-security.kubernetes.io/audit=restricted、pod-security.kubernetes.io/warn=restrictedです。

前のステップと同じ4つのラベルですが、値はすべて最も厳しい等級です。バージョンのラベルを抜かすと、クラスターをアップグレードするときにポリシーの内容が変わる可能性があります。

restrictedに違反するPodが拒否されるか確認する

kcsa-psa-restrictedに、privilegedコンテナを持つPodbadの作成を試みてください。拒否されるはずなので、その拒否メッセージ全体を/root/kcsa-psa/reject.txtに保存します。Podbadは、最後まで作成されていない状態である必要があります。

このステップの目標は、失敗を作り出すことです。コマンドが失敗するとメッセージは標準エラー出力に出るので、リダイレクトに注意してください。拒否メッセージの中に、どのプロファイルのどのフィールドが問題なのかがすべて書かれています。

baselineだけを通過する平凡なPod

kcsa-psa-baselineにPodapp-baselineを作成してください。イメージはnginx:1.27-alpineで、securityContextは何も指定しません。Runningまで進めます。

特別なセキュリティ設定を1つも入れていない、平凡なPodです。baselineは通過しますが、restrictedの要件は1つも満たしていない状態である必要があります。次のステップと比較するための対照群なので、わざわざ強化しないでください。

restrictedを通過するPod

kcsa-psa-restrictedにPodapp-restrictedを作成してください。イメージはnginx:1.27-alpine、PodレベルにsecurityContext.runAsNonRoot: trueとsecurityContext.seccompProfile.type: RuntimeDefault、コンテナレベルにallowPrivilegeEscalation: false、capabilities.drop: ["ALL"]、runAsUser: 1000を設定します。

4つの要件が必要で、そのうち2つはPodレベルのsecurityContextに、2つはコンテナレベルに入ります。どれがどこに入るのか迷ったら、拒否メッセージが教えてくれます。runAsUserも明示する必要があります。

適用除外の設定と適用除外の軸を整理する

/root/kcsa-psa/exempt.yamlにAdmissionConfigurationを書いてください。plugins[0].nameはPodSecurity、configuration.kindはPodSecurityConfiguration、defaults.enforceはbaseline、exemptions.namespacesの最初の項目はkube-systemにします。そして/root/kcsa-psa/exempt-note.txtに、PSAの適用除外の3つの軸を1行ずつ、正確にusernames、runtimeClasses、namespacesと書きます。

適用除外はネームスペースのラベルでは表現できないため、apiserverのアドミッション設定ファイルに書きます。このラボでは、そのファイルを作成するだけです。適用除外の軸は3つあり、3つの軸がそれぞれ何を基準に検査をスキップするのかを考えてみてください。

ラベルだけを上げたとき、既存のPodはどうなるか

kcsa-psa-baselineのenforceラベルだけをrestrictedに変更してください。そのうえで(a)既存のPodapp-baselineの現在の状態を確認して、/root/kcsa-psa/upgrade.txtにexisting-pod=<상태>の形で書き(プレースホルダーは状態です)、(b)ステップ4と同じスペックのPodapp-baseline2を作成してみて拒否されることを確認したうえで、同じファイルにnew-pod=rejectedの行を追加します。Podapp-baseline2は、作成されていない状態である必要があります。

PSAは、アドミッション時にしか判断しません。この事実が、等級を上げたときの結果を決めます。既存のPodの状態を自分で確認してそのまま書き、同じスペックの新しいPodを作成してみると、対比がはっきりします。