- Authors

- Name
- Youngju Kim
- @fjvbn20031
1. Validate 규칙 상세
1.1 패턴 매칭(Pattern Matching)
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-run-as-non-root
spec:
validationFailureAction: Enforce
rules:
- name: check-security-context
match:
any:
- resources:
kinds:
- Pod
validate:
message: 'Containers must run as non-root'
pattern:
spec:
containers:
- securityContext:
runAsNonRoot: true
패턴 매칭 연산자:
?*: 비어있지 않은 값 (null이 아닌 모든 값)*: 모든 값 (null 포함)X|Y: X 또는 Y!X: X가 아닌 값>X,<X,>=X,<=X: 수치 비교
1.2 deny 규칙
조건 기반으로 리소스를 거부:
rules:
- name: deny-latest-tag
match:
any:
- resources:
kinds:
- Pod
validate:
message: "Using 'latest' tag is not allowed. Use a specific version tag."
deny:
conditions:
any:
- key: '{{ request.object.spec.containers[].image }}'
operator: AnyIn
value:
- '*:latest'
- '*:*'
1.3 CEL 표현식
Kubernetes 1.25+ CEL(Common Expression Language) 사용:
rules:
- name: check-replica-count
match:
any:
- resources:
kinds:
- Deployment
validate:
cel:
expressions:
- expression: 'object.spec.replicas >= 2'
message: 'Deployment must have at least 2 replicas'
- expression: 'object.spec.replicas <= 100'
message: 'Deployment cannot exceed 100 replicas'
1.4 foreach
컬렉션의 각 요소에 대해 검증:
rules:
- name: check-each-container
match:
any:
- resources:
kinds:
- Pod
validate:
message: 'All containers must have resource limits'
foreach:
- list: 'request.object.spec.containers'
deny:
conditions:
any:
- key: '{{ element.resources.limits.memory }}'
operator: Equals
value: ''
2. Mutate 규칙 상세
2.1 patchStrategicMerge
Kubernetes Strategic Merge Patch 방식:
rules:
- name: add-sidecar
match:
any:
- resources:
kinds:
- Deployment
selector:
matchLabels:
inject-sidecar: 'true'
mutate:
patchStrategicMerge:
spec:
template:
spec:
containers:
- name: log-collector
image: fluentbit:latest
volumeMounts:
- name: shared-logs
mountPath: /var/log/app
volumes:
- name: shared-logs
emptyDir: {}
2.2 patchesJson6902
JSON Patch (RFC 6902) 방식:
rules:
- name: add-annotation
match:
any:
- resources:
kinds:
- Service
mutate:
patchesJson6902: |-
- op: add
path: /metadata/annotations/modified-by
value: kyverno
- op: replace
path: /spec/type
value: ClusterIP
2.3 foreach mutate
rules:
- name: add-pull-secret-to-all-containers
match:
any:
- resources:
kinds:
- Pod
mutate:
foreach:
- list: 'request.object.spec.containers'
patchStrategicMerge:
spec:
imagePullSecrets:
- name: my-registry-secret
3. Generate 규칙 상세
3.1 data 기반 생성
정책에 정의된 데이터로 리소스 생성:
rules:
- name: generate-default-limitrange
match:
any:
- resources:
kinds:
- Namespace
generate:
apiVersion: v1
kind: LimitRange
name: default-limits
namespace: '{{ request.object.metadata.name }}'
synchronize: true
data:
spec:
limits:
- default:
cpu: 500m
memory: 512Mi
defaultRequest:
cpu: 100m
memory: 128Mi
type: Container
3.2 clone 기반 생성
기존 리소스를 복제:
rules:
- name: clone-configmap
match:
any:
- resources:
kinds:
- Namespace
generate:
apiVersion: v1
kind: ConfigMap
name: shared-config
namespace: '{{ request.object.metadata.name }}'
synchronize: true
clone:
namespace: default
name: template-configmap
3.3 synchronize 옵션
synchronize: true일 때:
- 소스 리소스 변경 시 생성된 리소스도 자동 업데이트
- Background Controller가 동기화 담당
- 생성된 리소스의 수동 수정은 자동으로 복원됨
4. 변수와 컨텍스트
4.1 JMESPath 변수
rules:
- name: add-ns-label
match:
any:
- resources:
kinds:
- Deployment
mutate:
patchStrategicMerge:
metadata:
labels:
namespace: '{{ request.object.metadata.namespace }}'
owner: '{{ request.userInfo.username }}'
4.2 API 호출 컨텍스트
rules:
- name: check-namespace-labels
match:
any:
- resources:
kinds:
- Pod
context:
- name: namespaceInfo
apiCall:
urlPath: '/api/v1/namespaces/{{ request.namespace }}'
jmesPath: "metadata.labels.environment || 'unknown'"
validate:
message: 'Pods can only run in labeled namespaces'
deny:
conditions:
any:
- key: '{{ namespaceInfo }}'
operator: Equals
value: 'unknown'
4.3 ConfigMap 룩업
rules:
- name: check-allowed-registries
match:
any:
- resources:
kinds:
- Pod
context:
- name: allowedRegistries
configMap:
name: allowed-registries
namespace: kyverno
validate:
message: 'Image must be from an allowed registry'
foreach:
- list: 'request.object.spec.containers'
deny:
conditions:
all:
- key: '{{ element.image }}'
operator: AnyNotIn
value: '{{ allowedRegistries.data.registries }}'
5. 고급 패턴
5.1 조건부 앵커(Conditional Anchors)
# () 앵커: 조건부 - 필드가 존재하면 검증
validate:
pattern:
spec:
template:
spec:
containers:
- (image): "*/nginx:*" # nginx 이미지인 경우에만
resources:
limits:
memory: ">=256Mi"
# X() 부정 앵커: 필드가 존재하지 않아야 함
validate:
pattern:
spec:
template:
spec:
containers:
- name: "*"
X(securityContext):
X(privileged): true # privileged가 true이면 안 됨
5.2 전역 앵커
# =() 동등 앵커: 값이 같아야 함
validate:
pattern:
spec:
=(replicas): '>=3' # replicas가 설정되어 있으면 3 이상
6. 정리
Kyverno 정책 엔진의 핵심:
- validate: 패턴 매칭, deny 조건, CEL 표현식, foreach로 다양한 검증
- mutate: Strategic Merge Patch, JSON Patch로 리소스 자동 수정
- generate: data/clone 기반 리소스 자동 생성, synchronize로 동기화
- 변수 시스템: JMESPath, API 호출, ConfigMap 룩업으로 동적 정책
- 앵커 시스템: 조건부, 부정, 동등 앵커로 세밀한 패턴 매칭
다음 글에서는 Kyverno의 이미지 검증 기능과 공급망 보안을 다룹니다.