🔴 Advanced

Kyverno a OPA Gatekeeper — admission control a policy-as-code

Policy-as-code v Kubernetes je spôsob, ako deklaratívne presadzovať organizačné pravidlá: "každý pod musí mať resource limits", "image môže pochádzať iba z nášho registry", "HostPath volumes sú zakázané". Namiesto pravidiel v runbook-e alebo code review checklist-e, admission controller blokuje nevyhovujúce manifesty pri kubectl apply.

Kyverno (Nirmata, CNCF Graduated 2024) a OPA Gatekeeper (Styra + CNCF — OPA graduovalo 2021, Gatekeeper ako subprojekt) sú dva dominantné open-source nástroje v tejto oblasti. Obidva fungujú ako ValidatingAdmissionWebhook (a voliteľne MutatingAdmissionWebhook), ale rozchádzajú sa v filozofii, jazyku policy a operačnom modeli.

Tento článok ich porovnáva, ukazuje reálne policy pre typické K8s scenáre a pomôže rozhodnúť, ktorý nástroj patrí do vášho stacku.


Admission control v skratke

Každý kubectl apply prechádza cez niekoľko fáz API servera:

kubectl apply
    │
    ▼
┌─────────────────────────────────────────────────────┐
│  kube-apiserver                                     │
│                                                     │
│  ┌─────────────┐   ┌──────────────┐   ┌──────────┐  │
│  │Authentication│ → │ Authorization │ → │Admission │  │
│  │(kto je kto)  │   │(čo smie robiť)│   │Controllers│  │
│  └─────────────┘   └──────────────┘   └────┬─────┘  │
│                                             │        │
│                     Mutating webhooks ◄────┤        │
│                                             │        │
│                     Validating webhooks ◄──┤        │
│                                             │        │
│                                             ▼        │
│                                      ┌──────────┐   │
│                                      │  etcd    │   │
│                                      └──────────┘   │
└─────────────────────────────────────────────────────┘

Mutating webhooks môžu upraviť manifest pred uložením (napr. automaticky pridať label, injektovať sidecar). Validating webhooks môžu len schváliť alebo zamietnuť — nemôžu meniť.

Oba nástroje používajú tieto webhooks. Kyverno + Gatekeeper sa inštalujú ako K8s deployments, ktoré sa registrujú do API servera ako webhook handlery.


Dve filozofie — YAML-native vs Rego

Najvýraznejší rozdiel medzi Kyverno a Gatekeeper je jazyk pre policy:

Kyverno — policy je natívne Kubernetes CRD s YAML syntaxou, ktorá je blízka K8s manifestom. Nemusíte sa učiť nový jazyk.

Gatekeeper — policy sa píšu v Rego, deklaratívnom jazyku OPA. Rego je silnejší (Turing-complete? formálne áno, ale obmedzený), ale má strmú učenlivú krivku.

Porovnanie rovnakej policy — "pod musí mať resource limits":

Kyverno policy

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-resource-limits
spec:
  validationFailureAction: Enforce
  background: true
  rules:
    - name: check-resources
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        message: "CPU a memory limits musia byť definované."
        pattern:
          spec:
            containers:
              - name: "*"
                resources:
                  limits:
                    memory: "?*"
                    cpu: "?*"

Sedem riadkov validate pattern-u. "?*" znamená "nejaká hodnota" (anchor modifier).

Gatekeeper policy

Gatekeeper potrebuje dve komponenty — ConstraintTemplate (Rego logika) a Constraint (inštancia s parametrami):

# 1. ConstraintTemplate — definuje validátor v Rego
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8srequireresourcelimits
spec:
  crd:
    spec:
      names:
        kind: K8sRequireResourceLimits
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequireresourcelimits

        violation[{"msg": msg}] {
          container := input.review.object.spec.containers[_]
          not container.resources.limits.cpu
          msg := sprintf("container '%s' nemá CPU limit", [container.name])
        }

        violation[{"msg": msg}] {
          container := input.review.object.spec.containers[_]
          not container.resources.limits.memory
          msg := sprintf("container '%s' nemá memory limit", [container.name])
        }
# 2. Constraint — aplikuje ConstraintTemplate na konkrétne resources
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequireResourceLimits
metadata:
  name: require-resource-limits
spec:
  enforcementAction: deny
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    namespaces:
      - production
      - staging

Ďalej použiteľnejšie keď máte viacero podobných kontrol — Rego je reusable. Pre jeden-off validation je Kyverno stručnejší.


Kyverno — deep dive

Architektúra

┌───────────────────────────────────────────────────┐
│  kyverno namespace                                │
│                                                   │
│  ┌─────────────────┐  ┌────────────────────────┐  │
│  │ admission       │  │ background controller  │  │
│  │ controller      │  │ (policy reports,       │  │
│  │ (webhook)       │  │  mutate existing)      │  │
│  └────────┬────────┘  └────────────────────────┘  │
│           │                                       │
│  ┌────────▼────────┐  ┌────────────────────────┐  │
│  │ reports          │  │ cleanup controller     │  │
│  │ controller       │  │ (scheduled deletion)   │  │
│  └──────────────────┘  └────────────────────────┘  │
└───────────────────────────────────────────────────┘

Kyverno v1.10+ má multiple controller architecture (bolo v jednom pode, teraz rozdelené):

  • admission-controller — vyhodnocuje admission requests
  • background-controller — generuje resources, mutate existujúce
  • reports-controllerPolicyReport CRDs pre audit
  • cleanup-controller — scheduled deletion policies

Inštalácia

helm repo add kyverno https://kyverno.github.io/kyverno/
helm install kyverno kyverno/kyverno \
  --namespace kyverno \
  --create-namespace \
  --set admissionController.replicas=3 \
  --set backgroundController.replicas=2 \
  --set reportsController.replicas=2 \
  --set cleanupController.replicas=2 \
  --version 3.3.0

# Komunitné policy (ClusterPolicies pre typické scenáre)
helm install kyverno-policies kyverno/kyverno-policies \
  --namespace kyverno \
  --set podSecurityStandard=restricted

Produkčný setup: minimálne 3 admission replicas pre HA (high availability cruciálne — ak Kyverno padne, admission môže blokovať celé klaster deploy-y, alebo propagovať failure policy).

Kyverno operations — validate, mutate, generate, verifyImages, cleanup

Kyverno podporuje 5 rôznych typov pravidiel:

  1. validate — schváliť alebo zamietnuť manifest
  2. mutate — upraviť manifest pred uložením (pridať labels, defaulty)
  3. generate — vytvoriť súvisiace resources (napr. pri vytvorení Namespace automaticky pridať NetworkPolicy)
  4. verifyImages — Cosign signature verification (supply chain security)
  5. cleanup — TTL-based delete existujúcich resources

Príklad každého:

# Mutate: automaticky pridať label s cost-center
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: add-cost-center-label
spec:
  rules:
    - name: add-label
      match:
        any:
          - resources:
              kinds: [Pod, Deployment]
      mutate:
        patchStrategicMerge:
          metadata:
            labels:
              cost-center: "{{ request.namespace.metadata.annotations.\"cost-center\" || 'unknown' }}"
# Generate: každý nový Namespace dostane default NetworkPolicy
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: generate-default-netpol
spec:
  rules:
    - name: default-deny
      match:
        any:
          - resources:
              kinds: [Namespace]
      generate:
        apiVersion: networking.k8s.io/v1
        kind: NetworkPolicy
        name: default-deny
        namespace: "{{ request.object.metadata.name }}"
        data:
          spec:
            podSelector: {}
            policyTypes: [Ingress, Egress]
# VerifyImages: iba signed imagy z nášho registry
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: verify-signed-images
spec:
  validationFailureAction: Enforce
  webhookTimeoutSeconds: 30
  rules:
    - name: check-signature
      match:
        any:
          - resources:
              kinds: [Pod]
      verifyImages:
        - imageReferences:
            - "registry.example.sk/*"
          attestors:
            - entries:
                - keyless:
                    subject: "https://github.com/example-sk/*/.github/workflows/release.yml@refs/heads/main"
                    issuer: "https://token.actions.githubusercontent.com"
# Cleanup: každá dev pod staršia ako 7 dní zmizne
apiVersion: kyverno.io/v2beta1
kind: ClusterCleanupPolicy
metadata:
  name: cleanup-old-dev-pods
spec:
  schedule: "0 2 * * *"  # každú noc 2 AM
  match:
    any:
      - resources:
          kinds: [Pod]
          namespaces: [dev]
  conditions:
    all:
      - key: "{{ target.metadata.creationTimestamp | time_to_hours }}"
        operator: GreaterThan
        value: 168  # 7 × 24

OPA Gatekeeper — deep dive

Architektúra

┌─────────────────────────────────────────────────┐
│  gatekeeper-system namespace                    │
│                                                 │
│  ┌──────────────────┐  ┌──────────────────┐    │
│  │ gatekeeper-       │  │ gatekeeper-       │    │
│  │ controller-       │  │ audit             │    │
│  │ manager (webhook) │  │ (existing res     │    │
│  │                   │  │  audit cron)      │    │
│  └───────────────────┘  └───────────────────┘    │
│                                                 │
│  OPA Rego runtime (embedded in controller)      │
└─────────────────────────────────────────────────┘

Gatekeeper má jednoduchú architektúru — jeden controller s embedded OPA runtime. Menej komponent, ale všetko beží v jednom pode.

Inštalácia

helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm install gatekeeper gatekeeper/gatekeeper \
  --namespace gatekeeper-system \
  --create-namespace \
  --set replicas=3 \
  --version 3.17.0

# Gatekeeper Library (preddefinované policy)
git clone https://github.com/open-policy-agent/gatekeeper-library
kubectl apply -f gatekeeper-library/library/general/

Rego — primer

Rego je deklaratívny jazyk, syntakticky medzi Datalog a Prolog. Hlavné koncepty:

package k8spsp  # packaging

# Boolean rule: fires when matched
deny[msg] {
    input.review.object.spec.hostNetwork == true
    msg := "hostNetwork is not allowed"
}

# Set comprehension (multiple violations)
violation[{"msg": msg}] {
    container := input.review.object.spec.containers[_]
    # ilustratívne — v reálnom policy kontrolujte runAsUser == 0 alebo runAsNonRoot == false
    container.securityContext.runAsNonRoot == false
    msg := sprintf("container %s môže bežať ako root", [container.name])
}

# Helper function
is_privileged(container) = true {
    container.securityContext.privileged == true
}

# Iterate collections
violation[{"msg": msg}] {
    some i
    container := input.review.object.spec.containers[i]
    is_privileged(container)
    msg := sprintf("container[%d] je privileged", [i])
}

Pre ConstraintTemplate sa Rego balí do spec.targets[].rego.

Constraint Templates + Constraints

Tento dvojdielny prístup je zároveň sila aj slabosť Gatekeeper:

  • Sila: ConstraintTemplate je znovu použiteľná definícia (napr. "require label X"). Pre konkrétny use-case vytvoríte Constraint s parametrami.
  • Slabosť: dvojakorá komplexita pre jednoduché pravidlá, ktoré by v Kyverne boli jeden YAML.

Príklad: require label pomocou ConstraintTemplate:

apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8srequiredlabels
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredLabels
      validation:
        openAPIV3Schema:
          type: object
          properties:
            labels:
              type: array
              items:
                type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequiredlabels

        violation[{"msg": msg, "details": {"missing_labels": missing}}] {
          provided := {label | input.review.object.metadata.labels[label]}
          required := {label | label := input.parameters.labels[_]}
          missing := required - provided
          count(missing) > 0
          msg := sprintf("you must provide labels: %v", [missing])
        }

Constraint:

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
  name: namespace-must-have-owner
spec:
  enforcementAction: deny
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Namespace"]
  parameters:
    labels:
      - owner
      - team
      - cost-center

Teraz môžete rovnakú K8sRequiredLabels použiť opakovane s rôznymi parametrami.

Validation vs Mutation v Gatekeeper

Gatekeeper historicky robil iba validation. Mutation podpora pribudla v 3.8 a používa iný CRD typ:

apiVersion: mutations.gatekeeper.sh/v1
kind: Assign
metadata:
  name: always-pull-images
spec:
  applyTo:
    - groups: [""]
      kinds: ["Pod"]
      versions: ["v1"]
  match:
    scope: Namespaced
  location: "spec.containers[name:*].imagePullPolicy"
  parameters:
    assign:
      value: "Always"

Gatekeeper mutation je stále menej používaná ako validation — väčšina tímov mutation rieši cez Kyverno alebo externé tools.


Porovnanie Kyverno vs Gatekeeper

Kritérium Kyverno OPA Gatekeeper
Policy jazyk YAML (K8s-native) Rego (deklaratívny)
Learning curve ✅ Plochá pre K8s ľudí ❌ Strmá (Rego)
Validation
Mutation ✅ Prvotriedny use-case ⚠️ Pozdejší add-on
Generate resources ✅ Unikátne
Image verification (Cosign) ✅ Prvotriedna ⚠️ Vyžaduje externý tool
Cleanup policies
Pre-existing policies (library) ✅ Kyverno Policies (~50 batch) ✅ Gatekeeper Library
PolicyReport CRDs ⚠️ Cez Audit
Background scanning ✅ Scans existing resources ✅ Audit cron
Performance ✅ O(n) — paralelný eval ⚠️ Rego compile overhead per policy
Multi-cluster policies ✅ Cez ArgoCD/Flux
CNCF status Graduated (2024) Graduated (OPA, 2021)
Governance Nirmata Styra + CNCF
Ecosystem outside K8s K8s-only ✅ OPA je univerzálny (API, Terraform, CI/CD)
Community size ✅ Rastúca (K8s-native appeal) ✅ Staršia, etablovaná

Praktické policy pre typické scenáre

1. Pod Security Standards — restricted level

Kyverno má pred-balenú kompletnú sadu:

helm install kyverno-policies kyverno/kyverno-policies \
  --namespace kyverno \
  --set podSecurityStandard=restricted

To aplikuje ~15 policies (no privileged, no hostPath, runAsNonRoot, atď.).

2. Iba schválené registries

# Kyverno
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: allowed-registries
spec:
  validationFailureAction: Enforce
  rules:
    - name: check-image
      match:
        any:
          - resources: {kinds: [Pod]}
      validate:
        message: "Image musí pochádzať z povoleného registry."
        pattern:
          spec:
            containers:
              - image: "registry.example.sk/* | ghcr.io/example-sk/*"

3. Externé služby nesmú ísť na internet

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: no-external-networking
spec:
  validationFailureAction: Enforce
  rules:
    - name: block-external-egress
      match:
        any:
          - resources: {kinds: [NetworkPolicy]}
      validate:
        message: "NetworkPolicy nesmie povoľovať egress na 0.0.0.0/0."
        deny:
          conditions:
            any:
              - key: "{{ request.object.spec.egress[].to[].ipBlock.cidr }}"
                operator: AnyIn
                value: ["0.0.0.0/0"]

4. Mandatory labels

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-team-label
spec:
  validationFailureAction: Enforce
  rules:
    - name: check-team
      match:
        any:
          - resources: {kinds: [Deployment, StatefulSet]}
      validate:
        message: "Deployment musí mať 'team' label."
        pattern:
          metadata:
            labels:
              team: "?*"

Pre-production testing — kyverno test a gator

Obe platformy podporujú CLI testing policies na mock resources pred aplikáciou do klastera.

Kyverno test

# Adresárová štruktúra
policies/
├── require-resources.yaml
└── test/
    ├── kyverno-test.yaml
    ├── good-pod.yaml
    └── bad-pod.yaml

# kyverno-test.yaml
name: require-resources-test
policies:
  - ../require-resources.yaml
resources:
  - good-pod.yaml
  - bad-pod.yaml
results:
  - policy: require-resource-limits
    rule: check-resources
    resource: good-pod
    result: pass
  - policy: require-resource-limits
    rule: check-resources
    resource: bad-pod
    result: fail

# Spustenie
kyverno test policies/test/

OPA Gatekeeper — gator CLI

# Test ConstraintTemplate + Constraint + input
gator test -f templates/ -f constraints/ -f inputs/

Obe CLIs v GitHub Actions = reliable shift-left — policy regressions nedojdu do produkcie.


Rollout stratégia

Admission controllers sú kritická infraštruktúra. Zlá policy môže zablokovať cluster operations. Fázy:

1. Audit mode (nie Enforce)

# Kyverno: validationFailureAction: Audit (nie Enforce)
# Gatekeeper: enforcementAction: dryrun

Niekoľko týždňov sledujte PolicyReport / gatekeeper-audit. Koľko resources by to blokovalo? Aké false positives?

2. Background scanning

# Kyverno
spec:
  background: true  # scan existing resources, not just admission

Identifikuje existujúce non-compliant resources. Daju sa opraviť postupne.

3. Enforce po dolaďení

Po 2-4 týždňoch auditu prepnite na enforce. Teraz zamietne nevyhovujúce manifesty.

4. Exclusion list pre system namespaces

spec:
  rules:
    - name: example
      match:
        any:
          - resources:
              kinds: [Pod]
      exclude:
        any:
          - resources:
              namespaces: [kube-system, kyverno, gatekeeper-system]

Nikdy neaplikujte policy na kube-system — môžete zablokovať upgrade control plane.

5. Monitoring

Sledujte latency admission webhooks — apiserver_admission_webhook_rejection_count, apiserver_admission_webhook_admission_duration_seconds.

# PrometheusRule
- alert: AdmissionWebhookLatencyHigh
  expr: |
    histogram_quantile(0.99,
      rate(apiserver_admission_webhook_admission_duration_seconds_bucket[5m])
    ) > 1
  for: 5m
  annotations:
    summary: "Admission webhook p99 latency > 1s — pomalá reakcia API servera"

Anti-patterns

  1. Start with Enforce mode — vždy audit najprv, inak zablokujete legitímnych workloadov a pokazíte si dôveru tímu.
  2. Žiadny exclusion pre system namespaces — cluster upgrade zlyhá, kube-scheduler nevie vytvoriť podu.
  3. Timeout webhooku príliš nízkytimeoutSeconds: 1 spôsobí, že policy zamietne všetko keď je controller pod load. Nastavte 10–30s.
  4. Failure policy Ignore — admission zlyhá, webhook je down, resources sa stále akceptujú. Open admission != secure. Používajte Fail, ak máte HA deployment.
  5. Monolitický policy súbor — keď máte 50+ rules v jednom ClusterPolicy, debugging je peklo. Rozdeľte na logické skupiny (security, cost, naming).
  6. Ignorovať RBAC na policies — kto môže meniť ClusterPolicy? Ak všetci devops, môžu si vypnúť svoje vlastné kontroly. Používajte git + review process, nie ad-hoc kubectl apply.
  7. Žiadne alerty na rejection rate — ak rejection_count klesne na 0, možno policy neplatí (webhook failed-open). Monitor.
  8. Rego bez unit testov — pri Gatekeeper, Rego kód bez gator verify = produkčný debugger.

Rozhodovací strom

Potrebujete admission control v K8s?
│
├── Tím hlavne K8s/DevOps, žiadne predošlé Rego znalosti?
│   ├── Potrebujete mutation + generate? → Kyverno
│   ├── Jednoduché validation + Pod Security? → Kyverno (menej boilerplate)
│   └── Všetko ostatné → Kyverno
│
├── Tím už používa OPA mimo K8s (Terraform, API gateways)?
│   └── OPA Gatekeeper (znalosť Rego sa prenáša)
│
├── Potrebujete pokročilú image verifikáciu (Cosign attestations)?
│   └── Kyverno (lepšia natívna podpora cez verifyImages)
│
├── Multi-cluster s complex policies a Rego už používate?
│   └── OPA Gatekeeper
│
└── Default voľba v 2026 pre čisto K8s use-case: **Kyverno**

Kyverno + Gatekeeper spolu?

Technicky môžete mať oba nainštalované. Každý operuje na vlastných CRD typoch, neprekážajú si. Dôvod prečo mať oba:

  • Kyverno pre K8s-native policies (najrýchlejší development cycle).
  • Gatekeeper pre reusable Rego policy už používaná mimo K8s.

V praxi je to rare setup — duplicitná prevádzková réžia. Väčšina tímov vyberá jeden.


Zhrnutie

Admission control je nutnosť v každom non-trivial K8s klastri. Bez neho closujete zodpovednosť za compliance na ľudí, ktorí si to nebudú pamätať pod tlakom.

V 2026 je Kyverno de-facto standard pre K8s-native tímy — má nižšiu learning curve, lepšie Cosign features, mutation aj generate v jednom nástroji.

OPA Gatekeeper má miesto tam, kde vaša organizácia už investovala do OPA mimo K8s (API authorization, Terraform plans, CI/CD gates). V tom prípade znalosť Rego sa prenáša a konsolidácia tooling-u má zmysel.

V oboch prípadoch: audit pred enforce, testovať cez CLI, monitoring webhook latencie, exkludovať system namespaces. Policy without ops disciplína = produkčný výbuch.


Ďalšie čítanie