LabHub

정책을 코드로 · 정책 예외와 리포트 · 이론

Audit 에서 Enforce 까지 — 정책을 실제로 켜는 순서

LabHub 에서 이어서 보기

한 줄 요약

정책은 쓰는 것보다 켜는 것이 어렵고, 켜는 순서는 언제나 관측 → 예외 정리 → 강제 세 단계다.

왜 이게 필요했나

정책 하나를 잘 써 놓고 곧바로 Enforce 로 올린 팀에게 일어나는 일은 대개 똑같다. 배포가 우수수 막히고, 슬랙에 문의가 쌓이고, 몇 시간 뒤 누군가 "일단 정책 좀 내려 주세요"라고 말한다. 정책은 내려가고 다시는 올라가지 않는다. 실패의 원인은 정책의 품질이 아니다. 이미 돌고 있는 것들이 그 규칙을 지키고 있는지 아무도 몰랐다는 것이다.

클러스터에는 새로 배포되는 워크로드만 있는 것이 아니다. 2년 전에 올라간 배치 잡, 벤더가 준 헬름 차트, 어느 팀이 임시로 띄웠다가 잊은 파드가 함께 산다. 새 규칙이 이들 중 몇 개에 걸리는지는 규칙을 걸어 보기 전에는 알 수 없다. 그래서 정책 엔진은 막지 않고 세어 보는 모드를 반드시 갖고 있다.

어떻게 동작하나

핵심은 두 가지 장치다.

첫째, Audit 과 Enforce.

| 모드 | 위반 요청 | 남는 것 |
| --- | --- | --- |
| Audit | 통과시킨다 | 리포트에 fail 로 기록된다 |
| Enforce | 거부한다 | 리포트에도 남고 사용자도 즉시 안다 |

Audit 은 "정책이 켜져 있지 않은 상태"가 아니라 "강제만 꺼 둔 상태" 다. 판정은 그대로 일어나고 결과가 쌓인다. 그래서 Audit 으로 며칠 두면 "이 규칙을 켜면 몇 개가 막히는가"라는 질문에 숫자로 답할 수 있다. 강제 수준이 규칙 단위(validate.failureAction)로 내려온 뒤로는 한 정책 안에서 검증된 규칙만 Enforce 로 올리고 새 규칙은 Audit 으로 얹을 수 있다.

둘째, 백그라운드 스캔과 PolicyReport.

어드미션 단계는 앞으로 들어올 것만 본다. 이미 클러스터 안에 있는 오브젝트는 아무도 다시 검사하지 않는다. 그래서 spec.background: true 인 정책은 백그라운드 컨트롤러가 주기적으로 기존 리소스를 훑으며 같은 규칙으로 판정한다. 그 결과가 리포트로 쌓인다.

리포트에는 results 배열에 리소스별 판정(policy, rule, result, message)이 들어가고, summarypass·fail·warn·error·skip 집계가 들어간다. 이 summary.fail 이 도입 작업의 진척도 지표다. 정책을 켠 날 47 이었다가 2주 뒤 3 이 되면, 그 3 이 남은 예외 후보다.

셋째, PolicyException.

남은 것들 중에는 정말로 못 고치는 것이 있다. 벤더 이미지라 리밋을 못 넣는다든지, 노드 에이전트라 특권이 필요하다든지. 이때 정책을 되돌리는 대신 예외를 문서로 남긴다. 예외에는 세 겹의 범위가 있다.

1. spec.exceptions[].policyName — 어떤 정책에 대한 예외인가
2. spec.exceptions[].ruleNames — 그 정책의 어느 규칙만 면제인가
3. spec.match — 어떤 리소스에만 적용되는가 (kinds, namespaces, 그리고 names)

세 겹을 다 좁히는 것이 중요하다. ruleNames 를 생략하고 정책 전체를 면제하면 그 리소스는 앞으로 그 정책에 추가되는 모든 규칙에서도 빠진다. names 없이 네임스페이스만 적으면 그 안에서 새로 만들어지는 워크로드까지 영구히 규칙 밖에 놓인다. 예외는 정책을 끄는 스위치가 아니라 부채 목록이어야 한다. 목록이 길어지면 눈에 보이고, 눈에 보이면 줄일 수 있다. 예외마다 만료일이나 담당 팀을 어노테이션으로 붙여 두면 목록이 저절로 관리된다.

이 세 장치를 순서대로 쓰면 도입 절차가 나온다.

1) 정책을 Audit 으로 배포 + background: true2) 며칠~몇 주 리포트의 summary.fail 을 관찰3) 고칠 수 있는 것은 팀과 함께 고친다 (fail 이 줄어드는 것을 본다)4) 못 고치는 것만 좁은 PolicyException 으로 남긴다5) fail 이 예외 건수까지 내려오면 그 규칙을 Enforce 로 올린다6) 예외 목록을 주기적으로 다시 본다

현장에서 만나는 모습

첫째, Audit 을 켜 두고 아무도 안 보는 경우. 리포트는 쌓이지만 대시보드도 알림도 없으면 그냥 CRD 오브젝트가 늘어날 뿐이다. Audit 은 관측이지 관측 결과를 읽어 주는 사람은 아니다. 정책을 Audit 으로 배포하는 순간 "누가 언제 이 숫자를 보는가"를 함께 정해야 한다.

둘째, 리포트가 쌓여 클러스터를 누르는 경우. 리소스가 많은 클러스터에서 모든 것을 매칭하는 정책을 background 로 켜면 리포트 오브젝트가 대량으로 만들어진다. 리포트 컨트롤러가 집계 속도를 못 따라가면 적체가 시작된다. 매치 범위를 좁히는 일이 여기서도 답이다.

셋째, 예외가 조용히 영구화되는 경우. "다음 스프린트에 고칠게요"로 만든 예외가 2년째 남아 있는 클러스터는 흔하다. 예외에 만료일과 담당자를 적어 두고, 분기마다 목록을 훑는 절차를 만들어야 한다. 예외를 만드는 것보다 예외를 지우는 절차를 만드는 쪽이 어렵고 중요하다.

넷째, 이 환경의 정직한 한계. 여기서는 백그라운드 컨트롤러가 돌지 않으므로 클러스터에 PolicyReport 가 저절로 쌓이지 않는다. 대신 kyverno apply --policy-report 로 같은 형식의 리포트를 로컬에서 만들 수 있고, 그 summary 의 pass/fail 수치가 실제 리포트의 그것과 같은 의미를 갖는다. pol-validate 실습에서 만든 리포트가 바로 그것이었다.

다음 확인에서 볼 것

이 모듈에는 새 실습이 없다. 대신 pol-validate 실습에서 만든 두 파일을 다시 열어 보라. /root/policy/validate/out/policy-report.yamlsummary 에 pass 1건과 fail 1건이 들어 있었는데, 실제 클러스터라면 그 fail 숫자가 며칠에 걸쳐 줄어드는 것을 보며 Enforce 전환 시점을 판단한다. 이어지는 퀴즈에서는 /root/policy/validate/exception.yamlpolicyName·ruleNames·리소스 names 세 겹이 예외 범위를 어떻게 좁히는지, 만료일·담당자와 함께 부채 목록으로 관리하는 이유를 확인한다.