[AEWS] #6์ฃผ์ฐจ Kyverno ์‹ค์Šต (5)

25๋…„๋„ AWS EKS Hands-on Study ์Šคํ„ฐ๋”” ์ •๋ฆฌ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

 

Kyverno

etc-image-0

Kyverno๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๋„ค์ดํ‹ฐ๋ธŒ ์ •์ฑ… ์—”์ง„์œผ๋กœ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ์ •์ฑ…์„ ์ •์˜ / ๊ฒ€์ฆ / ๋ณ€ํ™˜ / ์ ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋ฉฐ,

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค CRD๋ฅผ ํ™œ์šฉํ•ด YAML ๊ธฐ๋ฐ˜์œผ๋กœ ์ •์ฑ…์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

Validation (๊ฒ€์ฆ)

  • ์ž˜๋ชป๋œ ๋ฆฌ์†Œ์Šค๊ฐ€ ํด๋Ÿฌ์Šคํ„ฐ์— ์ƒ์„ฑ๋˜์ง€ ์•Š๋„๋ก ์ฐจ๋‹จํ•œ๋‹ค.
  • Admission Controller๋กœ ๋™์ž‘ํ•˜์—ฌ ์ •์ฑ…์„ ๋งŒ์กฑํ•˜์ง€ ์•Š๋Š” ๋ฆฌ์†Œ์Šค๋Š” Denied ์ฒ˜๋ฆฌํ•œ๋‹ค.

Mutation (๋ณ€๊ฒฝ)

  • ๊ธฐ์กด ๋ฆฌ์†Œ์Šค๋ฅผ ์ž๋™์œผ๋กœ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • MutatingAdmissionWebhook์„ ํ™œ์šฉํ•˜์—ฌ ๋ฆฌ์†Œ์Šค๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค.

Generation (์ƒ์„ฑ)

  • ํŠน์ • ๋ฆฌ์†Œ์Šค๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ ์ž๋™์œผ๋กœ ๋‹ค๋ฅธ ๋ฆฌ์†Œ์Šค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ด๋Š” Kubernetes ๋ฆฌ์†Œ์Šค ํ…œํ”Œ๋ฆฟ์„ ์ž๋™ํ™”ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

Verification (์„œ๋ช… ๊ฒ€์ฆ)

  • ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€ ์„œ๋ช…์„ ๊ฒ€์ฆํ•˜์—ฌ ๋ณด์•ˆ ์ •์ฑ…์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

kyverno ์•„ํ‚คํ…์ฒ˜

etc-image-1

 

Kyverno๋Š” Webhook, Engine, Report Controller, Background Controller ๋“ฑ์˜ ์ฃผ์š” ์ปดํฌ๋„ŒํŠธ๋กœ ๋™์ž‘ํ•œ๋‹ค.

 

 

Webhook Controller (์›นํ›… ์ปจํŠธ๋กค๋Ÿฌ)

  • ValidatingWebhookConfiguration ๋ฐ MutatingWebhookConfiguration์„ ๊ด€๋ฆฌํ•œ๋‹ค.
  • ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค API ์„œ๋ฒ„๊ฐ€ ์š”์ฒญ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋„๋ก Webhook์„ ๋“ฑ๋กํ•œ๋‹ค.
  • ์ž๋™์œผ๋กœ TLS ์ธ์ฆ์„œ๋ฅผ ๊ด€๋ฆฌํ•˜์—ฌ Webhook ๋ณด์•ˆ์„ ์œ ์ง€ํ•œ๋‹ค.
  • Webhook ์š”์ฒญ์„ ๋ฐ›์œผ๋ฉด Engine ์ปจํŠธ๋กค๋Ÿฌ๋กœ ์ „๋‹ฌํ•˜์—ฌ ์ •์ฑ…์„ ์ ์šฉํ•œ๋‹ค.

Engine Controller (์—”์ง„ ์ปจํŠธ๋กค๋Ÿฌ)

  • Kyverno ์ •์ฑ…์„ ์ฒ˜๋ฆฌํ•˜๋Š” ํ•ต์‹ฌ ์—”์ง„์œผ๋กœ ๋ณ€ํ˜•(Mutate), ๊ฒ€์ฆ(Validate), ์ƒ์„ฑ(Generate) ๋“ฑ์˜ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
  • Webhook Controller์™€ ์—ฐ๋™ํ•˜์—ฌ ์š”์ฒญ์„ ๊ฒ€์‚ฌํ•˜๊ณ  ์ •์ฑ…์„ ์ ์šฉํ•œ๋‹ค.
  • ๊ธฐ์กด ๋ฆฌ์†Œ์Šค๋ฅผ ์Šค์บ”ํ•˜์—ฌ ์ •์ฑ… ์œ„๋ฐ˜ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๊ณ  ์ •์ฑ… ์ ์šฉ ๊ฒฐ๊ณผ๋ฅผ etcd ์ €์žฅ์†Œ์— ๋ฐ˜์˜ํ•œ๋‹ค.

Report Controllers (๋ฆฌํฌํŠธ ์ปจํŠธ๋กค๋Ÿฌ)

  • ์ •์ฑ… ์ ์šฉ ๊ฒฐ๊ณผ๋ฅผ ์ˆ˜์ง‘ํ•˜์—ฌ ๋ฆฌํฌํŠธ ์ƒ์„ฑํ•˜๋ฉฐ ์ •์ฑ… ์œ„๋ฐ˜ ์—ฌ๋ถ€๋ฅผ PolicyReport ๋ฆฌ์†Œ์Šค ํ˜•ํƒœ๋กœ ์ €์žฅํ•˜๋ฉฐ, ๊ด€๋ฆฌ์ž๋Š” kubectl get policyreport ๋ช…๋ น์–ด๋กœ ์ •์ฑ… ์œ„๋ฐ˜ ์—ฌ๋ถ€๋ฅผ ํ™•์ธ ๊ฐ€๋Šฅํ•˜๋‹ค.

Background Controller (๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ปจํŠธ๋กค๋Ÿฌ)

  • ๊ธฐ์กด ๋ฆฌ์†Œ์Šค์—๋„ ์ •์ฑ…์„ ์ ์šฉํ•œ๋‹ค.
  • Webhook ๋ฐฉ์‹์ด ์•„๋‹Œ ํด๋Ÿฌ์Šคํ„ฐ ๋‚ด ๊ธฐ์กด ๋ฆฌ์†Œ์Šค๋ฅผ ์ฃผ๊ธฐ์ ์œผ๋กœ ์Šค์บ”ํ•˜๊ณ  ์ •์ฑ… ์œ„๋ฐ˜ ์‚ฌํ•ญ์„ ์ž๋™์œผ๋กœ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ๋ณด๊ณ ํ•œ๋‹ค.

kyverno ์„ค์น˜

cat << EOF > kyverno-value.yaml
config:
  resourceFiltersExcludeNamespaces: [ kube-system ]

admissionController:
  serviceMonitor:
    enabled: true

backgroundController:
  serviceMonitor:
    enabled: true

cleanupController:
  serviceMonitor:
    enabled: true

reportsController:
  serviceMonitor:
    enabled: true
EOF
kubectl create ns kyverno
helm repo add kyverno https://kyverno.github.io/kyverno/
helm install kyverno kyverno/kyverno --version 3.3.7 -f kyverno-value.yaml -n kyverno


kubectl get pod,svc -n kyverno
NAME                                                READY   STATUS    RESTARTS   AGE
pod/kyverno-admission-controller-df7b67cf-xj8c2     0/1     Running   0          21s
pod/kyverno-background-controller-8544847cf-pg7dz   1/1     Running   0          21s
pod/kyverno-cleanup-controller-5db46d8ddb-44kq8     1/1     Running   0          21s
pod/kyverno-reports-controller-77f95686d4-xjppx     1/1     Running   0          21s

NAME                                            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
service/kyverno-background-controller-metrics   ClusterIP   10.100.113.109   <none>        8000/TCP   23s
service/kyverno-cleanup-controller              ClusterIP   10.100.151.180   <none>        443/TCP    23s
service/kyverno-cleanup-controller-metrics      ClusterIP   10.100.28.67     <none>        8000/TCP   23s
service/kyverno-reports-controller-metrics      ClusterIP   10.100.32.13     <none>        8000/TCP   23s
service/kyverno-svc                             ClusterIP   10.100.125.77    <none>        443/TCP    23s
service/kyverno-svc-metrics                     ClusterIP   10.100.71.20     <none>        8000/TCP   23s

 

์ธ์ฆ์„œ ํ™•์ธ

kubectl -n kyverno get secret kyverno-svc.kyverno.svc.kyverno-tls-ca -o jsonpath='{.data.tls\.crt}' | base64 -d
-----BEGIN CERTIFICATE-----
MIIC7TCCAdWgAwIBAgIBADANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA0qLmt5...
...
-----END CERTIFICATE-----

kubectl -n kyverno get secret kyverno-svc.kyverno.svc.kyverno-tls-ca -o jsonpath='{.data.tls\.crt}' | base64 -d | step certificate inspect --short
X.509v3 Root CA Certificate (RSA 2048) [Serial: 0]
  Subject:     *.kyverno.svc
  Issuer:      *.kyverno.svc
  Valid from:  2025-03-15T20:56:51Z
          to:  2026-03-15T21:56:51Z

 

 

Kyverno Webhook ์„œ๋ฒ„๋Š” ์ž์ฒด ์„œ๋ช…๋œ TLS ์ธ์ฆ์„œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๋ฐ kubectl get secret ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ TLS ์ธ์ฆ์„œ๋ฅผ ์ง์ ‘ ํ™•์ธ ๊ฐ€๋Šฅํ•˜๋‹ค.

Validating Webhook์—์„œ๋„ ๊ฐ™์€ CA ์ธ์ฆ์„œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ API ์„œ๋ฒ„์™€ ํ†ต์‹ ํ•œ๋‹ค.

 

ํด๋Ÿฌ์Šคํ„ฐ ์ •์ฑ… ์ ์šฉ

kubectl apply -f- << EOF
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-labels
spec:
  validationFailureAction: Enforce
  rules:
  - name: check-team
    match:
      any:
      - resources:
          kinds:
          - Pod
    validate:
      message: "label 'team' is required"
      pattern:
        metadata:
          labels:
            team: "?*"
EOF

kubectl get ClusterPolicy
NAME             ADMISSION   BACKGROUND   READY   AGE   MESSAGE
require-labels   true        true         True    26s   Ready

 

 

ํŒŒ๋“œ ์ƒ์„ฑ ํ…Œ์ŠคํŠธ

kubectl create deployment nginx --image=nginx
error: failed to create deployment: admission webhook "validate.kyverno.svc-fail" denied the request:

resource Deployment/default/nginx was blocked due to the following policies

require-labels:
  autogen-check-team: 'validation error: label ''team'' is required. rule autogen-check-team
    failed at path /spec/template/metadata/labels/team/'

 

Kyverno ์ •์ฑ…์ด ๋™์ž‘ํ•˜์—ฌ ๋ผ๋ฒจ์ด ์—†๋Š” ๊ฒฝ์šฐ ๋ฐฐํฌ๊ฐ€ ์ฐจ๋‹จ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

kubectl run nginx --image nginx --labels team=backend
pod/nginx created

kubectl get pod -l team=backend
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          10s

 

team=backend ๋ผ๋ฒจ์„ ํฌํ•จํ•˜๋ฉด ์ •์ƒ์ ์œผ๋กœ ์ƒ์„ฑ๋œ๋‹ค.

Muatate๋ฅผ ํ™œ์šฉํ•œ ํŒŒ๋“œ ์ž๋™ ๋ผ๋ฒจ๋ง ์ ์šฉ

kubectl apply -f- << EOF
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: add-labels
spec:
  rules:
  - name: add-team
    match:
      any:
      - resources:
          kinds:
          - Pod
    mutate:
      patchStrategicMerge:
        metadata:
          labels:
            +(team): bravo
EOF

kubectl get mutatingwebhookconfigurations
NAME                                    WEBHOOKS   AGE
aws-load-balancer-webhook               3          27m
kube-prometheus-stack-admission         1          5m55s
kyverno-policy-mutating-webhook-cfg     1          3m26s
kyverno-resource-mutating-webhook-cfg   1          3m26s
kyverno-verify-mutating-webhook-cfg     1          3m26s
pod-identity-webhook                    1          7h20m
vpc-resource-mutating-webhook           1          7h20m

kubectl get ClusterPolicy
NAME         ADMISSION   BACKGROUND   READY   AGE   MESSAGE
add-labels   true        true         True    17s   Ready

 

Kyverno์˜ Mutating ์ •์ฑ…์„ ์‚ฌ์šฉํ•˜์—ฌ Pod ์ƒ์„ฑ ์‹œ team=bravo ๋ผ๋ฒจ์„ ์ž๋™ ์ถ”๊ฐ€ํ•˜๋„๋ก ์„ค์ •ํ•œ๋‹ค.

 

kubectl run redis --image redis
pod/redis created

kubectl get pod redis --show-labels
NAME    READY   STATUS    RESTARTS   AGE   LABELS
redis   1/1     Running   0          8s    run=redis,team=bravo

 

๋ผ๋ฒจ์„ ๋ช…์‹œํ•˜์ง€ ์•Š์•˜์Œ์—๋„ team=bravo๊ฐ€ ์ž๋™ ์ถ”๊ฐ€๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.