LabHub
배우기 러닝패스 코스

KCA — Kyverno Certified Associate

The Policy Remains, but an Invalid Pod Was Created

LabHub 에서 이어서 보기

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

목표

정책 객체가 남아도 호출 등록이 제거되면 Fail의 호출 실패 처리를 시험한 것이 아닙니다. 정상 축소 뒤 등록·응답의 복구 시각과 객체 UID를 비교하고 server dry-run으로 검증과 저장을 구분합니다.

왜 중요한가

실패라는 한 단어로 정책의 명시적 거부와 웹훅 호출 오류를 묶으면 대응을 잘못 고릅니다. 정책·등록·응답·이미 실행 중인 Pod를 따로 관측해야 합니다. 두 실습은 각각 새 VM에서 시작하며 다른 실습의 자료가 필요 없습니다. 학생 전용 VM 밖에서 장애를 만들지 마세요.

정상 축소는 55초 복구 감시자, 응답 중단은 pidfd와 20초 자동 재개 타이머를 사용합니다. 이 실습은 55분을 예상합니다. 기본 세션은 60분이며 만료 전에 필요하면 +시간으로 연장하세요. 최대 180분이고 종료 시 VM과 파일은 사라집니다. 필요한 자료를 먼저 내려받으세요.

모든 학생 파일은 /root/kca-webhook 아래입니다. 각 act N의 원자료는 evidence/NN.json에 저장되며 내용은 facts에서 읽습니다. 설명에 나오는 02.json 등은 이 evidence 경로입니다. 정규 JSON 해시는 /opt/fixtures/kca_webhook_common.py의 digest(read(경로))이며 sha256sum의 파일 바이트 해시와 다릅니다. Python에서 sys.path에 /opt/fixtures를 추가해 사용하세요.

단계

  1. inspect로 이번 VM의 vm.node_uid와 namespaces를 확인하세요. scope.json에 target=kca-webhook-target, control=kca-webhook-control, node_uid, namespaces를 기록합니다. namespaces는 실제 이름을 키, UID를 값으로 둡니다. act 1로 이번 VM의 범위를 보존하세요.
  2. policy.json에 policies.kyverno.io/v1의 ValidatingPolicy를 작성하세요. 이름 kca-webhook-label, validationActions=[Deny], failurePolicy=Fail, webhookConfiguration.timeoutSeconds=3, evaluation.background.enabled=false입니다. matchConstraints.namespaceSelector.matchLabels는 kubernetes.io/metadata.name=kca-webhook-target이고 resourceRules는 apiGroups=[빈 문자열], apiVersions=[v1], operations=[CREATE], resources=[pods]입니다. validations의 expression은 "'environment' in object.metadata.?labels.orValue({})", message는 KCA_ENVIRONMENT_REQUIRED입니다. 불필요한 필드 없이 작성하고 act 2로 실제 등록을 확인하세요.
  3. registration.json에 service=kyverno-svc, namespace=kyverno, path=/vpol/kca-webhook-label, selector_target=kca-webhook-target, selector_source=namespace-label, operation=CREATE, resource=pods, failure_policy=Fail, timeout_seconds=3, policy_uid=02.json의 facts.policy.metadata.uid를 기록하세요. act 3으로 등록과 범위 밖 무라벨 요청의 저장 UID를 관측하세요.
  4. act 4를 실행하세요. evidence/04.json의 facts.good는 라벨이 있는 Pod의 저장 UID, bad는 라벨 누락의 명시적 거부·미저장, existing은 같은 UID의 Running이어야 합니다. 에러 원문과 저장 여부를 함께 읽으세요.
  5. shutdown-plan.json에 action=observe-graceful-shutdown, inspect의 controller.metadata.uid를 deployment_uid로, replicas_before=1, replicas_during=0, replicas_after=1, restore_deadline_sec=55를 기록하세요. act 5는 전용 VM 컨트롤러를 정상 축소하고 복구합니다. evidence/05.json에서 같은 정책 UID, 등록 부재, 위반 저장, 복구 뒤 거부와 새 컨트롤러 Pod를 구분하세요.
  6. recovery.json에 05.json의 facts.replicas_restored_at, facts.recovery.registered_at, facts.recovery.response_at를 각각 같은 이름의 키로 옮기세요. replicas_mean=desired-count-not-policy-readiness, controller_pod=replaced, policy=same-uid, shutdown_evidence_sha256=05.json의 정규 JSON 해시를 적습니다. act 6은 새 위반 요청의 거부와 기준선 Pod 생존을 다시 확인합니다.
  7. dryrun.json에 mode=server, admission=evaluated, good=accepted-not-stored, bad=explicit-deny, existing=same-uid-running, evidence_sha256=06.json의 정규 JSON 해시를 기록하세요. act 7은 새 이름으로 server dry-run을 수행합니다. evidence/07.json의 정상 Pod 응답과 저장 부재, 위반 요청의 명시적 거부를 비교하세요.
  8. report.json에 shutdown=registration-removed-not-fail-bypass, policy=same-uid, controller_pod=replaced, existing=same-uid-running, dryrun=admission-without-storage를 기록하세요. shutdown_evidence_sha256와 dryrun_evidence_sha256에는 05.json과 07.json의 정규 JSON 해시를 넣습니다. act 8 뒤 전체 채점을 다시 실행하세요.

참고

명령은 python3 /opt/fixtures/kca_webhook_lab.py inspect, act 1부터 act 8, grade 1부터 grade 8입니다. grade는 입력과 보존한 실제 관측을 읽으며 장애를 다시 만들지 않습니다. 완료 act는 자료와 자원을 보존합니다. 부분 입력도 자동 덮어쓰지 않습니다. 중단된 실행은 결과가 불확실하므로 실패 원자료를 내려받고 새 실습에서 재현하세요. 정책 대상은 CREATE pods입니다. 모든 API·모든 설치 버전·고가용성에 일반화하지 마세요. Kubernetes 서버 dry-run

VM과 대상·대조 범위

inspect로 이번 VM의 vm.node_uid와 namespaces를 확인하세요. scope.json에 target=kca-webhook-target, control=kca-webhook-control, node_uid, namespaces를 기록합니다. namespaces는 실제 이름을 키, UID를 값으로 둡니다. act 1로 이번 VM의 범위를 보존하세요.

inspect의 vm.node_uid와 namespaces를 보세요. 이름과 UID는 다릅니다.

Deny·Fail 정책 직접 작성

policy.json에 policies.kyverno.io/v1의 ValidatingPolicy를 작성하세요. 이름 kca-webhook-label, validationActions=[Deny], failurePolicy=Fail, webhookConfiguration.timeoutSeconds=3, evaluation.background.enabled=false입니다. matchConstraints.namespaceSelector.matchLabels는 kubernetes.io/metadata.name=kca-webhook-target이고 resourceRules는 apiGroups=[빈 문자열], apiVersions=[v1], operations=[CREATE], resources=[pods]입니다. validations의 expression은 "'environment' in object.metadata.?labels.orValue({})", message는 KCA_ENVIRONMENT_REQUIRED입니다. 불필요한 필드 없이 작성하고 act 2로 실제 등록을 확인하세요.

namespaceSelector는 namespace 라벨을 고릅니다. 검증 동작 Deny와 호출 실패 처리 Fail을 구분하세요.

호출 등록의 범위를 요청으로 확인

registration.json에 service=kyverno-svc, namespace=kyverno, path=/vpol/kca-webhook-label, selector_target=kca-webhook-target, selector_source=namespace-label, operation=CREATE, resource=pods, failure_policy=Fail, timeout_seconds=3, policy_uid=02.json의 facts.policy.metadata.uid를 기록하세요. act 3으로 등록과 범위 밖 무라벨 요청의 저장 UID를 관측하세요.

정책 선언뿐 아니라 02.json의 실제 service 경로·namespaceSelector·rules도 대조하세요. 범위 밖 요청은 Fail을 우회했다는 뜻이 아닙니다.

정상 허용·거부와 기존 Pod 기준선

act 4를 실행하세요. evidence/04.json의 facts.good는 라벨이 있는 Pod의 저장 UID, bad는 라벨 누락의 명시적 거부·미저장, existing은 같은 UID의 Running이어야 합니다. 에러 원문과 저장 여부를 함께 읽으세요.

AlreadyExists는 정책 거부가 아닙니다. 뒤 단계에서 기존 Pod의 UID를 이 기준선과 비교합니다.

정상 종료 뒤 정책과 등록의 다른 수명

shutdown-plan.json에 action=observe-graceful-shutdown, inspect의 controller.metadata.uid를 deployment_uid로, replicas_before=1, replicas_during=0, replicas_after=1, restore_deadline_sec=55를 기록하세요. act 5는 전용 VM 컨트롤러를 정상 축소하고 복구합니다. evidence/05.json에서 같은 정책 UID, 등록 부재, 위반 저장, 복구 뒤 거부와 새 컨트롤러 Pod를 구분하세요.

정책이 남아도 호출 등록이 사라질 수 있습니다. replicas=1 직후에 정책까지 복구됐다고 가정하지 마세요.

복구 시각과 실제 거부를 따로 검증

recovery.json에 05.json의 facts.replicas_restored_at, facts.recovery.registered_at, facts.recovery.response_at를 각각 같은 이름의 키로 옮기세요. replicas_mean=desired-count-not-policy-readiness, controller_pod=replaced, policy=same-uid, shutdown_evidence_sha256=05.json의 정규 JSON 해시를 적습니다. act 6은 새 위반 요청의 거부와 기준선 Pod 생존을 다시 확인합니다.

시각은 이벤트의 정확한 발생 시각이 아니라 실행기가 확인한 관측 시각입니다. 등록 확인과 실제 거부 응답을 같은 상태로 뭉개지 마세요.

서버 검증 성공과 저장 성공 구분

dryrun.json에 mode=server, admission=evaluated, good=accepted-not-stored, bad=explicit-deny, existing=same-uid-running, evidence_sha256=06.json의 정규 JSON 해시를 기록하세요. act 7은 새 이름으로 server dry-run을 수행합니다. evidence/07.json의 정상 Pod 응답과 저장 부재, 위반 요청의 명시적 거부를 비교하세요.

client dry-run은 서버 웹훅을 확인하지 않습니다. server dry-run의 정상 응답에 객체가 있다고 실제 저장됐다고 해석하지 마세요.

서로 다른 객체의 수명으로 사고 보고

report.json에 shutdown=registration-removed-not-fail-bypass, policy=same-uid, controller_pod=replaced, existing=same-uid-running, dryrun=admission-without-storage를 기록하세요. shutdown_evidence_sha256와 dryrun_evidence_sha256에는 05.json과 07.json의 정규 JSON 해시를 넣습니다. act 8 뒤 전체 채점을 다시 실행하세요.

재생성된 컨트롤러 Pod와 계속 살아 있는 기준선 Pod를 구분하세요. 보고서 해시만 맞춰도 앞 단계의 실제 원자료가 없으면 통과하지 못합니다.