AuditからEnforceまで — ポリシーを実際に点ける順序
一言でいうと
ポリシーは、書くことよりもオンにすることのほうが難しく、オンにする順序は、常に観測 → 例外の整理 → 強制の3つの段階です。
なぜ必要なのか
ポリシーを1つうまく書いて、すぐにEnforceに上げたチームに起きることは、たいてい同じです。デプロイが次々とブロックされ、Slackに問い合わせが溜まり、数時間後に誰かが「とりあえずポリシーを下げてください」と言い出します。ポリシーは下げられ、二度と上がりません。失敗の原因は、ポリシーの質ではありません。すでに動いているものたちが、そのルールを守っているかどうか、誰も知らなかったことです。
クラスターには、新しくデプロイされるワークロードだけがあるわけではありません。2年前に上がったバッチジョブ、ベンダーがくれたHelmチャート、どこかのチームが一時的に起動して忘れたPodが、一緒に暮らしています。新しいルールがこれらのうちいくつに引っかかるかは、ルールをかけてみる前にはわかりません。そのため、ポリシーエンジンには、ブロックせずに数えてみるモードが必ずあります。
どう動くのか
核心は、2つの仕組みです。
1つ目は、AuditとEnforceです。
| モード | 違反リクエスト | 残るもの |
|---|---|---|
Audit |
通過させる | レポートにfailとして記録される |
Enforce |
拒否する | レポートにも残り、ユーザーもすぐに気づく |
Auditは、「ポリシーがオンになっていない状態」ではなく、「強制だけをオフにした状態」です。判定はそのまま行われ、結果が溜まります。そのため、Auditで数日置いておけば、「このルールをオンにすると、いくつがブロックされるのか」という質問に、数字で答えられます。強制レベルがルール単位(validate.failureAction)に下りてきてからは、1つのポリシーの中で、検証済みのルールだけをEnforceに上げ、新しいルールはAuditで載せることができます。
2つ目は、バックグラウンドスキャンとPolicyReportです。
アドミッションの段階は、これから入ってくるものだけを見ます。すでにクラスターの中にあるオブジェクトは、誰も再び検査しません。そのため、spec.background: trueのポリシーは、バックグラウンドコントローラーが定期的に既存のリソースを走査して、同じルールで判定します。その結果が、レポートとして溜まります。
PolicyReport: ネームスペーススコープ。そのネームスペースのリソースの判定結果ClusterPolicyReport: クラスタースコープのリソースの判定結果
レポートには、results配列にリソースごとの判定(policy, rule, result, message)が入り、summaryにpass・fail・warn・error・skipの集計が入ります。このsummary.failが、導入作業の進捗の指標です。ポリシーをオンにした日に47だったものが、2週間後に3になったなら、その3が、残った例外の候補です。
3つ目は、PolicyExceptionです。
残ったものの中には、本当に直せないものがあります。ベンダーのイメージなのでリミットを入れられない、ノードのエージェントなので特権が必要、といったものです。このとき、ポリシーを元に戻す代わりに、例外をドキュメントとして残します。例外には、3重の範囲があります。
spec.exceptions[].policyName: どのポリシーに対する例外かspec.exceptions[].ruleNames: そのポリシーのどのルールだけが免除かspec.match: どのリソースにだけ適用されるか(kinds、namespaces、そしてnames)
3重すべてを絞ることが重要です。ruleNamesを省略してポリシー全体を免除すると、そのリソースは、今後そのポリシーに追加されるすべてのルールからも外れます。namesなしでネームスペースだけを書くと、その中で新しく作られるワークロードまで、永久にルールの外に置かれます。例外は、ポリシーをオフにするスイッチではなく、負債の一覧でなければなりません。一覧が長くなれば目に見え、目に見えれば減らせます。例外ごとに、有効期限や担当チームをアノテーションとして付けておけば、一覧がひとりでに管理されます。
この3つの仕組みを順番に使うと、導入の手順が出てきます。
1) 정책을 Audit 으로 배포 + background: true
2) 며칠~몇 주 리포트의 summary.fail 을 관찰
3) 고칠 수 있는 것은 팀과 함께 고친다 (fail 이 줄어드는 것을 본다)
4) 못 고치는 것만 좁은 PolicyException 으로 남긴다
5) fail 이 예외 건수까지 내려오면 그 규칙을 Enforce 로 올린다
6) 예외 목록을 주기적으로 다시 본다
このコードブロックの韓国語は、6つの手順を順に、ポリシーをAuditとしてデプロイしてbackground: trueにする、数日から数週間、レポートのsummary.failを観察する、直せるものはチームと一緒に直す(failが減るのを見る)、直せないものだけを狭いPolicyExceptionとして残す、failが例外の件数まで下がったらそのルールをEnforceに上げる、例外の一覧を定期的に見直す、と述べています。
現場での姿
1つ目は、Auditをオンにしたまま誰も見ない場合です。レポートは溜まりますが、ダッシュボードもアラートもなければ、ただCRDのオブジェクトが増えるだけです。Auditは観測であって、観測の結果を読んでくれる人ではありません。ポリシーをAuditでデプロイする瞬間に、「誰がいつこの数字を見るのか」も、一緒に決めなければなりません。
2つ目は、レポートが溜まってクラスターを圧迫する場合です。リソースが多いクラスターで、すべてにマッチするポリシーをbackgroundでオンにすると、レポートのオブジェクトが大量に作られます。レポートコントローラーが、集計の速度に追いつけなくなると、ラグが始まります。マッチ範囲を絞ることが、ここでも答えです。
3つ目は、例外が黙って永続化する場合です。「次のスプリントで直します」で作った例外が、2年目も残っているクラスターは、よくあります。例外に有効期限と担当者を書いておき、四半期ごとに一覧を見渡す手順を作る必要があります。例外を作ることよりも、例外を消す手順を作るほうが、難しく、重要です。
4つ目は、この環境の正直な限界です。ここでは、バックグラウンドコントローラーが動かないため、クラスターにPolicyReportが自然に溜まることはありません。その代わり、kyverno apply --policy-reportで、同じ形式のレポートをローカルで作れ、そのsummaryのpass/failの数値が、実際のレポートのものと同じ意味を持ちます。pol-validateのラボで作ったレポートが、まさにそれでした。
次の確認で見ること
続くラボで、この文章の最後の2つの段落を、手で作ります。担当者と有効期限と根拠を書いた例外台帳を作り、期限切れの例外を見つけてブロックする検査ツールを書き、例外が実際にポリシーの適用範囲を絞っているか確認したうえで、違反を1か所に集めて、「今Enforceに上げてもよいか」を数字で答えるレポートを作ります。例外を作ることよりも、例外を消す手順を作ることのほうが難しいと、そこで身をもって知ることになります。ラボの後のクイズでは、/root/policy/validate/exception.yamlのpolicyName・ruleNames・リソースのnamesの3重が、例外の範囲をどう絞るのか、有効期限・担当者とともに、負債の一覧として管理する理由を確認します。