LabHub
배우기 러닝패스 코스

KCA — Kyverno Certified Associate

The policy was rejected, and the culprit was permissions

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

설치된 Kyverno 의 구성요소를 읽고, generate·cleanup 이 거절될 때 컨트롤러 권한을 집계 ClusterRole 로 더해 고치며, kyverno ConfigMap 의 resourceFilters 와 webhooks 설정이 요청을 어디서 걸러 내는지 실제 요청으로 구분합니다.

왜 중요한가

Kyverno 는 하나의 프로그램이 아니라 어드미션·백그라운드·정리·보고서 네 컨트롤러가 각자의 ServiceAccount 로 도는 시스템입니다. generate 규칙이 만드는 객체와 정리 정책이 지우는 객체는 요청한 사람이 아니라 그 컨트롤러의 권한으로 처리되므로, 권한이 없으면 정책을 쓰는 순간 어드미션에서 거절됩니다. 설치 매니페스트는 기본 권한을 최소로 두고 라벨로 집계되는 ClusterRole 을 더하게 설계되어 있어, 와일드카드 권한을 주는 대신 필요한 종류와 동사만 더하는 것이 운영의 기본입니다. 반대로 검사를 빼고 싶을 때는 두 자리가 있습니다. resourceFilters 는 API 서버가 요청을 보낸 뒤 Kyverno 가 무시하는 것이고, 웹훅 namespaceSelector 는 API 서버가 아예 보내지 않는 것입니다. 어느 쪽이든 기본 제외 항목을 지우면 Kyverno 가 자기 자신이나 시스템 네임스페이스를 막는 사고가 납니다.

단계

  1. /root/kca-install/inventory.jsonversion(kyverno-admission-controller 이미지의 태그), controllers(kyverno 네임스페이스 Deployment 이름 → spec.replicas 숫자), crd_count(API 그룹이 kyverno.io 로 끝나는 CRD 개수), webhook_configs(이름에 kyverno 가 든 ValidatingWebhookConfiguration·MutatingWebhookConfiguration 이름을 정렬한 배열)를 적으세요.
  2. /root/kca-install/02-gen-pdb.yaml 에 ClusterPolicy gen-pdb 를 작성해 적용해 보세요. 규칙 default-pdb 는 라벨 kca.io/pdb=true 인 Namespace 가 생기면 그 안에 PodDisruptionBudget default-pdb(minAvailable 1, selector app=web)를 synchronize true 로 생성합니다. 적용 명령의 출력 전체를 /root/kca-install/gen-denied.txt 에 저장하세요.
  3. /root/kca-install/03-role-bg.yaml 에 ClusterRole kca-bg-pdb 를 만들어 라벨 rbac.kyverno.io/aggregate-to-background-controller: "true" 를 붙이고 policy 그룹 poddisruptionbudgets 에 get·list·watch·create·update·delete 만 허용하세요(와일드카드 금지). 그다음 gen-pdb 를 다시 적용하고, 네임스페이스 kca-pdb-a 를 라벨 kca.io/pdb=true 로 만들어 PDB 가 생기는 것을 확인합니다. 생긴 PDB 의 UID 를 적어 두고 PDB 를 지운 뒤 다시 생긴 PDB 의 UID 와 함께 /root/kca-install/pdb.jsonfirst_uid, second_uid 로 적으세요.
  4. /root/kca-install/04-clean-short.yaml 에 ClusterCleanupPolicy clean-short 를 작성해 적용해 보세요. 네임스페이스 kca-clean 에서 라벨 ttl=short 인 Pod 를 매분(*/1 * * * *) 지웁니다. 적용 명령의 출력 전체를 /root/kca-install/cleanup-denied.txt 에 저장하세요.
  5. /root/kca-install/05-role-cleanup.yaml 에 ClusterRole kca-cleanup-pods(라벨 rbac.kyverno.io/aggregate-to-cleanup-controller: "true", core pods 에 get·list·watch·delete 만)를 적용하고 clean-short 를 다시 적용하세요. 네임스페이스 kca-clean 에 라벨 ttl=short 인 Pod shortttl=long 인 Pod long 을 만들고, 다음 정각 분이 지나 short 만 사라진 것을 확인한 뒤 /root/kca-install/cleanup.jsonlong_uid(남은 long 의 UID)와 last_execution(clean-short 의 status.lastExecutionTime)을 적으세요.
  6. 네임스페이스 kca-skipkca-ctl 을 만들고 /root/kca-install/06-need-team.yaml 에 ClusterPolicy need-team(background false, 규칙 team, 두 네임스페이스의 Pod 에 team 라벨 요구, Enforce)을 적용하세요. 그다음 kyverno 네임스페이스 ConfigMap kyvernoresourceFilters 에 기존 항목을 모두 유지한 채 [Pod,kca-skip,*] 를 덧붙이세요. kca-skip 의 라벨 없는 파드는 받아들여지고 kca-ctl 의 라벨 없는 파드는 계속 거절되어야 합니다.
  7. 네임스페이스 kca-sel 을 라벨 kca.io/webhook=skip 으로 만들고 need-team 의 대상 네임스페이스에 kca-sel 을 더해 다시 적용하세요. 그다음 ConfigMap kyvernowebhooks 값의 namespaceSelector 에 기존 kube-system·kyverno 제외 조건을 유지한 채 kca.io/webhook NotIn [skip] 조건을 더하세요. Kyverno 가 갱신한 kyverno-resource-validating-webhook-cfg 에 그 조건이 들어가고, kca-sel 의 라벨 없는 파드는 받아들여지며 kca-ctl 은 계속 거절되어야 합니다. resourceFilters 에는 kca-sel 을 넣지 않습니다.
  8. /root/kca-install/report.jsonbackground_role(generate 권한을 더한 ClusterRole 이름), cleanup_role(정리 권한을 더한 ClusterRole 이름), pdb_regenerated(3단계 두 UID 가 다른지, 불리언), skip_by(kca-skip 을 거른 설정 키: resourceFilters 또는 webhooks), sel_by(kca-sel 을 거른 설정 키), default_exclusions(웹훅 selector 에 남아 있는 기본 제외 네임스페이스 이름을 정렬한 배열)를 적으세요.

참고

설치된 Kyverno 가 무엇으로 이루어져 있나

/root/kca-install/inventory.jsonversion(kyverno-admission-controller 이미지의 태그), controllers(kyverno 네임스페이스 Deployment 이름 → spec.replicas 숫자), crd_count(API 그룹이 kyverno.io 로 끝나는 CRD 개수), webhook_configs(이름에 kyverno 가 든 ValidatingWebhookConfiguration·MutatingWebhookConfiguration 이름을 정렬한 배열)를 적으세요.

CRD 의 그룹은 spec.group 에 있습니다. kyverno.io, policies.kyverno.io, reports.kyverno.io 처럼 여러 그룹이 있습니다. 웹훅 등록은 정책을 만들 때 Kyverno 가 추가로 만들기도 하므로 지금 있는 것을 읽으세요.

정책은 맞는데 어드미션이 거절했다

/root/kca-install/02-gen-pdb.yaml 에 ClusterPolicy gen-pdb 를 작성해 적용해 보세요. 규칙 default-pdb 는 라벨 kca.io/pdb=true 인 Namespace 가 생기면 그 안에 PodDisruptionBudget default-pdb(minAvailable 1, selector app=web)를 synchronize true 로 생성합니다. 적용 명령의 출력 전체를 /root/kca-install/gen-denied.txt 에 저장하세요.

generate 규칙의 대상 종류는 요청한 사람이 아니라 background controller 의 ServiceAccount 가 만듭니다. Kyverno 는 정책을 받을 때 그 계정의 권한을 미리 확인합니다. 거절 메시지에서 누구에게 어떤 동사가 없는지 읽으세요.

라벨 하나로 컨트롤러에 권한을 더한다

/root/kca-install/03-role-bg.yaml 에 ClusterRole kca-bg-pdb 를 만들어 라벨 rbac.kyverno.io/aggregate-to-background-controller: "true" 를 붙이고 policy 그룹 poddisruptionbudgets 에 get·list·watch·create·update·delete 만 허용하세요(와일드카드 금지). 그다음 gen-pdb 를 다시 적용하고, 네임스페이스 kca-pdb-a 를 라벨 kca.io/pdb=true 로 만들어 PDB 가 생기는 것을 확인합니다. 생긴 PDB 의 UID 를 적어 두고 PDB 를 지운 뒤 다시 생긴 PDB 의 UID 와 함께 /root/kca-install/pdb.jsonfirst_uid, second_uid 로 적으세요.

Kyverno 가 설치한 kyverno:background-controller ClusterRole 은 aggregationRule 을 가집니다. 새 ClusterRole 을 따로 바인딩할 필요가 없습니다. synchronize 가 켜진 생성물은 지워도 다시 만들어집니다.

지울 권한이 없는 정리 정책

/root/kca-install/04-clean-short.yaml 에 ClusterCleanupPolicy clean-short 를 작성해 적용해 보세요. 네임스페이스 kca-clean 에서 라벨 ttl=short 인 Pod 를 매분(*/1 * * * *) 지웁니다. 적용 명령의 출력 전체를 /root/kca-install/cleanup-denied.txt 에 저장하세요.

정리 정책을 실행하는 것은 cleanup controller 입니다. 기본 설치의 그 계정이 어떤 종류를 지울 수 있는지는 kyverno:cleanup-controller ClusterRole 에서 볼 수 있습니다.

짧은 수명 파드만 정각에 사라졌다

/root/kca-install/05-role-cleanup.yaml 에 ClusterRole kca-cleanup-pods(라벨 rbac.kyverno.io/aggregate-to-cleanup-controller: "true", core pods 에 get·list·watch·delete 만)를 적용하고 clean-short 를 다시 적용하세요. 네임스페이스 kca-clean 에 라벨 ttl=short 인 Pod shortttl=long 인 Pod long 을 만들고, 다음 정각 분이 지나 short 만 사라진 것을 확인한 뒤 /root/kca-install/cleanup.jsonlong_uid(남은 long 의 UID)와 last_execution(clean-short 의 status.lastExecutionTime)을 적으세요.

cron 일정은 분 단위라 최대 1분을 기다립니다. selector 에 맞지 않는 파드는 그대로 남아야 합니다.

Kyverno 가 받고도 못 본 척한 요청

네임스페이스 kca-skipkca-ctl 을 만들고 /root/kca-install/06-need-team.yaml 에 ClusterPolicy need-team(background false, 규칙 team, 두 네임스페이스의 Pod 에 team 라벨 요구, Enforce)을 적용하세요. 그다음 kyverno 네임스페이스 ConfigMap kyvernoresourceFilters 에 기존 항목을 모두 유지한 채 [Pod,kca-skip,*] 를 덧붙이세요. kca-skip 의 라벨 없는 파드는 받아들여지고 kca-ctl 의 라벨 없는 파드는 계속 거절되어야 합니다.

resourceFilters 는 [종류,네임스페이스,이름] 묶음을 공백으로 이은 문자열입니다. 기본값에는 kube-system·kyverno 네임스페이스와 Event 같은 항목이 들어 있어서 통째로 바꾸면 Kyverno 가 자기 자원까지 검사하게 됩니다. Kyverno 는 이 ConfigMap 을 재시작 없이 다시 읽습니다.

API 서버가 아예 묻지 않게 한다

네임스페이스 kca-sel 을 라벨 kca.io/webhook=skip 으로 만들고 need-team 의 대상 네임스페이스에 kca-sel 을 더해 다시 적용하세요. 그다음 ConfigMap kyvernowebhooks 값의 namespaceSelector 에 기존 kube-system·kyverno 제외 조건을 유지한 채 kca.io/webhook NotIn [skip] 조건을 더하세요. Kyverno 가 갱신한 kyverno-resource-validating-webhook-cfg 에 그 조건이 들어가고, kca-sel 의 라벨 없는 파드는 받아들여지며 kca-ctl 은 계속 거절되어야 합니다. resourceFilters 에는 kca-sel 을 넣지 않습니다.

webhooks 값은 JSON 문자열입니다. Kyverno 는 그 selector 를 자기가 관리하는 웹훅 등록에 복사하고, API 서버는 selector 에 맞지 않는 네임스페이스의 요청을 Kyverno 에 보내지도 않습니다. 등록 객체를 직접 고치면 Kyverno 가 되돌립니다.

권한과 필터를 어디에 두었는지 보고

/root/kca-install/report.jsonbackground_role(generate 권한을 더한 ClusterRole 이름), cleanup_role(정리 권한을 더한 ClusterRole 이름), pdb_regenerated(3단계 두 UID 가 다른지, 불리언), skip_by(kca-skip 을 거른 설정 키: resourceFilters 또는 webhooks), sel_by(kca-sel 을 거른 설정 키), default_exclusions(웹훅 selector 에 남아 있는 기본 제외 네임스페이스 이름을 정렬한 배열)를 적으세요.

앞 단계에서 남긴 파일과 지금의 ConfigMap·웹훅 등록을 근거로 적습니다. 채점기는 같은 값을 클러스터에서 다시 계산합니다.