KCA — Kyverno 인증 어소시에이트 · 정책 운영 · 실습
라벨 규칙을 풀었는데 아무도 몰랐다
목표
Kyverno CLI 의 apply·test·jp 로 정책이 무엇을 거부하고 무엇을 바꾸고 무엇을 만드는지 클러스터에 올리기 전에 판정하고,
그 판정을 시험 묶음과 CI 스크립트로 고정합니다.
왜 중요한가
어드미션 정책은 틀리면 조용합니다. 검증 규칙을 느슨하게 고친 실수는 아무 요청도 막지 않을 뿐 오류를 내지 않고,
변형 규칙의 앵커 하나는 이미 값이 있는 리소스를 건드리는지 아닌지를 바꿉니다. 운영 클러스터에서 그 차이를 발견하면 이미 늦습니다.kyverno test 는 "이 리소스는 통과, 저 리소스는 실패, 이 리소스는 이렇게 바뀐다" 는 기대를 먼저 적어 두고 엔진의 실제 판정과 비교합니다.
그래서 정책을 고친 사람이 의도하지 않은 완화를 했을 때 시험이 먼저 빨간불을 켭니다. 클러스터에 없는 ConfigMap 이나 API 호출 결과는
values 파일로 채우고, 조건식의 JMESPath 는 kyverno jp 로 따로 돌려 보면서 정책 저장소를 코드처럼 검증합니다.
단계
1. /root/kca-cli/validate/policy.yaml 에 ClusterPolicy require-team 을 작성하세요. 규칙 check-team 은 Pod 를 골라 metadata.labels.team 이 비어 있지 않은 값이어야 한다고 요구하고 failureAction 은 Enforce 입니다. /root/kca-cli/validate/resources.yaml 에는 Pod good(라벨 team=pay), 라벨 없는 Pod bad, 파드 템플릿에 team 라벨이 없는 Deployment web 을 둡니다(모두 namespace default). kyverno apply 에 --policy-report 를 붙여 실행하고 표준 출력을 /root/kca-cli/apply-report.yaml 에 저장하세요.
2. /root/kca-cli/validate/kyverno-test.yaml 에 Test 를 작성하세요(apiVersion cli.kyverno.io/v1alpha1). policies 는 policy.yaml, resources 는 resources.yaml 이고, results 에 good 은 pass, bad 는 fail, Deployment web 은 1단계 보고서에 나온 자동 생성 규칙 이름으로 fail 을 기대합니다. kyverno test /root/kca-cli/validate 가 3건 모두 통과해야 합니다.
3. /root/kca-cli/validate 를 /root/kca-cli/regressed 로 통째로 복사하고, 복사본의 policy.yaml 에서 team 키만 등가 앵커 =(team) 으로 바꾸세요(라벨이 없으면 통과하게 되는 흔한 실수). kyverno test /root/kca-cli/regressed --remove-color 의 출력 전체를 /root/kca-cli/regression.txt 에 저장하고 종료 코드도 확인하세요. 요약 줄과 종료 코드만 보지 말고 표의 RESULT·REASON 열에서 기대와 실제가 어긋난 행을 찾습니다. 원본 validate 는 그대로 통과해야 합니다.
4. /root/kca-cli/mutate/ 에 ClusterPolicy add-managed-by(규칙 add-label, Pod 에 managed-by: kyverno 라벨을 없을 때만 추가하는 추가 앵커 사용), resources.yaml(라벨 없는 Pod plain, managed-by: helm 라벨이 있는 Pod owned), 변형 뒤 기대 모습 patched.yaml(plain 에 라벨이 붙은 Pod), kyverno-test.yaml 을 두세요. 시험은 plain 을 patchedResources 와 비교해 pass, owned 는 skip 을 기대하고 kyverno test /root/kca-cli/mutate 가 통과해야 합니다.
5. /root/kca-cli/generate/ 에 ClusterPolicy ns-quota(규칙 gen-quota, Namespace 가 생기면 그 네임스페이스에 ResourceQuota default-quota 를 spec.hard.pods: "10" 으로 생성, synchronize false), resources.yaml(Namespace team-a), 기대 생성물 generated.yaml, kyverno-test.yaml(team-a 에 대해 generatedResource 비교, pass)을 두고 kyverno test /root/kca-cli/generate 를 통과시키세요.
6. /root/kca-cli/context/ 에 ClusterPolicy allowed-registries 를 두세요. 규칙 check-registry 는 Pod 에 대해 컨텍스트 reg 로 ConfigMap platform/registry-config 를 읽고, foreach 로 모든 컨테이너 이미지가 reg.data.allowed(쉼표로 구분한 패턴 목록) 중 하나에 맞지 않으면 거부합니다(Enforce). resources.yaml 에는 이미지가 registry.lab/web:1.0 하나인 Pod internal, 거기에 docker.io/busybox:1.36 컨테이너 sidecar 를 더한 Pod external 을 둡니다. 클러스터가 없으므로 values.yaml(kind Values)로 reg.data.allowed 를 registry.lab/* 로 채우고, kyverno-test.yaml 의 variables 로 연결해 internal pass, external fail 을 통과시키세요.
7. /root/kca-cli/jp/query.txt 에 JMESPath 식 하나를 쓰세요. Pod 객체를 입력으로 받아 이미지가 registry.lab/ 로 시작하지 않는 컨테이너의 이름 목록을 돌려줘야 합니다. /root/kca-cli/jp/external.yaml 에 6단계의 Pod external 한 개만 두고, kyverno jp query -i jp/external.yaml -q jp/query.txt 의 출력을 /root/kca-cli/jp/result.json 에 저장하세요.
8. /root/kca-cli/ci.sh 를 실행 가능한 스크립트로 만드세요. 첫 인자로 루트 디렉터리(없으면 /root/kca-cli)를 받아 그 아래 validate·mutate·generate·context 네 디렉터리에 각각 kyverno test 를 돌리고, 하나라도 실패하면 0 이 아닌 값으로 끝나야 합니다. 3단계에서 본 것처럼 종료 코드가 0 이어도 출력 표에 기대와 실제가 어긋난 행(REASON 이 Want ...)이 있으면 실패로 처리해야 합니다. regressed 는 돌리지 않습니다. 채점기는 복사본의 정책·시험을 여러 방식으로 망가뜨려 스크립트가 실패하는지 봅니다.
참고
- 이 이미지에는 kyverno CLI 1.13.2 가 들어 있습니다.
kyverno version으로 확인하세요. 이 실습은 클러스터를 쓰지 않습니다. - 시험 결과만 보려면
kyverno test <디렉터리> --fail-only, 자세한 이유는--detailed-results. - 흔한 실수: Deployment 에 대한 기대를 Pod 규칙 이름으로 적는 것. 자동 생성 규칙은 이름이 다릅니다.
- 흔한 실수:
Test Summary줄과 종료 코드만 믿는 것. 이 버전은 fail 기대가 pass 로 뒤집힌 행을 표에만 남깁니다(3단계에서 직접 확인합니다). - 흔한 실수: JMESPath 문자열을 백틱으로 감싸는 것. 백틱 안은 JSON 이라 따옴표 없는 글자는 구문 오류가 됩니다.
- [Kyverno CLI test](https://kyverno.io/docs/kyverno-cli/usage/test/) · [Kyverno CLI apply](https://kyverno.io/docs/kyverno-cli/usage/apply/) · [Kyverno CLI jp](https://kyverno.io/docs/kyverno-cli/usage/jp/) · [자동 생성 규칙](https://kyverno.io/docs/policy-types/cluster-policy/autogen/)
단계 8개
- 정책을 올리기 전에 엔진에 먼저 물어본다
- 기대 결과를 먼저 적어 두는 시험
- 라벨 규칙을 풀었는데 시험이 먼저 알아챘다
- 바뀐 결과까지 비교하는 mutate 시험
- 만들어질 객체를 미리 비교하는 generate 시험
- 클러스터 없이 ConfigMap 컨텍스트를 채운다
- 조건식을 정책 밖에서 먼저 돌려 본다
- 정책 저장소의 CI 문지기