注入・生成の規則と権限を立てる
目標
mutateの2つの方式とgenerateの2つの方式をマニフェストとして書き、generateが実際に動作するために必要なRBACをクラスターに直接立てて、権限まで検証します。
なぜ重要なのか
generateルールは、Kyvernoで最も静かに失敗する機能です。admissionは成功するのでkubectlは何のエラーも出さず、リソースだけができません。原因はたいてい2つで、matchされていないか、backgroundコントローラーに権限がないかです。このラボで権限を自分で作り、auth can-iで確認してみると、あとで現場で生成物が見えないときに、ポリシーのYAMLを探し回る代わりに、UpdateRequestと権限を先に見るようになります。サイドカー注入にリソースリミットを一緒に入れる習慣も、同じ種類の予防措置です。
ステップ
/root/kca-mutate/ディレクトリを作成し、mutate-labels.yamlにkindとしてClusterPolicy、metadata.nameとしてkca-add-team-labelを書いてください。ルールadd-managed-byを作り、matchのkindsにDeploymentを入れ、mutate.patchStrategicMergeでmetadata.labelsのkca.io/managed-byにkyvernoを入れるようにしてください。- 同じファイルにルール
inject-sidecarを追加してください。match.any[0].resources.selector.matchLabelsのkca.io/injectで対象を選び、mutate.patchStrategicMerge.spec.template.spec.containers[0]にnamelog-collector、image、そしてresources.limitsのmemoryとcpuをすべて入れてください。 /root/kca-mutate/mutate-json6902.yamlにkindとしてClusterPolicyを書き、spec.rules[0].mutate.patchesJson6902でアノテーションkca.io/ownerを追加するadd操作を書いてください。パスは/metadata/annotations/の下で、キーのスラッシュをエスケープする必要があります。/root/kca-mutate/generate-netpol.yamlにkindとしてClusterPolicy、metadata.nameとしてkca-generate-default-denyを書いてください。matchのkindsはNamespace、generate.apiVersionはnetworking.k8s.io/v1、kindはNetworkPolicy、nameはdefault-deny、namespaceは新しいネームスペースの名前を受け取る変数、synchronizeはtrueにし、generate.data.spec.policyTypesにはIngressとEgressを入れてください。/root/kca-mutate/generate-clone.yamlにkindとしてClusterPolicy、metadata.nameとしてkca-clone-baselineを書いてください。generate.kindはConfigMap、nameはkca-baseline、clone.namespaceはkca-shared、clone.nameはkca-baseline-config、synchronizeはtrueにし、dataは書かないでください。- クラスターにネームスペース
kca-sharedを作成し、その中にRolekca-clone-readerを実際に作成してください。コアグループのconfigmapsにget、list、watchだけを許可し、deleteは入れないでください。 - クラスターにネームスペース
kyvernoとその中のServiceAccountkyverno-background-controllerを作成し、kca-sharedにRoleBindingkca-clone-readerを実際に作成して、Rolekca-clone-readerをそのServiceAccountに結び付けてください。 kca-sharedにConfigMapkca-baseline-configを実際に作成してください。データはlog-level=infoとretention=7dの2つです。そのあとkubectl auth can-iで、該当のServiceAccountがこのネームスペースのconfigmapsを読み取れて、secretsは読み取れないことを確認してください。
参考
kubectl create role kca-clone-reader --verb=get,list,watch --resource=configmaps -n kca-sharedで素早く作成できます。- 権限の確認は
kubectl auth can-i get configmaps --as=system:serviceaccount:kyverno:kyverno-background-controller -n kca-sharedです。 - よくある間違い1: generateにcloneとdataを同時に書いてしまうこと。どちらか一方だけを選びます。
- よくある間違い2: JSON Patchのパスで、キーのスラッシュをそのままにしてしまうこと。パスの区切り文字と区別できません。
patchStrategicMergeでラベルを注入する
/root/kca-mutate/ディレクトリを作成し、mutate-labels.yamlにkindとしてClusterPolicy、metadata.nameとしてkca-add-team-labelを書いてください。ルールadd-managed-byを作り、matchのkindsにDeploymentを入れ、mutate.patchStrategicMergeでmetadata.labelsのkca.io/managed-byにkyvernoを入れるようにしてください。
mutateブロックの中にオブジェクトの形をそのまま描くと、その部分だけがマージされます。ラベルのキーにドットとスラッシュがある場合は、YAMLで引用符で囲んでください。
サイドカー注入とリソースリミット
同じファイルにルールinject-sidecarを追加してください。match.any[0].resources.selector.matchLabelsのkca.io/injectで対象を選び、mutate.patchStrategicMerge.spec.template.spec.containers[0]にname log-collector、image、そしてresources.limitsのmemoryとcpuをすべて入れてください。
注入するコンテナには、リソースリミットを必ず入れる必要があります。mutateがvalidateより先に動くという事実が、ここでなぜ重要なのかを思い出してください。そして、すべてのワークロードではなく、ラベルで選んだものにだけ注入されるようにしてください。
JSON Patchでアノテーションを追加する
/root/kca-mutate/mutate-json6902.yamlにkindとしてClusterPolicyを書き、spec.rules[0].mutate.patchesJson6902でアノテーションkca.io/ownerを追加するadd操作を書いてください。パスは/metadata/annotations/の下で、キーのスラッシュをエスケープする必要があります。
JSON Pointerは、スラッシュでパスを区切ります。キー名そのものにスラッシュが入る場合は特別なエスケープが必要で、その表記を知らないと、パスがまったく違う場所を指してしまいます。
ネームスペースごとにdefault-denyを生成する
/root/kca-mutate/generate-netpol.yamlにkindとしてClusterPolicy、metadata.nameとしてkca-generate-default-denyを書いてください。matchのkindsはNamespace、generate.apiVersionはnetworking.k8s.io/v1、kindはNetworkPolicy、nameはdefault-deny、namespaceは新しいネームスペースの名前を受け取る変数、synchronizeはtrueにし、generate.data.spec.policyTypesにはIngressとEgressを入れてください。
generateでは、何を(apiVersion/kind)、どんな名前で、どのネームスペースに作るかをすべて書く必要があります。対象のネームスペースは、今作られたそのネームスペースなので、変数で受け取ります。
cloneで複製する
/root/kca-mutate/generate-clone.yamlにkindとしてClusterPolicy、metadata.nameとしてkca-clone-baselineを書いてください。generate.kindはConfigMap、nameはkca-baseline、clone.namespaceはkca-shared、clone.nameはkca-baseline-config、synchronizeはtrueにし、dataは書かないでください。
cloneは、元のネームスペースと名前を指定します。dataと一緒には使えないこと、そして元の変更に追従させるにはどのフィールドが必要かを確認してください。
複製元を読み取るRoleを作成する
クラスターにネームスペースkca-sharedを作成し、その中にRole kca-clone-readerを実際に作成してください。コアグループのconfigmapsにget、list、watchだけを許可し、deleteは入れないでください。
ここからは実際のクラスターです。読み取りだけが必要なので、動詞は3つあれば十分で、コアグループのリソースのapiGroupsは空文字列です。
backgroundコントローラーにバインドする
クラスターにネームスペースkyvernoとその中のServiceAccount kyverno-background-controllerを作成し、kca-sharedにRoleBinding kca-clone-readerを実際に作成して、Role kca-clone-readerをそのServiceAccountに結び付けてください。
対象は、kyvernoネームスペースのServiceAccountです。そのネームスペースとServiceAccountも、このラボ環境にはないので、一緒に作成する必要があります。
元のConfigMapと権限の検証
kca-sharedにConfigMap kca-baseline-configを実際に作成してください。データはlog-level=infoとretention=7dの2つです。そのあとkubectl auth can-iで、該当のServiceAccountがこのネームスペースのconfigmapsを読み取れて、secretsは読み取れないことを確認してください。
複製元が実際にあってはじめて、cloneが成立します。そして、kubectl auth can-iに--asでServiceAccountになりすますと、権限が正しく付いているかを手で確認できます。