Перейти к содержимому
Hogin Hogin
Назад

Kyverno vs OPA Gatekeeper: когда брать что

10 мин чтения

Kyverno и OPA Gatekeeper решают одну задачу — не пустить «плохой» ресурс в кластер до того, как он будет сохранён в etcd. Оба проекта окончили CNCF с отличием, оба работают как admission webhook, у обоих есть готовые библиотеки политик на сотни правил. Разница не в качестве: вопрос в том, где заканчивается ваш Kubernetes. Если политика нужна только внутри кластера — Kyverno позволяет писать её тем же YAML, которым вы пишете Deployment. Если та же проверка должна сработать и в Terraform, и в GitHub Actions, и на API-шлюзе — OPA Rego переиспользуется везде без переписывания.

Разберём матрицу «когда что» без религии.

Содержание

Открыть содержание

Что такое admission webhook и зачем нужны оба инструмента

Любой kubectl apply проходит через несколько уровней защиты внутри API Server: аутентификацию субъекта, авторизацию через RBAC, OpenAPI-схемную валидацию поля типа — и лишь потом попадает в цепочку admission контроллеров. В этой цепочке работают два вида webhook: MutatingAdmissionWebhook (может изменить объект) и ValidatingAdmissionWebhook (только разрешить или отклонить). Только после прохождения обоих объект записывается в etcd и становится «реальным» состоянием кластера.

Kyverno и OPA Gatekeeper реализуют именно эти webhook: они перехватывают создание и обновление Pod, Deployment, Namespace, ServiceAccount и любого другого ресурса — в том числе Custom Resources — и применяют ваши политики до того, как что-то изменится. Ни один Pod с образом nginx:latest не проскочит мимо, если политика запрещает плавающие теги. Ни один Deployment без лимита CPU не уйдёт в etcd, если есть соответствующее правило.

Путь запроса через Admission Webhook

Принципиальное различие начинается на следующем шаге — как именно вы описываете, что считать нарушением.

Язык политик: YAML против Rego

Kyverno описывает политики как нативные Kubernetes Custom Resources — ClusterPolicy (действует на весь кластер) и Policy (ограничена одним namespace). Это обычные YAML-манифесты: вы кладёте их в GitOps-репозиторий, применяете через kubectl apply или Helm, и они живут рядом с Deployment и ConfigMap. Логика строится декларативно: блок match определяет, к каким ресурсам применяется правило, а дальше — один из трёх действий: validate (проверить), mutate (изменить), generate (создать новый ресурс).

С версии Kyverno 1.17 CEL-выражения получили статус v1. CEL — это тот же язык, что Kubernetes использует во встроенном ValidatingAdmissionPolicy; он компактен, типизирован и проверяется заранее без запуска. Сложная логика, которая раньше требовала громоздких deny.conditions в Rego, теперь пишется в одну строку прямо в поле expression.

Вот как выглядит запрет тегов :latest на Kyverno с CEL:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: disallow-latest-tag
spec:
  validationFailureAction: Enforce
  rules:
    - name: require-pinned-tag
      match:
        any:
          - resources:
              kinds: [Pod]
      validate:
        cel:
          expressions:
            - expression: >
                object.spec.containers.all(c,
                  !c.image.endsWith(':latest'))
              message: "Теги :latest запрещены. Укажите точный тег или SHA-дайджест."

Если вы когда-нибудь писали Kubernetes YAML — здесь нет ни одной новой концепции. Поле match работает как labelSelector, cel.expressions читается почти как SQL WHERE.

OPA Gatekeeper использует Rego — функциональный язык Open Policy Agent. Подход двухслойный: ConstraintTemplate описывает саму логику (содержит Rego-код и определяет CRD для нового типа Constraint), а Constraint — конкретный экземпляр правила с параметрами и областью применения. Один и тот же ConstraintTemplate можно применить в нескольких Constraint с разными параметрами — например, запретить :latest в prod, но разрешить в dev.

Rego — не YAML и не Go. Это декларативный язык логического программирования в духе Datalog: переменные неизменяемы, правила — это наборы выражений, все из которых должны быть истинны одновременно, а результат — набор значений переменной violation. Он мощнее CEL для очень сложных случаев, но требует отдельного изучения.

Та же политика на Gatekeeper:

apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8sdisallowlatestimage
spec:
  crd:
    spec:
      names:
        kind: K8sDisallowLatestImage
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8sdisallowlatestimage
        violation[{"msg": msg}] {
          c := input.review.object.spec.containers[_]
          endswith(c.image, ":latest")
          msg := sprintf("Контейнер %v использует тег :latest", [c.name])
        }
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sDisallowLatestImage
metadata:
  name: disallow-latest
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: [Pod]

Вдвое больше файлов, новый язык, новые концепции. Зато ровно тот же Rego работает в OPA-сервере рядом с Terraform, в Conftest в CI-пайплайне, и в политиках доступа к API. Если ваша команда уже использует OPA где-то ещё — переиспользование перевесит кривую обучения.

Возможности: validation, mutation, generation

Kyverno умеет три вещи, которых OPA Gatekeeper не умеет из коробки.

Validation — есть у обоих. Отклонить некорректный ресурс с чёткой ошибкой. Режим Audit позволяет сначала наблюдать нарушения без блокировки и видеть их в PolicyReport; переключить на Enforce — одна строка в манифесте. Этот режим особенно ценен при внедрении: сначала смотришь, что нарушается, потом включаешь принудительное исполнение.

Mutation — изменение ресурса перед сохранением, без отклонения. Kyverno поддерживает её в стабильном виде с богатым DSL: добавить label или аннотацию, выставить securityContext.runAsNonRoot: true, удалить hostNetwork: true, изменить образ. Это особенно удобно при постепенном переходе на новые стандарты: сначала мутируешь молча, потом добавляешь validation. Gatekeeper реализовал мутацию в v3.14 как beta-функцию, и она до сих пор имеет заметные ограничения в синтаксисе и типах ресурсов.

Generation — автоматическое создание сопутствующих ресурсов по триггеру. Классический сценарий: создали новый Namespace — Kyverno автоматически сгенерировал NetworkPolicy с дефолтным запретом входящего трафика, ResourceQuota с лимитами CPU/памяти и LimitRange для Pod. Платформенные инженеры ставят это однажды, и каждый новый Namespace сразу получает корректные guardrails без ручной работы. OPA не умеет генерировать ресурсы вообще — это за пределами его модели.

Возможности Kyverno vs OPA Gatekeeper

ValidatingAdmissionPolicy (k8s 1.30+): кто обнимает лучше

Kubernetes 1.30 стабилизировал ValidatingAdmissionPolicy (VAP) — встроенный механизм validation-политик на CEL, который живёт прямо в API Server без стороннего webhook. Главное преимущество: нет сетевого вызова к webhook-серверу. На практике это значит меньше латентности admission path и один потенциальный источник отказа минус.

VAP не умеет мутировать и генерировать ресурсы, поэтому не заменяет Kyverno и Gatekeeper полностью — только дополняет их для простых validation-правил.

Kyverno 1.17 умеет автоматически синхронизировать ClusterPolicy в нативные VAP-ресурсы. Включаете флаг generateValidatingAdmissionPolicy: true при установке через Helm — и Kyverno пишет объекты ValidatingAdmissionPolicy и ValidatingAdmissionPolicyBinding за вас. Простые validation-правила отрабатывают через Kubernetes нативно; webhook вызывается только для mutation и generation. Оператору не нужно делать ничего особенного: пишете обычную ClusterPolicy, Kyverno сам решает, пустить ли проверку через VAP.

Gatekeeper v3.22 тоже умеет маршрутизировать validation через VAP: параметр enforcementAction: denyAction в Constraint направляет исполнение через нативный VAP без вызова Gatekeeper webhook. Rego-логика остаётся прежней — меняется только путь исполнения. Интеграция более явная и требует явного выбора на уровне Constraint, в отличие от прозрачного авто-генерации у Kyverno.

Таблица сравнения

ФичаKyvernoOPA Gatekeeper
Язык политикYAML + CELRego
Validation✅ стабильная✅ стабильная
Mutation✅ стабильная⚠️ beta
Generation
ValidatingAdmissionPolicy✅ авто-генерация✅ через denyAction
Политики вне Kubernetes✅ Terraform, CI, API
Готовая библиотека✅ Kyverno Policies✅ Gatekeeper Library
Кривая входаНизкая (YAML)Средняя (Rego)
Audit-режим✅ PolicyReport✅ .status.violations
Параметризация правилЧерез переменныеЧерез Constraint params

Что нужно, чтобы запустить Kyverno

Требования: Kubernetes ≥ 1.25, Helm 3.

helm repo add kyverno https://kyverno.github.io/kyverno/
helm repo update
helm install kyverno kyverno/kyverno \
  --namespace kyverno --create-namespace \
  --set features.generateValidatingAdmissionPolicy.enabled=true

После установки Kyverno добавляет несколько webhook в кластер — вы увидите их через kubectl get validatingwebhookconfigurations. При отказе Kyverno pod поведение определяется параметром failurePolicy: по умолчанию Fail (webhook недоступен — запрос отклонён), что консервативно и безопасно для production.

Применяем готовую политику из официальной библиотеки — не нужно писать самостоятельно:

kubectl apply -f \
  https://raw.githubusercontent.com/kyverno/policies/main/best-practices/disallow-latest-tag/disallow-latest-tag.yaml

Проверяем:

kubectl run test --image=nginx:latest --restart=Never
# Error from server: admission webhook "kyverno-resource-validating-webhook-cfg.kyverno.svc"
# denied the request: Теги :latest запрещены. Укажите точный тег или SHA-дайджест.

kubectl run ok --image=nginx:1.27.0 --restart=Never
# pod/ok created

Смотрим audit-отчёт по всем существующим ресурсам:

kubectl get policyreport -A
# NAMESPACE   NAME                            PASS   FAIL   WARN
# default     cpol-disallow-latest-tag        12     3      0

PolicyReport — CRD от Policy Report Working Group; Kyverno заполняет его автоматически при audit-сканировании. Удобно подключать к Grafana через kubectl exporter.

Что нужно, чтобы запустить OPA Gatekeeper

Требования: Kubernetes ≥ 1.25, Helm 3.

helm repo add gatekeeper \
  https://open-policy-agent.github.io/gatekeeper/charts
helm repo update
helm install gatekeeper gatekeeper/gatekeeper \
  --namespace gatekeeper-system --create-namespace

Gatekeeper устанавливает три компонента: controller-manager (обрабатывает admission запросы), audit (фоново проверяет существующие ресурсы) и webhook (сам сервер). При отказе webhook поведение тоже регулируется failurePolicy.

Применяем ConstraintTemplate и Constraint:

kubectl apply -f constraint-template.yaml
# ConstraintTemplate - создаёт CRD K8sDisallowLatestImage
# Подождём, пока Gatekeeper зарегистрирует CRD
kubectl wait --for condition=established \
  crd/k8sdisallowlatestimages.constraints.gatekeeper.sh --timeout=60s

kubectl apply -f constraint.yaml

Проверяем:

kubectl run test --image=nginx:latest --restart=Never
# Error from server ([disallow-latest] Контейнер test использует тег :latest)

kubectl run ok --image=nginx:1.27.0 --restart=Never
# pod/ok created

Смотрим нарушения, которые audit нашёл в существующих ресурсах:

kubectl get k8sdisallowlatestimage disallow-latest \
  -o jsonpath='{.status.violations}' | jq .
# [{"enforcementAction":"deny","group":"","kind":"Pod",
#   "message":"Контейнер legacy использует тег :latest",
#   "name":"legacy","namespace":"default","version":"v1"}]

Когда оправдан гибридный вариант

Большие платформенные команды нередко держат оба инструмента в одном кластере. Такой выбор оправдан, когда обе потребности присутствуют одновременно: нужна богатая mutation и generation (Kyverno), и при этом те же проверки должны работать за пределами Kubernetes (OPA).

Типичное разделение: Kyverno занимается mutation и generation — проставляет обязательные labels на все ресурсы, добавляет securityContext в Pod если не указан, создаёт NetworkPolicy для каждого нового Namespace. OPA занимается validation, причём тот же Rego-код запускается и в кластере, и в GitHub Actions через conftest check, и против terraform plan через OPA CLI.

# Conftest: та же политика в CI
conftest test deployment.yaml \
  --policy policies/disallow-latest.rego
# FAIL - deployment.yaml - Контейнер app использует тег :latest

Главная ловушка гибридного варианта — дублирование. Если вы написали validation на Kyverno «для быстроты», а потом добавили ту же проверку в OPA, вы сразу получаете два источника правды. При изменении правила нужно менять оба; при расхождении между ними — разобраться, какое «главное». Если вы запускаете оба, строго разграничьте зоны ответственности письменно, и ревьюьте каждую новую политику на предмет «не дублирует ли она то, что уже есть в другом движке».

Гибридный вариант: Kyverno + OPA

Итог

Kyverno — правильный выбор для команды, которая живёт в YAML и работает только внутри Kubernetes. Меньше новых концепций, mutation и generation из коробки, прозрачная авто-интеграция с нативным VAP в k8s 1.30+. Kyverno Policies — библиотека из сотен готовых правил для быстрого старта.

OPA Gatekeeper — правильный выбор, если ваша политика выходит за пределы кластера в Terraform, CI или другие системы. Одним языком Rego покрываете всё, а библиотека Gatekeeper Library даёт те же готовые политики для Kubernetes-специфичных проверок.

Гибридный вариант (Kyverno мутирует и генерирует, OPA проверяет везде) оправдан, когда обе потребности есть одновременно, — но требует строгого разграничения зон ответственности с первого дня. Иначе вы получите две конкурирующие копии одних и тех же правил, и через год никто не будет понимать, какая из них «главная».


Поделиться:

Следующая статья
Flux за вечер: GitOps для одного небольшого кластера