Validating Admission Controller는 kube-apiserver에서 클러스터로 들어오는 요청을 검토하여 정책에 부합하지 않는 요청을 거부하는 기능을 수행하는 플러그인이다. 즉, 잘못된 설정이 적용되는 것을 사전에 차단하여 클러스터의 보안과 안정성을 유지할 수 있다.
- Admission Webhook Server는 API 서버의 요청 처리 과정 중에 개입하여 요청을 검증하거나 변환하는 확장 메커니즘이다.
- Mutating Webhooks: API 서버가 최초 요청을 수신한 후, 인증 및 권한 부여가 완료된 다음 가장 먼저 호출된다. (이 단계에서 요청 객체가 수정 될 수 있다.)
- Validating Webhooks: 모든 변이(Mutating)가 완료된 후, 최종 객체에 대한 유효성을 검증한다.
Validating Admission Controller | Mutating Admission Controller | |
역할 | 정책을 검증하고 거부할 수 있음 | 요청을 자동 수정할 수 있음 |
수행 가능 작업 | 허용 또는 거부 | 요청 내용을 변경 후 승인 |
예시 | CPU/메모리 제한 초과하면 거부 | 특정 라벨 자동 추가 |
✅ Mutating Admission Controller → 요청을 자동으로 변경 가능
✅ Validating Admission Controller → 정책 위반 시 요청을 거부
Validating Admission Controller
- ValidatingWebhookConfiguration
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: "pod-policy.example.com"
webhooks:
- name: "pod-policy.example.com" # webhook 이름
rules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE"]
resources: ["pods"]
scope: "Namespaced"
clientConfig:
service:
namespace: "example-namespace"
name: "example-service"
caBundle: <CA_BUNDLE>
admissionReviewVersions: ["v1"]
sideEffects: None
timeoutSeconds: 5
Mutating Admission Controller
- MutatingWebhookConfiguration
[ Mutating Admission 실습 ]
1. Create TLS secret webhook-server-tls for secure webhook communication in webhook-demo namespace.
참고) https://kubernetes.io/docs/reference/kubectl/generated/kubectl_create/kubectl_create_secret_tls/
controlplane ~ ➜ kubectl -n webhook-demo create secret tls webhook-server-tls \
> --cert "/root/keys/webhook-server-tls.crt" \
> --key "/root/keys/webhook-server-tls.key"
secret/webhook-server-tls created
- tls.crt: 서버의 인증서(Certificate)
클라이언트가 서버의 신원을 확인할 수 있도록 하는 공개 키 인증서이다. ( PEM 형식) - tls.key: 인증서와 쌍을 이루는 비공개 키(Private Key)
서버가 자신의 신원을 증명하고, 클라이언트와의 통신을 암호화하는 데 사용된다. ( PEM 형식)
2. Create webhook deployment now.
# 웹훅 서버를 실행하는 컨테이너를 관리하는 Deployment
# TLS 인증서를 Secret에서 불러와 보안이 강화된 HTTPS 서버 실행
controlplane ~ ➜ cat /root/webhook-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: webhook-server
namespace: webhook-demo
labels:
app: webhook-server
spec:
replicas: 1
selector:
matchLabels:
app: webhook-server
template:
metadata:
labels:
app: webhook-server
spec:
securityContext:
runAsNonRoot: true # 컨테이너를 root 사용자가 아닌 일반 사용자로 실행
runAsUser: 1234 # 사용자 ID
containers:
- name: server
image: stackrox/admission-controller-webhook-demo:latest
imagePullPolicy: Always # 항상 최신 이미지를 가져옴
ports:
- containerPort: 8443
name: webhook-api
volumeMounts: # 컨테이너 내부에서 TLS 인증서를 /run/secrets/tls 경로에 읽기 전용(readOnly: true)으로 마운트
- name: webhook-tls-certs
mountPath: /run/secrets/tls
readOnly: true
volumes:
- name: webhook-tls-certs
secret: # 위에서 만든 시크릿 기반 TLS 인증서
secretName: webhook-server-tls
controlplane ~ ➜ kubectl apply -f webhook-deployment.yaml
deployment.apps/webhook-server created
3. webhook service 만들기
controlplane ~ ➜ cat webhook-service.yaml
apiVersion: v1
kind: Service
metadata:
name: webhook-server
namespace: webhook-demo
spec:
selector:
app: webhook-server
ports:
- port: 443
targetPort: webhook-api
controlplane ~ ➜ kubectl apply -f webhook-service.yaml
service/webhook-server created
4. webhook-configuration 배포하기
- Pod가 생성될 때마다 웹훅 서버(/mutate)에 요청을 보냄
controlplane ~ ➜ cat webhook-configuration.yaml
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
name: demo-webhook
webhooks:
- name: webhook-server.webhook-demo.svc # 웹훅의 이름 - 쿠버네티스 Service를 통해 웹훅 서버에 요청을 보냄
clientConfig:
service:
name: webhook-server
namespace: webhook-demo
path: "/mutate" # /mutate 엔드포인트로 웹훅 요청을 전달
caBundle: LS0tLS1.... # (Base64 인코딩된 CA 인증서)
rules:
- operations: [ "CREATE" ] # Pod가 생성될 때만 웹훅이 실행됨
apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
admissionReviewVersions: ["v1beta1"] # 지원하는 AdmissionReview 버전
sideEffects: None # 이 웹훅이 외부 리소스에 추가적인 요청을 하지 않음 (예: DB 업데이트 없음)
controlplane ~ ➜ kubectl apply -f webhook-configuration.yaml
mutatingwebhookconfiguration.admissionregistration.k8s.io/demo-webhook created
→ Denies all request for pod to run as root in container if no securityContext is provided.
→ If no value is set for runAsNonRoot, a default of true is applied, and the user ID defaults to 1234
→ Allow to run containers as root if runAsNonRoot set explicitly to false in the securityContext
5. pod with no securityContext 배포하기
controlplane ~ ➜ cat pod-with-defaults.yaml
# A pod with no securityContext specified.
# Without the webhook, it would run as user root (0). The webhook mutates it
# to run as the non-root user with uid 1234.
apiVersion: v1
kind: Pod
metadata:
name: pod-with-defaults
labels:
app: pod-with-defaults
spec:
restartPolicy: OnFailure
containers:
- name: busybox
image: busybox
command: ["sh", "-c", "echo I am running as user $(id -u)"]
controlplane ~ ➜ kubectl apply -f pod-with-defaults.yaml
pod/pod-with-defaults created
controlplane ~ ➜ kubectl get pods pod-with-defaults -o yaml | grep runAs
runAsNonRoot: true
runAsUser: 1234
6. Deploy pod with a securityContext explicitly allowing it to run as root
controlplane ~ ➜ cat pod-with-override.yaml
# A pod with a securityContext explicitly allowing it to run as root.
# The effect of deploying this with and without the webhook is the same. The
# explicit setting however prevents the webhook from applying more secure
# defaults.
apiVersion: v1
kind: Pod
metadata:
name: pod-with-override
labels:
app: pod-with-override
spec:
restartPolicy: OnFailure
securityContext:
runAsNonRoot: false
containers:
- name: busybox
image: busybox
command: ["sh", "-c", "echo I am running as user $(id -u)"]
controlplane ~ ➜ kubectl apply -f pod-with-override.yaml
pod/pod-with-override created
7. Deploy a pod with a conflicting securityContext i.e. pod running with a user id of 0 (root)
-> Admission Controller가 작동하는지 확인하기 위한 용도의 Pod 생성
controlplane ~ ➜ cat pod-with-conflict.yaml
# A pod with a conflicting securityContext setting: it has to run as a non-root
# user, but we explicitly request a user id of 0 (root).
# Without the webhook, the pod could be created, but would be unable to launch
# due to an unenforceable security context leading to it being stuck in a
# 'CreateContainerConfigError' status. With the webhook, the creation of
# the pod is outright rejected.
apiVersion: v1
kind: Pod
metadata:
name: pod-with-conflict
labels:
app: pod-with-conflict
spec:
restartPolicy: OnFailure
securityContext:
runAsNonRoot: true
runAsUser: 0
containers:
- name: busybox
image: busybox
command: ["sh", "-c", "echo I am running as user $(id -u)"]
controlplane ~ ➜ kubectl apply -f pod-with-conflict.yaml
Error from server: error when creating "pod-with-conflict.yaml": admission webhook "webhook-server.webhook-demo.svc" denied the request: runAsNonRoot specified, but runAsUser set to 0 (the root user)
# 거절 -> 제대로 작동하는 것 확인
참고: https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/
'Container > Kubernetes' 카테고리의 다른 글
[K8S] Autoscaling - VPA (0) | 2025.02.26 |
---|---|
[K8S] Autoscaling - HPA (0) | 2025.02.26 |
[K8S] Admission Controller (0) | 2025.02.24 |
[K8S] Kustomize Overlay/Components (0) | 2025.02.24 |
[K8S] Kustomize Patches (0) | 2025.02.23 |