注入・生成の規則と権限を立てる
한국어 원문으로 표시합니다.
목표
mutate 두 방식과 generate 두 방식을 매니페스트로 작성하고, generate 가 실제로 동작하는 데 필요한 RBAC 을 클러스터에 직접 세워 권한까지 검증합니다.
왜 중요한가
generate 규칙은 Kyverno 에서 가장 조용하게 실패하는 기능입니다. admission 은 성공하므로 kubectl 은 아무 오류도 내지 않고, 리소스만 생기지 않습니다. 원인은 대개 두 가지인데 match 가 안 됐거나 background 컨트롤러에 권한이 없는 것입니다. 이 실습에서 권한을 직접 만들고 auth can-i 로 확인해 보면, 나중에 현장에서 생성물이 안 보일 때 정책 YAML 을 뒤지는 대신 UpdateRequest 와 권한을 먼저 보게 됩니다. 사이드카 주입에 리소스 리밋을 함께 넣는 습관도 같은 종류의 예방 조치입니다.
단계
/root/kca-mutate/디렉터리를 만들고mutate-labels.yaml에 kindClusterPolicy,metadata.namekca-add-team-label을 쓰세요. 규칙add-managed-by를 만들어match의 kinds 에Deployment를 넣고,mutate.patchStrategicMerge로metadata.labels의kca.io/managed-by를kyverno로 넣게 하세요.- 같은 파일에 규칙
inject-sidecar를 추가하세요.match.any[0].resources.selector.matchLabels의kca.io/inject로 대상을 고르고,mutate.patchStrategicMerge.spec.template.spec.containers[0]에 namelog-collector, image, 그리고resources.limits의memory와cpu를 모두 넣으세요. /root/kca-mutate/mutate-json6902.yaml에 kindClusterPolicy를 쓰고spec.rules[0].mutate.patchesJson6902로 어노테이션kca.io/owner를 추가하는 add 연산을 작성하세요. 경로는/metadata/annotations/아래이며 키의 슬래시를 이스케이프해야 합니다./root/kca-mutate/generate-netpol.yaml에 kindClusterPolicy,metadata.namekca-generate-default-deny를 쓰세요. match 의 kinds 는Namespace,generate.apiVersion은networking.k8s.io/v1,kind는NetworkPolicy,name은default-deny,namespace는 새 네임스페이스 이름을 받는 변수,synchronize는true,generate.data.spec.policyTypes에는Ingress와Egress를 넣으세요./root/kca-mutate/generate-clone.yaml에 kindClusterPolicy,metadata.namekca-clone-baseline을 쓰세요.generate.kind는ConfigMap,name은kca-baseline,clone.namespace는kca-shared,clone.name은kca-baseline-config,synchronize는true이고data는 쓰지 마세요.- 클러스터에 네임스페이스
kca-shared를 만들고 그 안에 Rolekca-clone-reader를 실제로 만드세요. 코어 그룹의configmaps에get,list,watch만 허용하고delete는 넣지 마세요. - 클러스터에 네임스페이스
kyverno와 그 안의 ServiceAccountkyverno-background-controller를 만들고,kca-shared에 RoleBindingkca-clone-reader를 실제로 만들어 Rolekca-clone-reader를 그 서비스어카운트에 묶으세요. kca-shared에 ConfigMapkca-baseline-config를 실제로 만드세요. 데이터는log-level=info와retention=7d두 개입니다. 그 뒤kubectl auth can-i로 해당 서비스어카운트가 이 네임스페이스의 configmaps 는 읽을 수 있고 secrets 는 읽을 수 없는지 확인하세요.
참고
kubectl create role kca-clone-reader --verb=get,list,watch --resource=configmaps -n kca-shared로 빠르게 만들 수 있습니다.- 권한 확인은
kubectl auth can-i get configmaps --as=system:serviceaccount:kyverno:kyverno-background-controller -n kca-shared입니다. - 흔한 실수 1: generate 에 clone 과 data 를 같이 쓰는 것. 둘 중 하나만 고릅니다.
- 흔한 실수 2: JSON Patch 경로에서 키의 슬래시를 그대로 두는 것. 경로 구분자와 구별되지 않습니다.
patchStrategicMerge 로 라벨 주입
/root/kca-mutate/ 디렉터리를 만들고 mutate-labels.yaml 에 kind ClusterPolicy, metadata.name kca-add-team-label 을 쓰세요. 규칙 add-managed-by 를 만들어 match 의 kinds 에 Deployment 를 넣고, mutate.patchStrategicMerge 로 metadata.labels 의 kca.io/managed-by 를 kyverno 로 넣게 하세요.
mutate 블록 안에 오브젝트 모양을 그대로 그리면 그 부분만 병합됩니다. 라벨 키에 점과 슬래시가 있으면 YAML 에서 따옴표로 감싸세요.
사이드카 주입과 리소스 리밋
같은 파일에 규칙 inject-sidecar 를 추가하세요. match.any[0].resources.selector.matchLabels 의 kca.io/inject 로 대상을 고르고, mutate.patchStrategicMerge.spec.template.spec.containers[0] 에 name log-collector, image, 그리고 resources.limits 의 memory 와 cpu 를 모두 넣으세요.
주입하는 컨테이너에 리소스 리밋을 반드시 넣어야 합니다. mutate 가 validate 보다 먼저 돈다는 사실이 왜 여기서 중요한지 떠올리세요. 그리고 모든 워크로드가 아니라 라벨로 고른 것에만 주입되게 하세요.
JSON Patch 로 어노테이션 추가
/root/kca-mutate/mutate-json6902.yaml 에 kind ClusterPolicy 를 쓰고 spec.rules[0].mutate.patchesJson6902 로 어노테이션 kca.io/owner 를 추가하는 add 연산을 작성하세요. 경로는 /metadata/annotations/ 아래이며 키의 슬래시를 이스케이프해야 합니다.
JSON Pointer 는 슬래시로 경로를 나눕니다. 키 이름 자체에 슬래시가 들어가면 특별한 이스케이프가 필요하고, 그 표기를 모르면 경로가 엉뚱한 곳을 가리킵니다.
네임스페이스마다 default-deny 생성
/root/kca-mutate/generate-netpol.yaml 에 kind ClusterPolicy, metadata.name kca-generate-default-deny 를 쓰세요. match 의 kinds 는 Namespace, generate.apiVersion 은 networking.k8s.io/v1, kind 는 NetworkPolicy, name 은 default-deny, namespace 는 새 네임스페이스 이름을 받는 변수, synchronize 는 true, generate.data.spec.policyTypes 에는 Ingress 와 Egress 를 넣으세요.
generate 는 무엇을(apiVersion/kind), 어떤 이름으로, 어느 네임스페이스에 만들지를 모두 적어야 합니다. 대상 네임스페이스는 방금 만들어진 그 네임스페이스이므로 변수로 받습니다.
clone 방식으로 복제하기
/root/kca-mutate/generate-clone.yaml 에 kind ClusterPolicy, metadata.name kca-clone-baseline 을 쓰세요. generate.kind 는 ConfigMap, name 은 kca-baseline, clone.namespace 는 kca-shared, clone.name 은 kca-baseline-config, synchronize 는 true 이고 data 는 쓰지 마세요.
clone 은 원본의 네임스페이스와 이름을 지정합니다. data 와 함께 쓸 수 없다는 점, 그리고 원본 변경을 따라가게 하려면 어떤 필드가 필요한지 확인하세요.
복제 원본을 읽을 Role 만들기
클러스터에 네임스페이스 kca-shared 를 만들고 그 안에 Role kca-clone-reader 를 실제로 만드세요. 코어 그룹의 configmaps 에 get, list, watch 만 허용하고 delete 는 넣지 마세요.
여기서부터 실제 클러스터입니다. 읽기만 필요하므로 동사는 세 개면 충분하고, 코어 그룹 리소스의 apiGroups 는 빈 문자열입니다.
백그라운드 컨트롤러에 바인딩
클러스터에 네임스페이스 kyverno 와 그 안의 ServiceAccount kyverno-background-controller 를 만들고, kca-shared 에 RoleBinding kca-clone-reader 를 실제로 만들어 Role kca-clone-reader 를 그 서비스어카운트에 묶으세요.
대상은 kyverno 네임스페이스의 서비스어카운트입니다. 그 네임스페이스와 서비스어카운트도 이 실습 환경에는 없으니 함께 만들어야 합니다.
원본 컨피그맵과 권한 검증
kca-shared 에 ConfigMap kca-baseline-config 를 실제로 만드세요. 데이터는 log-level=info 와 retention=7d 두 개입니다. 그 뒤 kubectl auth can-i 로 해당 서비스어카운트가 이 네임스페이스의 configmaps 는 읽을 수 있고 secrets 는 읽을 수 없는지 확인하세요.
복제 원본이 실제로 있어야 clone 이 성립합니다. 그리고 kubectl auth can-i 에 --as 로 서비스어카운트를 흉내 내면 권한이 제대로 붙었는지 손으로 확인할 수 있습니다.