既定値を埋めてくれる変形ポリシーを書く
目標
抜けている値を埋めてくれるミューテーションポリシーを3つの方式で書き、すでに指定された値には触れないことを、自分で確認します。最後に、何がどう変わったかの照合レポートを作ります。
なぜ重要なのか
ブロックするだけのポリシーは、問題をユーザーに押し付けます。リミットのないPodをすべて拒否すると、ルールは守られますが、チームごとに「いくつ入れればよいですか」という質問が生まれます。ミューテーションポリシーは、組織のデフォルト値を代わりに埋めることで、ルールを守りながら、誰もブロックしません。ただし、ここには越えてはいけない線があります。ユーザーが明示した値は絶対に上書きしないことです。チームがcpu: 500mと書いたのに、ポリシーが黙って変えてしまうと、そのチームは自分のマニフェストを信じられなくなり、その時からポリシーは、信頼ではなく恐怖の対象になります。そのため、追加アンカー+()は構文の飾りではなく、契約です。なお、この環境にはアドミッションWebhookが動いていないため、ミューテーションはkyverno CLIでローカルに評価して、結果のマニフェストを確認します。
ステップ
/root/policy/mutate/add-team-label.yamlにkind: ClusterPolicyを作成してください。spec.backgroundを明示し、spec.rules[0].mutate.patchStrategicMerge.metadata.labelsの下に+(team): unassignedを入れてください。ルール名はadd-default-team、マッチはpol-labネームスペースのPodです。/root/policy/mutate/add-defaults.yamlに2つ目のポリシーを作成し、+(...)の追加アンカーで、コンテナのresources.limitsに、cpuとmemoryのデフォルト値を埋めるルールを書いてください。そして、/root/policy/mutate/out/anchors.md(150バイト以上)に、条件アンカー()、追加アンカー+()、そして=()またはX()の違いを整理してください。- 同じ
add-defaults.yamlに、mutate.patchesJson6902を使うルールをもう1つ入れてください。op: addとpath: /spec/containers/0/imagePullPolicy、value: IfNotPresentの形です。そして、/root/policy/mutate/out/json6902-note.txtに、この方式が配列・インデックスを扱うときになぜ必要なのかを書いてください。 add-defaults.yamlに、mutate.foreachルールを入れてください。list: "request.object.spec.containers"でコンテナのリストを受け取り、内部でelement変数で現在の項目を指す必要があります。- 2つのポリシーを
/opt/lab/fixtures/policy/resources/bad-pod.yamlに適用して、ミューテーションされたPodマニフェストを/root/policy/mutate/out/mutated.yamlに保存してください。そのファイルには、metadata.labels.team、spec.containers[0].resources.limits.memory、spec.containers[0].imagePullPolicyの3つの値が、すべて埋まっている必要があります。 - 同じ2つのポリシーを
/opt/lab/fixtures/policy/resources/good-pod.yamlに適用して、/root/policy/mutate/out/preserved.yamlに保存してください。このPodには、もともとteam: platformラベルとcpu: 500mの制限があり、ミューテーションの後もそのままである必要があります。 /root/policy/mutate/mutate-existing.yamlを作成してください。spec.mutateExistingOnPolicyUpdate: trueを置き、ルールのmutate.targetsにkind: Pod、namespace: pol-labを書いて、トリガーではないリソースを修正するようにしてください。そして、/root/policy/mutate/out/existing-note.txtに、この動作がバックグラウンドで動くため、追加のRBAC権限が必要であることを書いてください。/root/policy/mutate/out/mutate-report.jsonを作成してください。最上位のmutations配列に3件以上を入れ、各項目は、field・before・after・ruleの4つのキーを持つ必要があります。beforeとafterが同じ項目は入れないでください。fieldにteamが含まれる項目のafterの値は、ステップ5で作ったmutated.yamlのmetadata.labels.teamの値と、正確に同じである必要があります。
参考
- ポリシーファイルを複数、一度に渡せます。
kyverno apply <정책1> <정책2> --resource <매니페스트>(プレースホルダーは順に、ポリシー1、ポリシー2、マニフェストです)です。 - ミューテーション結果のマニフェストは、出力オプションで受け取るか、出力からPodのドキュメント部分だけを切り出して保存すればよいです。採点は、そのファイルが正しいPodのYAMLかどうかだけを見ます。
+()は「なければ入れる」、()は「条件が合っているときだけ適用」です。2つは別の働きをします。- よくあるミス1:
teamラベルを、アンカーなしにそのまま書いてしまうことです。そうすると、ステップ6でplatformが上書きされて失敗します。 - よくあるミス2: ステップ8のレポートに、値が変わっていないフィールドを入れてしまうことです。ミューテーションでないものは、レポートに入れてはいけません。
ラベルを追加するミューテーションポリシーを作る
/root/policy/mutate/add-team-label.yamlにkind: ClusterPolicyを作成してください。spec.backgroundを明示し、spec.rules[0].mutate.patchStrategicMerge.metadata.labelsの下に+(team): unassignedを入れてください。ルール名はadd-default-team、マッチはpol-labネームスペースのPodです。
ミューテーションは、mutateの下に書きます。マップにフィールドを追加するには、オブジェクトと同じ形で書く方式が、最も読みやすいです。すでに値があるPodもすぐに扱うことになるので、上書きしない表記を最初から使ってください。
追加アンカーでリソースのデフォルト値を埋める
/root/policy/mutate/add-defaults.yamlに2つ目のポリシーを作成し、+(...)の追加アンカーで、コンテナのresources.limitsに、cpuとmemoryのデフォルト値を埋めるルールを書いてください。そして、/root/policy/mutate/out/anchors.md(150バイト以上)に、条件アンカー()、追加アンカー+()、そして=()またはX()の違いを整理してください。
「なければ入れ、あれば置いておく」という意味のアンカーが、別にあります。3種類のアンカーの違いをドキュメントに整理して、はじめて通過します。
JSONパッチで配列の項目を修正する
同じadd-defaults.yamlに、mutate.patchesJson6902を使うルールをもう1つ入れてください。op: addとpath: /spec/containers/0/imagePullPolicy、value: IfNotPresentの形です。そして、/root/policy/mutate/out/json6902-note.txtに、この方式が配列・インデックスを扱うときになぜ必要なのかを書いてください。
Strategic Mergeでは、「何番目のコンテナ」をピンポイントで指すのが難しいです。op・path・valueの3つで位置を指定する方式があります。
コンテナのリストを回るルールを書く
add-defaults.yamlに、mutate.foreachルールを入れてください。list: "request.object.spec.containers"でコンテナのリストを受け取り、内部でelement変数で現在の項目を指す必要があります。
コンテナの数がわからないときは、インデックスを使えません。リストを受け取るキーと、現在の項目を指す変数の名前を、確認してください。
ポリシーを実行して、ミューテーション結果を保存する
2つのポリシーを/opt/lab/fixtures/policy/resources/bad-pod.yamlに適用して、ミューテーションされたPodマニフェストを/root/policy/mutate/out/mutated.yamlに保存してください。そのファイルには、metadata.labels.team、spec.containers[0].resources.limits.memory、spec.containers[0].imagePullPolicyの3つの値が、すべて埋まっている必要があります。
2つのポリシーファイルを、一度に渡せます。保存するのは、実行の要約ではなく、ミューテーションされたPodのマニフェストです。
すでにある値が保存されるか確認する
同じ2つのポリシーを/opt/lab/fixtures/policy/resources/good-pod.yamlに適用して、/root/policy/mutate/out/preserved.yamlに保存してください。このPodには、もともとteam: platformラベルとcpu: 500mの制限があり、ミューテーションの後もそのままである必要があります。
同じポリシーを、値が埋まっているPodに対して実行します。元の値が変わっていたなら、アンカーを使わなかったか、間違って使ったということです。
すでに存在するリソースを修正するポリシーを書く
/root/policy/mutate/mutate-existing.yamlを作成してください。spec.mutateExistingOnPolicyUpdate: trueを置き、ルールのmutate.targetsにkind: Pod、namespace: pol-labを書いて、トリガーではないリソースを修正するようにしてください。そして、/root/policy/mutate/out/existing-note.txtに、この動作がバックグラウンドで動くため、追加のRBAC権限が必要であることを書いてください。
トリガーではなく別のリソースを修正するには、対象を別に書く必要があります。ポリシーを修正したときに、既存のリソースも手直しするかどうかを決めるスイッチもあります。
ミューテーション前後の照合レポートを作る
/root/policy/mutate/out/mutate-report.jsonを作成してください。最上位のmutations配列に3件以上を入れ、各項目は、field・before・after・ruleの4つのキーを持つ必要があります。beforeとafterが同じ項目は入れないでください。fieldにteamが含まれる項目のafterの値は、ステップ5で作ったmutated.yamlのmetadata.labels.teamの値と、正確に同じである必要があります。
フィールドごとに、前後の値と、どのルールが行ったかを入れます。値が変わっていない項目はミューテーションではないので、入れてはいけません。