ポリシーは残っているのに違反Podが作成された
目標
ポリシーオブジェクトが残っていても、呼び出しの登録が削除されていれば、Failの呼び出し失敗の処理をテストしたことにはなりません。正常なスケールダウンのあと、登録・応答の復旧時刻とオブジェクトのUIDを比べ、server dry-runで検証と保存を区別します。
なぜ重要なのか
失敗という1つの言葉で、ポリシーの明示的な拒否とWebhook呼び出しのエラーをまとめると、対応を間違えます。ポリシー・登録・応答・すでに実行中のPodを、別々に観測する必要があります。2つのラボは、それぞれ新しいVMで始まり、ほかのラボの資料は必要ありません。受講生専用VMの外で障害を作らないでください。
正常なスケールダウンでは55秒の復旧監視プロセスを、応答の停止ではpidfdと20秒の自動再開タイマーを使います。このラボの想定時間は55分です。基本のセッションは60分なので、期限が切れる前に必要なら+時間で延長してください。最大は180分で、終了するとVMとファイルは消えます。必要な資料を先にダウンロードしてください。
すべての受講生のファイルは、/root/kca-webhookの下にあります。各act Nの生データはevidence/NN.jsonに保存され、内容はfactsから読み取ります。説明に出てくる02.jsonなどは、このevidenceのパスです。正規のJSONハッシュは、/opt/fixtures/kca_webhook_common.pyのdigest(read(パス))であり、sha256sumのファイルバイトのハッシュとは違います。Pythonでsys.pathに/opt/fixturesを追加して使ってください。
ステップ
- inspectで、このVMのvm.node_uidとnamespacesを確認してください。scope.jsonに、target=kca-webhook-target、control=kca-webhook-control、node_uid、namespacesを記録します。namespacesは、実際の名前をキー、UIDを値にします。act 1で、このVMの範囲を保存してください。
- policy.jsonに、policies.kyverno.io/v1のValidatingPolicyを書いてください。名前はkca-webhook-label、validationActions=[Deny]、failurePolicy=Fail、webhookConfiguration.timeoutSeconds=3、evaluation.background.enabled=falseです。matchConstraints.namespaceSelector.matchLabelsはkubernetes.io/metadata.name=kca-webhook-targetで、resourceRulesはapiGroups=[空文字列]、apiVersions=[v1]、operations=[CREATE]、resources=[pods]です。validationsのexpressionは"'environment' in object.metadata.?labels.orValue({})"、messageはKCA_ENVIRONMENT_REQUIREDです。不要なフィールドなしで書き、act 2で実際の登録を確認してください。
- registration.jsonに、service=kyverno-svc、namespace=kyverno、path=/vpol/kca-webhook-label、selector_target=kca-webhook-target、selector_source=namespace-label、operation=CREATE、resource=pods、failure_policy=Fail、timeout_seconds=3、policy_uid=02.jsonのfacts.policy.metadata.uidを記録してください。act 3で、登録と、範囲外のラベルなしリクエストの保存UIDを観測してください。
- act 4を実行してください。evidence/04.jsonのfacts.goodはラベルがあるPodの保存UID、badはラベルの欠落による明示的な拒否・未保存、existingは同じUIDのRunningである必要があります。エラーの原文と保存されたかどうかを、一緒に読んでください。
- shutdown-plan.jsonに、action=observe-graceful-shutdown、inspectのcontroller.metadata.uidをdeployment_uidとして、replicas_before=1、replicas_during=0、replicas_after=1、restore_deadline_sec=55を記録してください。act 5は、専用VMのコントローラーを正常にスケールダウンして復旧します。evidence/05.jsonで、同じポリシーUID、登録の不在、違反の保存、復旧後の拒否と新しいコントローラーPodを区別してください。
- recovery.jsonに、05.jsonのfacts.replicas_restored_at、facts.recovery.registered_at、facts.recovery.response_atを、それぞれ同じ名前のキーで移してください。replicas_mean=desired-count-not-policy-readiness、controller_pod=replaced、policy=same-uid、shutdown_evidence_sha256=05.jsonの正規のJSONハッシュを書きます。act 6は、新しい違反リクエストの拒否と、ベースラインPodの生存を、再び確認します。
- dryrun.jsonに、mode=server、admission=evaluated、good=accepted-not-stored、bad=explicit-deny、existing=same-uid-running、evidence_sha256=06.jsonの正規のJSONハッシュを記録してください。act 7は、新しい名前でserver dry-runを実行します。evidence/07.jsonの正常なPodの応答と保存の不在、違反リクエストの明示的な拒否を、比べてください。
- report.jsonに、shutdown=registration-removed-not-fail-bypass、policy=same-uid、controller_pod=replaced、existing=same-uid-running、dryrun=admission-without-storageを記録してください。shutdown_evidence_sha256とdryrun_evidence_sha256には、05.jsonと07.jsonの正規のJSONハッシュを入れます。act 8のあと、全体の採点をもう一度実行してください。
参考
コマンドは、python3 /opt/fixtures/kca_webhook_lab.py inspect、act 1からact 8、grade 1からgrade 8です。gradeは、入力と保存された実際の観測を読み取り、障害を再び作りません。完了したactは、資料とリソースを保存します。部分的な入力も、自動では上書きしません。中断された実行は結果が不確実なので、失敗の生データをダウンロードして、新しいラボで再現してください。ポリシーの対象はCREATE podsです。すべてのAPI・すべてのインストールバージョン・高可用性に一般化しないでください。 Kubernetesサーバーdry-run
VMと対象・対照の範囲
inspectで、このVMのvm.node_uidとnamespacesを確認してください。scope.jsonに、target=kca-webhook-target、control=kca-webhook-control、node_uid、namespacesを記録します。namespacesは、実際の名前をキー、UIDを値にします。act 1で、このVMの範囲を保存してください。
inspectのvm.node_uidとnamespacesを見てください。名前とUIDは違います。
Deny・Failのポリシーを直接書く
policy.jsonに、policies.kyverno.io/v1のValidatingPolicyを書いてください。名前はkca-webhook-label、validationActions=[Deny]、failurePolicy=Fail、webhookConfiguration.timeoutSeconds=3、evaluation.background.enabled=falseです。matchConstraints.namespaceSelector.matchLabelsはkubernetes.io/metadata.name=kca-webhook-targetで、resourceRulesはapiGroups=[空文字列]、apiVersions=[v1]、operations=[CREATE]、resources=[pods]です。validationsのexpressionは"'environment' in object.metadata.?labels.orValue({})"、messageはKCA_ENVIRONMENT_REQUIREDです。不要なフィールドなしで書き、act 2で実際の登録を確認してください。
namespaceSelectorは、namespaceのラベルを選びます。検証動作のDenyと、呼び出し失敗の処理であるFailを区別してください。
呼び出し登録の範囲をリクエストで確認する
registration.jsonに、service=kyverno-svc、namespace=kyverno、path=/vpol/kca-webhook-label、selector_target=kca-webhook-target、selector_source=namespace-label、operation=CREATE、resource=pods、failure_policy=Fail、timeout_seconds=3、policy_uid=02.jsonのfacts.policy.metadata.uidを記録してください。act 3で、登録と、範囲外のラベルなしリクエストの保存UIDを観測してください。
ポリシーの宣言だけでなく、02.jsonの実際のserviceのパス・namespaceSelector・rulesも照らし合わせてください。範囲外のリクエストは、Failを迂回したという意味ではありません。
正常な許可・拒否と、既存のPodのベースライン
act 4を実行してください。evidence/04.jsonのfacts.goodはラベルがあるPodの保存UID、badはラベルの欠落による明示的な拒否・未保存、existingは同じUIDのRunningである必要があります。エラーの原文と保存されたかどうかを、一緒に読んでください。
AlreadyExistsは、ポリシーの拒否ではありません。あとのステップで、既存のPodのUIDを、このベースラインと比べます。
正常終了のあとの、ポリシーと登録の異なる寿命
shutdown-plan.jsonに、action=observe-graceful-shutdown、inspectのcontroller.metadata.uidをdeployment_uidとして、replicas_before=1、replicas_during=0、replicas_after=1、restore_deadline_sec=55を記録してください。act 5は、専用VMのコントローラーを正常にスケールダウンして復旧します。evidence/05.jsonで、同じポリシーUID、登録の不在、違反の保存、復旧後の拒否と新しいコントローラーPodを区別してください。
ポリシーが残っていても、呼び出しの登録が消えることがあります。replicas=1の直後に、ポリシーまで復旧したと仮定しないでください。
復旧時刻と実際の拒否を別々に検証する
recovery.jsonに、05.jsonのfacts.replicas_restored_at、facts.recovery.registered_at、facts.recovery.response_atを、それぞれ同じ名前のキーで移してください。replicas_mean=desired-count-not-policy-readiness、controller_pod=replaced、policy=same-uid、shutdown_evidence_sha256=05.jsonの正規のJSONハッシュを書きます。act 6は、新しい違反リクエストの拒否と、ベースラインPodの生存を、再び確認します。
時刻は、イベントの正確な発生時刻ではなく、実行ツールが確認した観測時刻です。登録の確認と、実際の拒否の応答を、同じ状態にまとめないでください。
サーバー検証の成功と保存の成功を区別する
dryrun.jsonに、mode=server、admission=evaluated、good=accepted-not-stored、bad=explicit-deny、existing=same-uid-running、evidence_sha256=06.jsonの正規のJSONハッシュを記録してください。act 7は、新しい名前でserver dry-runを実行します。evidence/07.jsonの正常なPodの応答と保存の不在、違反リクエストの明示的な拒否を、比べてください。
client dry-runは、サーバーWebhookを確認しません。server dry-runの正常な応答にオブジェクトがあるからといって、実際に保存されたと解釈しないでください。
異なるオブジェクトの寿命で事故報告を書く
report.jsonに、shutdown=registration-removed-not-fail-bypass、policy=same-uid、controller_pod=replaced、existing=same-uid-running、dryrun=admission-without-storageを記録してください。shutdown_evidence_sha256とdryrun_evidence_sha256には、05.jsonと07.jsonの正規のJSONハッシュを入れます。act 8のあと、全体の採点をもう一度実行してください。
再作成されたコントローラーPodと、生き続けているベースラインPodを区別してください。レポートのハッシュだけを合わせても、前のステップの実際の生データがなければ通過しません。