LabHub

KCA — Kyverno 인증 어소시에이트 · 정책 운영 · 이론

정책은 배포하는 것이 아니라 승격하는 것이다

LabHub 에서 이어서 보기

한 줄 요약

정책 운영의 핵심 절차는 하나다. Audit 으로 며칠 관찰해 걸리는 목록이 예상과 일치하는지 확인한 뒤 Enforce 로 올린다. 그리고 그 판단을 사람의 기억이 아니라 PolicyReport 와 CI 게이트에 맡긴다.

왜 이게 필요했나

개발 클러스터에 처음부터 Enforce 로 정책을 거는 실패 패턴은 늘 같은 모습이다. 서명 파이프라인이나 라벨 규칙이 아직 모든 팀에 깔리지 않은 상태에서 강제 모드를 켜면 배포가 통째로 막히고, 결국 정책이 아니라 정책을 만든 사람이 병목이 된다. 그다음에 벌어지는 일이 더 나쁘다. 급하니까 예외를 넓게 뚫고, 그 예외가 영구화된다.

반대로 전부 Audit 으로 두면 아무도 리포트를 보지 않는다. 그래서 필요한 것이 승격 절차다. 무엇을 보고, 어떤 조건이 만족되면, 어느 규칙을 올릴 것인가를 미리 정해 두는 것이다.

어떻게 동작하나

관찰의 도구가 PolicyReport 와 ClusterPolicyReport 다. 네임스페이스 단위 리포트에는 results 배열과 summary(pass/fail/warn/error/skip 개수)가 들어 있다. 실패만 뽑아 보는 습관이 중요하고, 정책 이름과 메시지를 함께 봐야 어느 규칙이 무엇 때문에 걸렸는지 판단이 선다.

차등 적용에는 두 가지 방법이 있다. 규칙 단위 failureAction 은 "어느 규칙을" 을 정하고, validationFailureActionOverrides 는 "어느 네임스페이스에서" 를 정한다. 개발 네임스페이스는 Audit 으로 두고 프로덕션만 Enforce 로 올리는 구성이 대표적이며, 두 축을 조합하면 규칙별로도 네임스페이스별로도 다르게 굴릴 수 있다.

정당한 예외는 PolicyException 으로 관리한다. 정책 이름과 규칙 이름을 지목하고 match 로 대상을 좁힌다. 여기서 핵심은 좁게 쓰는 것이다. 네임스페이스 하나를 통째로 빼는 대신 이름 패턴까지 적어야 하고, 예외 목록이 실제로 도는 대상의 절반을 넘어가면 그 정책은 보안을 주는 것이 아니라 보안이 있다는 착각을 준다.

정책 수준 플래그 셋도 알아 두어야 한다. background 는 기존 리소스를 훑어 리포트를 만드는 동작을 켜고 끄며 기본값은 true 다. admission 은 어드미션 단계에서 규칙을 적용할지이고 기본 true 이며, false 로 두면 background 전용 정책이 된다. applyRules 는 매칭된 리소스에 규칙을 몇 개나 적용할지로, One 이면 첫 매칭에서 멈추고 All 이 기본값이다. 규칙을 순서대로 나열해 두었는데 뒤쪽 규칙이 왜 안 도는지 찾고 있다면 이 필드부터 본다.

CI 게이트는 kyverno apply 가 만든다. 정책 파일과 --resource 로 검사할 매니페스트를 주면 로컬에서 맞물려 돌고, 실패나 에러가 있으면 종료 코드가 1이라 CI 잡에 그대로 걸린다. 이 습관 하나가 막는 사고가 크다. 매치 블록을 잘못 써서 아무것도 매칭하지 않는 정책을 만들어 놓고 통과했다고 착각하는 일 말이다. 아무것도 매칭하지 않는 정책은 클러스터에서 조용히 통과만 시키므로 사람 눈으로는 잘 도는 정책과 구분되지 않는다.

그리고 반복해 말할 원칙이 하나 있다. 와일드카드로 전 리소스를 매칭하는 정책은 클러스터의 모든 요청에 지연세를 매긴다. 기본 failurePolicy 가 Fail 이므로 타임아웃을 넘기는 순간 요청이 거부된다. 매치를 필요한 종류와 네임스페이스로 좁히는 작업은 성능 튜닝이 아니라 가용성 작업이다.

마지막으로 언제 쓰지 않을 것인가. 검사하려는 것이 필드 하나의 값이고 그 이상 아무것도 필요 없다면 쿠버네티스 내장 ValidatingAdmissionPolicy 와 CEL 로 충분하다. 컴포넌트를 하나 덜 운영한다는 것은 업그레이드 대상이 하나 줄고, 장애 시 의심할 곳이 하나 줄고, 웹훅 인증서 갱신을 신경 쓸 일이 하나 준다는 뜻이다. 더 나아가 파드 보안 수준처럼 표준화된 검사라면 정책 엔진 없이 네임스페이스 라벨 두 줄(Pod Security Admission)로 끝난다. Kyverno 를 정당화하는 것은 generate 와 mutate, 그리고 이미지 검증처럼 내장 기능이 못 하는 일들이다.

현장에서 만나는 모습

저자가 이미지 스캔 리포트를 다루며 세운 규칙이 정책 운영에도 그대로 적용된다. 예외에는 반드시 만료일을 넣는다는 것이다. 스캔 예외 파일에는 이유와 만료일을 함께 적고, 만료일이 지나면 스캐너가 다시 실패시킨다. 예외가 조용히 영구화되는 것을 막는 유일한 방법이 이것이었다. PolicyException 에는 만료 필드가 없으므로 같은 효과를 내려면 사람이 관리해야 한다. 예외 오브젝트의 어노테이션에 만료일과 사유를 적고 주기적으로 훑는 절차를 넣어 두는 편이 낫다.

또 하나, 스캔에서 배운 우선순위 감각이 여기서도 유효하다. 리포트에 1,247건이 있어도 오늘 조치할 것은 대개 한 자릿수다. 수정본이 있는 것만 남기고, 실제 악용이 확인된 것을 먼저 본다. 정책 리포트도 같다. fail 이 수백 건이라고 전부 오늘 고칠 대상이 아니라, 규칙별로 묶어 보고 어느 규칙이 가장 많은 실패를 만드는지부터 본다. 그 규칙 하나가 대개 잘못 쓴 규칙이거나, 조직이 아직 준비되지 않은 규칙이다.

저자의 홈랩은 7노드에 Cilium eBPF, ArgoCD, Harbor, Gitea 가 올라간 구성이고, 이 정도 규모에서도 정책을 전면 Enforce 로 켜면 KubeVirt 나 GPU Operator 같은 시스템 컴포넌트가 먼저 걸린다. 그래서 exclude 로 시스템 네임스페이스를 빼는 것이 선택이 아니라 기본값이 된다.

다음 실습에서 할 것

/root/kca-ops/ 에 네임스페이스별 차등 적용과 webhookConfiguration, 정책 플래그를 담은 정책 파일, PolicyException 파일, 그리고 승격 체크리스트를 실행 가능한 셸 스크립트로 작성한다. 그 뒤 PSA 라벨만으로 파드 보안 수준을 강제하는 네임스페이스를 실제로 만들어, 정책 엔진 없이 되는 지점이 어디까지인지 손으로 확인한다.