Post

Part 19/26: Admission Controller와 Webhook

Part 19/26: Admission Controller와 Webhook

Admission Controller는 API 요청이 etcd에 저장되기 전에 요청을 검증하거나 변형하는 게이트키퍼 역할을 한다. 인증(Authentication)과 인가(Authorization) 이후, 영속화 직전에 실행된다.

API 요청 흐름

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
클라이언트 요청
     ↓
┌─────────────┐
│ API Server  │
├─────────────┤
│ Authentication (인증)
│ - 누구인가?
├─────────────┤
│ Authorization (인가)
│ - 권한이 있는가? (RBAC)
├─────────────┤
│ Admission Controller  ← 여기서 동작
│ - Mutating (변형)
│ - Validating (검증)
├─────────────┤
│ etcd (저장)
└─────────────┘

Admission Controller 종류

Built-in Admission Controllers

Kubernetes에 내장된 컨트롤러들이다.

1
2
3
4
5
6
# 활성화된 Admission Controller 확인
kubectl exec -n kube-system kube-apiserver-<node> -- \
  kube-apiserver --help | grep enable-admission-plugins

# 또는 API Server 매니페스트 확인
cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep admission

주요 Built-in Controllers:

Controller유형설명
NamespaceLifecycleValidating삭제 중인 namespace에 리소스 생성 방지
LimitRangerMutatingLimitRange 기본값 적용
ServiceAccountMutatingServiceAccount 자동 할당
DefaultStorageClassMutating기본 StorageClass 자동 적용
ResourceQuotaValidatingResourceQuota 초과 방지
PodSecurityValidatingPod Security Standards 적용
NodeRestrictionValidatingkubelet의 API 접근 제한
MutatingAdmissionWebhookMutating외부 웹훅 호출
ValidatingAdmissionWebhookValidating외부 웹훅 호출

Mutating vs Validating

Mutating Admission Controller:

  • 요청을 수정할 수 있음
  • 기본값 설정, 사이드카 주입 등
  • Validating보다 먼저 실행

Validating Admission Controller:

  • 요청을 검증만 함
  • 조건 불만족 시 거부
  • Mutating 이후에 실행
1
2
요청 → Mutating → Mutating → ... → Validating → Validating → ... → 저장
       (순차 실행)                    (병렬 실행 가능)

Admission Controller 설정

API Server에서 활성화/비활성화

1
2
3
4
5
6
7
8
9
10
11
12
13
# /etc/kubernetes/manifests/kube-apiserver.yaml
apiVersion: v1
kind: Pod
metadata:
  name: kube-apiserver
  namespace: kube-system
spec:
  containers:
  - command:
    - kube-apiserver
    - --enable-admission-plugins=NodeRestriction,PodSecurity,MutatingAdmissionWebhook,ValidatingAdmissionWebhook
    - --disable-admission-plugins=DefaultTolerationSeconds
    # ...

주의: API Server 매니페스트 수정 후 자동 재시작됨.

Admission Webhook

개념

Webhook은 외부 서비스를 호출하여 Admission 로직을 확장한다.

1
2
3
4
5
6
7
8
9
10
11
12
API 요청
    ↓
API Server
    ↓ HTTPS 호출
┌─────────────────┐
│ Webhook Service │  ← 사용자 정의 로직
│  (Pod/외부)     │
└─────────────────┘
    ↓ 응답
API Server
    ↓
etcd 저장

MutatingWebhookConfiguration

요청을 수정하는 웹훅을 등록한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
  name: mutating-webhook
webhooks:
- name: mutate.example.com
  clientConfig:
    service:
      name: webhook-service
      namespace: webhook-system
      path: "/mutate"
    caBundle: <base64-encoded-ca-cert>
  rules:
  - operations: ["CREATE", "UPDATE"]
    apiGroups: [""]
    apiVersions: ["v1"]
    resources: ["pods"]
  admissionReviewVersions: ["v1"]
  sideEffects: None
  failurePolicy: Fail
  namespaceSelector:
    matchLabels:
      webhook: enabled

ValidatingWebhookConfiguration

요청을 검증하는 웹훅을 등록한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: validating-webhook
webhooks:
- name: validate.example.com
  clientConfig:
    service:
      name: webhook-service
      namespace: webhook-system
      path: "/validate"
    caBundle: <base64-encoded-ca-cert>
  rules:
  - operations: ["CREATE", "UPDATE"]
    apiGroups: ["apps"]
    apiVersions: ["v1"]
    resources: ["deployments"]
  admissionReviewVersions: ["v1"]
  sideEffects: None
  failurePolicy: Fail

주요 설정 옵션

failurePolicy:

  • Fail: 웹훅 오류 시 요청 거부 (기본값)
  • Ignore: 웹훅 오류 시 요청 허용

sideEffects:

  • None: 부작용 없음 (드라이런 가능)
  • NoneOnDryRun: 드라이런 시 부작용 없음
  • Some: 부작용 있음
  • Unknown: 알 수 없음

namespaceSelector / objectSelector: 특정 namespace나 object에만 웹훅 적용.

1
2
3
4
5
6
namespaceSelector:
  matchLabels:
    environment: production
objectSelector:
  matchLabels:
    inject-sidecar: "true"

matchPolicy:

  • Exact: 정확히 지정된 리소스만
  • Equivalent: 동등한 리소스도 포함 (예: deployments와 deployments/scale)

실전 사용 사례

1. 사이드카 자동 주입 (Istio 스타일)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
  name: sidecar-injector
webhooks:
- name: sidecar-injector.istio.io
  clientConfig:
    service:
      name: istiod
      namespace: istio-system
      path: "/inject"
  rules:
  - operations: ["CREATE"]
    apiGroups: [""]
    apiVersions: ["v1"]
    resources: ["pods"]
  namespaceSelector:
    matchLabels:
      istio-injection: enabled

2. 이미지 레지스트리 검증

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: image-policy
webhooks:
- name: images.policy.example.com
  rules:
  - operations: ["CREATE", "UPDATE"]
    apiGroups: [""]
    apiVersions: ["v1"]
    resources: ["pods"]
  # 승인된 레지스트리의 이미지만 허용
  # 웹훅 서비스에서 이미지 출처 검증

3. 리소스 요청 강제

1
2
3
4
5
6
7
8
9
10
11
12
# 모든 Pod에 resources.requests 필수
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: require-resources
webhooks:
- name: resources.policy.example.com
  rules:
  - operations: ["CREATE"]
    apiGroups: [""]
    apiVersions: ["v1"]
    resources: ["pods"]

ImagePolicyWebhook

이미지 정책을 검증하는 특수 Admission Controller이다.

설정

1
2
3
4
5
6
7
8
9
10
11
12
# /etc/kubernetes/admission/admission-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: ImagePolicyWebhook
  configuration:
    imagePolicy:
      kubeConfigFile: /etc/kubernetes/admission/imagepolicy-kubeconfig.yaml
      allowTTL: 50
      denyTTL: 50
      retryBackoff: 500
      defaultAllow: false  # 기본 거부

API Server에서 활성화:

1
2
--admission-control-config-file=/etc/kubernetes/admission/admission-config.yaml
--enable-admission-plugins=ImagePolicyWebhook

Validating/Mutating Admission Policy (1.26+)

Kubernetes 1.26부터 CEL(Common Expression Language)을 사용한 인라인 정책이 가능하다.

ValidatingAdmissionPolicy

웹훅 없이 검증 규칙을 정의한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: "require-runasnonroot"
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
    - apiGroups:   [""]
      apiVersions: ["v1"]
      operations:  ["CREATE", "UPDATE"]
      resources:   ["pods"]
  validations:
  - expression: "object.spec.securityContext.runAsNonRoot == true"
    message: "Pods must run as non-root"
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
  name: "require-runasnonroot-binding"
spec:
  policyName: "require-runasnonroot"
  validationActions: [Deny]
  matchResources:
    namespaceSelector:
      matchLabels:
        environment: production

장점:

  • 웹훅 서비스 불필요
  • 지연 시간 감소
  • 클러스터 내에서 완결

트러블슈팅

Admission 거부 디버깅

1
2
3
4
5
6
7
8
9
10
11
12
# 에러 예시
Error from server: admission webhook "validate.example.com" denied the request: ...

# 웹훅 상태 확인
kubectl get validatingwebhookconfigurations
kubectl get mutatingwebhookconfigurations

# 웹훅 상세 확인
kubectl describe validatingwebhookconfiguration <name>

# 웹훅 서비스 로그 확인
kubectl logs -n webhook-system <webhook-pod>

웹훅 서비스 장애 시

failurePolicy: Fail 설정 시 웹훅 서비스가 다운되면 모든 관련 요청이 거부된다.

1
2
3
4
5
6
# 긴급 대응: 웹훅 설정 삭제
kubectl delete validatingwebhookconfiguration <name>

# 또는 failurePolicy를 Ignore로 변경
kubectl patch validatingwebhookconfiguration <name> \
  --type='json' -p='[{"op": "replace", "path": "/webhooks/0/failurePolicy", "value": "Ignore"}]'

웹훅 제외 namespace

1
2
3
4
5
6
7
8
# kube-system 등 중요 namespace 제외
namespaceSelector:
  matchExpressions:
  - key: kubernetes.io/metadata.name
    operator: NotIn
    values:
    - kube-system
    - kube-public

기술 면접 대비

자주 묻는 질문

Q: Mutating과 Validating Admission Controller의 실행 순서는?

A: Mutating이 먼저 실행되고, 그 다음 Validating이 실행된다. Mutating 컨트롤러들은 순차적으로 실행되며 이전 컨트롤러의 변경 사항이 다음 컨트롤러에 전달된다. Validating 컨트롤러들은 병렬로 실행될 수 있고, 하나라도 거부하면 전체 요청이 거부된다.

Q: Admission Webhook의 failurePolicy 옵션 차이는?

A: Fail은 웹훅이 오류를 반환하거나 응답하지 않으면 요청을 거부한다. Ignore는 웹훅 오류 시에도 요청을 허용한다. 보안이 중요한 웹훅은 Fail을, 선택적인 기능은 Ignore를 사용한다. Fail 설정 시 웹훅 서비스 가용성이 클러스터 운영에 영향을 미칠 수 있다.

Q: Admission Controller와 RBAC의 차이는?

A: RBAC은 “이 사용자가 이 동작을 할 수 있는가?”를 결정하는 인가(Authorization) 단계이다. Admission Controller는 인가를 통과한 요청에 대해 “이 요청의 내용이 정책에 부합하는가?”를 검사한다. 예를 들어 RBAC은 Pod 생성 권한을 확인하고, Admission Controller는 Pod 스펙이 보안 정책을 만족하는지 확인한다.

Q: 사이드카 주입은 어떻게 동작하는가?

A: MutatingWebhookConfiguration을 등록하여 Pod 생성 요청을 가로챈다. 웹훅 서비스가 Pod 스펙에 사이드카 컨테이너를 추가하여 응답한다. 원본 요청에는 사이드카가 없었지만 실제 생성되는 Pod에는 사이드카가 포함된다. Istio의 envoy 사이드카가 대표적인 예이다.

Q: 클러스터 부트스트랩 시 웹훅이 문제가 될 수 있는 이유는?

A: 웹훅 서비스가 아직 실행되지 않은 상태에서 failurePolicy: Fail 웹훅이 kube-system Pod에 적용되면 시스템 컴포넌트를 생성할 수 없어 데드락이 발생한다. 이를 방지하려면 kube-system namespace를 웹훅 대상에서 제외하거나, 시스템 컴포넌트용 exemption을 설정해야 한다.

CKA 시험 대비 필수 명령어

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Admission Controller 확인
kubectl exec -n kube-system kube-apiserver-<node> -- \
  kube-apiserver --help | grep enable-admission-plugins

# Webhook 설정 조회
kubectl get validatingwebhookconfigurations
kubectl get mutatingwebhookconfigurations
kubectl describe validatingwebhookconfiguration <name>

# API Server 매니페스트 확인
cat /etc/kubernetes/manifests/kube-apiserver.yaml

# 웹훅 삭제 (긴급 시)
kubectl delete validatingwebhookconfiguration <name>
kubectl delete mutatingwebhookconfiguration <name>

CKA 빈출 시나리오

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 시나리오 1: 활성화된 Admission Controller 확인
# API Server Pod에서 --enable-admission-plugins 플래그 확인

# 시나리오 2: 특정 Admission Controller 활성화
# /etc/kubernetes/manifests/kube-apiserver.yaml 수정
# --enable-admission-plugins=NodeRestriction,PodSecurity,...,NewPlugin

# 시나리오 3: Webhook 트러블슈팅
# 1. webhook configuration 확인
kubectl get validatingwebhookconfigurations -o yaml
# 2. webhook 서비스/pod 확인
kubectl get pods -n <webhook-namespace>
# 3. 로그 확인
kubectl logs -n <webhook-namespace> <webhook-pod>

다음 단계

This post is licensed under CC BY 4.0 by the author.