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

ポリシーをコードで

必須ラベルとレジストリ制限のポリシーを書く

TT Labで続きを見る

目標

必須ラベルを要求する検証ポリシーと、レジストリを制限する拒否ルールを自分で書き、通過・失敗の判定とポリシーレポートをローカルで確認します。最後に、正当な例外を狭い範囲で表現します。

なぜ重要なのか

検証ポリシーで事故を起こすのは、条件式ではなくマッチ範囲です。条件が間違っていればテストで引っかかりますが、マッチが間違っていると、ポリシーが黙って何もしないため、誰も気づきません。そのため、通過すべきリソースとブロックされるべきリソースの両方を入れてみることが、ポリシー作成の基本です。もう1つ、拒否メッセージはポリシーの半分です。デプロイをブロックされた人が見られるのは、kubectl applyが出力した1行だけで、その1行が不親切だと、ポリシーの運用コストがすべて問い合わせとして返ってきます。最後に、この環境にはポリシーエンジンのコントローラーが起動していないため、クラスターは誤ったPodを実際にはブロックしません。判定は、kyverno applyでローカルで確認し、採点も、ポリシーのYAMLの構造とその実行結果を見ます。

ステップ

  1. /root/policy/validate/require-labels.yamlを作成してください。apiVersion: kyverno.io/v1、kind: ClusterPolicy、metadata.nameはrequire-labelsです。spec.validationFailureActionをEnforceに(または、ルールのvalidate.failureActionをEnforceに)、spec.backgroundをtrueにして、spec.rules[0].nameをcheck-required-labelsと名付けてください。
  2. 同じルールに、match.any[0].resources.kindsでPodを、namespacesでpol-labを指定してください。そして、ルールにexclude.any[0].resources.namespacesでkube-systemを除外してください。
  3. validate.pattern.metadata.labelsの下に、app.kubernetes.io/nameとteamの2つのラベルを、それぞれ"?*"で要求してください。同じvalidateにmessageを入れますが、15文字以上にして、何を直すべきかがわかるように書いてください。
  4. kyverno apply /root/policy/validate/require-labels.yaml --resource /opt/lab/fixtures/policy/resources/good-pod.yamlを実行して、結果を/root/policy/validate/out/pass.txtに保存してください。結果に、require-labelsというポリシー名と通過の表示が見える必要があり、失敗の件数は0である必要があります。
  5. 同じポリシーを/opt/lab/fixtures/policy/resources/bad-pod.yamlで実行して、/root/policy/validate/out/fail.txtに保存してください(失敗の件数は1以上、ポリシー名を含む)。そして、/root/policy/validate/out/fail-note.txtに、どのラベルがなくて引っかかったかを、韓国語で書いてください。
  6. /root/policy/validate/restrict-registry.yamlに、2つ目のClusterPolicyを作成してください。ルールにvalidate.deny.conditions.all(またはany)を使い、許可するレジストリとしてregistry.labhub.ioを入れて、それ以外のイメージを拒否するようにしてください。そのあと、/opt/lab/fixtures/policy/resources/bad-registry.yamlで実行した結果を、/root/policy/validate/out/registry.txtに保存してください(拒否/失敗が見える必要があります)。
  7. restrict-registry.yamlのルールに、preconditionsを追加してください。{{ request.operation }}のようなリクエストコンテキストの変数を使って、CREATE・UPDATEのときだけルールが動くようにします。そして、/root/policy/validate/out/precondition-note.txtに、preconditionsとdenyの違いを書いてください。preconditionsが偽ならルールがスキップされる点と、denyはルールが実行された結果として拒否する点の、両方が入っている必要があります。
  8. require-labels.yamlを、good-podとbad-podの両方を--resourceで入れて、--policy-reportで実行し、/root/policy/validate/out/policy-report.yamlに保存してください(summary.passは1以上、summary.failは1以上)。そして、/root/policy/validate/exception.yamlにkind: PolicyExceptionを作成して、spec.exceptions[0].policyNameをrequire-labels、ruleNamesをcheck-required-labels、spec.match.any[0].resources.namesをlegacy-batch-*のように名前単位で絞ってください。

参考

ポリシーの骨組みと強制モードを決める

/root/policy/validate/require-labels.yamlを作成してください。apiVersion: kyverno.io/v1、kind: ClusterPolicy、metadata.nameはrequire-labelsです。spec.validationFailureActionをEnforceに(または、ルールのvalidate.failureActionをEnforceに)、spec.backgroundをtrueにして、spec.rules[0].nameをcheck-required-labelsと名付けてください。

ClusterPolicyは、kyverno.ioグループのCRDです。失敗時にブロックするか記録だけにするか、そして既存のリソースも検査の対象にするかは、specで決めます。

適用対象と除外対象を絞る

同じルールに、match.any[0].resources.kindsでPodを、namespacesでpol-labを指定してください。そして、ルールにexclude.any[0].resources.namespacesでkube-systemを除外してください。

matchは、anyの下にresourcesで、種類とネームスペースを書きます。セットになるexcludeを抜かすと、システムネームスペースまで対象になります。

必須ラベルのパターンと拒否メッセージを書く

validate.pattern.metadata.labelsの下に、app.kubernetes.io/nameとteamの2つのラベルを、それぞれ"?*"で要求してください。同じvalidateにmessageを入れますが、15文字以上にして、何を直すべきかがわかるように書いてください。

patternは、検査するオブジェクトと同じ形で書きます。「あるだけでよい」という意味の演算子が、別にあります。メッセージは、拒否された人が読む唯一のドキュメントです。

通過すべきPodで実行してみる

kyverno apply /root/policy/validate/require-labels.yaml --resource /opt/lab/fixtures/policy/resources/good-pod.yamlを実行して、結果を/root/policy/validate/out/pass.txtに保存してください。結果に、require-labelsというポリシー名と通過の表示が見える必要があり、失敗の件数は0である必要があります。

kyverno CLIは、ポリシーファイルと、--resourceで受け取ったマニフェストを、ローカルで評価します。結果にポリシー名が見えるように、出力形式を選んでください。

違反するPodで実行して、原因を書く

同じポリシーを/opt/lab/fixtures/policy/resources/bad-pod.yamlで実行して、/root/policy/validate/out/fail.txtに保存してください(失敗の件数は1以上、ポリシー名を含む)。そして、/root/policy/validate/out/fail-note.txtに、どのラベルがなくて引っかかったかを、韓国語で書いてください。

通過だけを確認しても、何にもマッチしないポリシーと区別できません。失敗があると、終了コードが1になる点も、覚えておいてください。

レジストリを制限するdenyルールを書く

/root/policy/validate/restrict-registry.yamlに、2つ目のClusterPolicyを作成してください。ルールにvalidate.deny.conditions.all(またはany)を使い、許可するレジストリとしてregistry.labhub.ioを入れて、それ以外のイメージを拒否するようにしてください。そのあと、/opt/lab/fixtures/policy/resources/bad-registry.yamlで実行した結果を、/root/policy/validate/out/registry.txtに保存してください(拒否/失敗が見える必要があります)。

「リストの中になければ拒否」のような条件は、patternでは表現しにくいです。conditionsの下のanyとallのどちらが合っているか、考えてみてください。

preconditionsでルールの適用範囲を絞る

restrict-registry.yamlのルールに、preconditionsを追加してください。{{ request.operation }}のようなリクエストコンテキストの変数を使って、CREATE・UPDATEのときだけルールが動くようにします。そして、/root/policy/validate/out/precondition-note.txtに、preconditionsとdenyの違いを書いてください。preconditionsが偽ならルールがスキップされる点と、denyはルールが実行された結果として拒否する点の、両方が入っている必要があります。

preconditionsが偽なら、ルールは評価すらされません。denyと何が違うのかを、ファイルに整理して、はじめて通過します。

ポリシーレポートと狭い例外を作る

require-labels.yamlを、good-podとbad-podの両方を--resourceで入れて、--policy-reportで実行し、/root/policy/validate/out/policy-report.yamlに保存してください(summary.passは1以上、summary.failは1以上)。そして、/root/policy/validate/exception.yamlにkind: PolicyExceptionを作成して、spec.exceptions[0].policyNameをrequire-labels、ruleNamesをcheck-required-labels、spec.match.any[0].resources.namesをlegacy-batch-*のように名前単位で絞ってください。

通過1件と失敗1件が、1つのレポートの要約に一緒に入るには、リソースを両方入れる必要があります。例外は、ポリシー名・ルール名・リソース名まで絞ってください。