Policy as Code в Kubernetes: Kyverno vs OPA Gatekeeper с реални политики

Policy as Code в Kubernetes: Kyverno vs OPA Gatekeeper с реални политики

В света на Kubernetes, сигурността и съответствието не са нещо, което добавяме накрая. Те са фундаментална част от процеса. Ето защо концепцията Policy as Code (PaC) бързо се превърна в стандарт за модерните екипи. Тя ви позволява да дефинирате правила за сигурност, съответствие и оперативна ефективност като код, който се версионира, тества и внедрява точно като вашието приложение. За Kubernetes, двата основни играча на това поле са Kyverno и OPA Gatekeeper.

В тази статия ще ги сравним практически, с реални политики и примери, подходящи за българските екипи – от стартъпи в София до аутсорсинг компании във Варна и Пловдив.

Защо Policy as Code е Изискване, а не Опция

Представете си, че сте технически лийд в стартъп в София. Вашият екип внедрява нови функции бързо. Но как гарантирате, че всички деплоймънти имат зададени лимити за ресурси? Или че никога няма да се деплойне контейнер без подпис от вашия registry? Ръчната проверка не е мащабируема. Човекът от другата смяна може да пропусне нещо.

Policy as Code автоматизира тези проверки. Тя прилага правила във всеки един етап от жизнения цикъл на приложението – преди да стигне до кластъра (чрез CI/CD) и след като е в кластъра (чрез admission controllers). Това е сърцето на DevSecOps: вграждане на сигурността в процеса на разработка.

Съперниците в Рийнга: Kyverno срещу OPA Gatekeeper

И двата инструмента решават един и същ основен проблем, но по доста различен начин.

OPA Gatekeeper е проект с отворен код, базиран на Open Policy Agent (OPA) – общо предназначение за политики, не само за Kubernetes. Gatekeeper е специфичният „адapter“ за Kubernetes. Той е мощен и гъвкав, но с по-стръмна крива на обучение.

Kyverno е проект, създаден специално за Kubernetes. Той не изисква нов език за писане на политики – използва самата Kubernetes манифест структура. Цели да бъде лесен за употреба и интегриран.

Нека ги видим в действие с три често срещани сценария.


Сценарий 1: Изискване на Labels в Namespace

Много екипи използват labels върху namespaces за логическо разделение (напр., env=prodteam=backend). Нека изискваме всеки нов namespace да има етикет cost-center.

Политика с Kyverno

Kyverno политиките са дефинирани като Kubernetes Policy или ClusterPolicy ресурси.

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-namespace-labels
spec:
  validationFailureAction: Enforce # Блокира създаването при нарушение
  background: false
  rules:
  - name: check-for-cost-center
    match:
      any:
      - resources:
          kinds:
          - Namespace
    validate:
      message: "Всички namespaces трябва да имат label 'cost-center'."
      pattern:
        metadata:
          labels:
            cost-center: "?*" # ?* означава, че стойността трябва да съществува и да е с дължина >0

Плюс: Лесно се чете и разбира. Ако познавате YAML и Kubernetes структури, политиката е интуитивна.

Политика с OPA Gatekeeper

За Gatekeeper трябва да създадете два ресурса: ConstraintTemplate (дефинира логиката) и Constraint (прилага логиката за конкретни ресурси).

ConstraintTemplate:

apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8srequiredlabels
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredLabels
      validation:
        openAPIV3Schema:
          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("Namespace трябва да има следните labels: %v", [missing])
        }

Constraint:

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

Плюс: Непълна гъвкавост. С една обща ConstraintTemplate можете да създавате множество Constraints за различни labels и различни ресурси (напр., за Pods, Services). Минус: Изисква познаване на Rego езика.


Сценарий 2: Прилагане на Resource Limits

Една от най-честите причини за нестабилност в кластъри е „алчният“ Pod, който изяжда цялата памет на нод. Нека изискваме всички Pods в namespace production да дефинират limits.cpu и limits.memory.

Политика с Kyverno

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-resource-limits
spec:
  validationFailureAction: Enforce
  background: false
  rules:
  - name: check-resource-limits
    match:
      any:
      - resources:
          namespaces: ["production"] # Прилага се само за production namespace!
          kinds:
          - Pod
    validate:
      message: "Всички Pods в production трябва да дефинират limits.cpu и limits.memory."
      pattern:
        spec:
          containers:
          - resources:
              limits:
                memory: "?*"
                cpu: "?*"

Много мощен аспект на Kyverno: Той може директно да създава (mutate) ресурси. Ако искате автоматично да зададете limits, ако екипът ги е забравил, може да добавите правило за мутация:

# Допълнение към горната политика...
  rules:
  - name: set-default-resource-limits
    match:
      any:
      - resources:
          namespaces: ["staging"] # В staging автоматично задаваме limits
          kinds:
          - Pod
    mutate:
      patchStrategicMerge:
        spec:
          containers:
          - (name): "*"
            resources:
              limits:
                memory: "512Mi"
                cpu: "250m"

Политика с OPA Gatekeeper

За Gatekeeper, мутацията не е възможна нативно. Той се фокусира върху валидация. За тази задача ще създадем валидираща политика.

ConstraintTemplate:

apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8sresourcelimits
spec:
  crd:
    spec:
      names:
        kind: K8sResourceLimits
      validation:
        openAPIV3Schema:
          properties:
            limits:
              type: array
              items:
                type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8sresourcelimits
        violation[{"msg": msg}] {
          container := input.review.object.spec.containers[_]
          not container.resources.limits
          msg := sprintf("Контейнерът %v в Pod %v няма дефинирани resource limits.", [container.name, input.review.object.metadata.name])
        }
        violation[{"msg": msg}] {
          container := input.review.object.spec.containers[_]
          required_lim := input.parameters.limits[_]
          not container.resources.limits[required_lim]
          msg := sprintf("Контейнерът %v в Pod %v няма дефиниран limit %v.", [container.name, input.review.object.metadata.name, required_lim])
        }

Constraint:

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sResourceLimits
metadata:
  name: pods-must-have-cpu-memory-limits
spec:
  match:
    namespaces: ["production"]
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
  parameters:
    limits: ["cpu", "memory"]

Сценарий 3: Проверка на Подпис на Container Image

Това е златният стандарт за сигурност. Изискването само подписали (signed) images да се пускат в production предотвратява множество атаки.

Политика с Kyverno

Kyverno има вградена поддръжка за проверка на image signatures чрез косвеница (keyless) или с ключове.

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: check-image-signature
spec:
  validationFailureAction: Enforce
  background: false
  rules:
  - name: verify-signature-keyless
    match:
      any:
      - resources:
          namespaces: ["production"]
          kinds:
          - Pod
    verifyImages:
    - imageReferences:
      - "*my-bulgarian-registry.bg/projects/app*" # Проверява само images от нашия private registry
      attestors:
      - entries:
        - keyless:
            issuer: "https://token.actions.githubusercontent.com"
            subject: "https://github.com/your-bg-org/your-repo/.github/workflows/ci-cd.yml@refs/heads/main"
            # Проверява дали image е подписан от GitHub Actions workflow в конкретния репо и клон.

Плюс: Изключително лесно за настройка сравнено с ръчното писане на такава логика. Интеграцията е плътна.

Политика с OPA Gatekeeper

За Gatekeeper, това е много по-сложно. Трябва да извлечете информацията за image от манифеста, да извикате външен API (напр., Cosign) за проверка, и да върнете резултат. Това обикновено изисква разширяване на OPA с вънчни данни (external data) чрез OPA’s http.send() или създаване на собствен външен уебхук провайдър. Това увеличава сложността значително и не е препоръчително за начинаещи.


Разбор: Кога да Избереш Kyverno, а кога OPA Gatekeeper?

КритерийKyvernoOPA Gatekeeper
Лекота на употребаВисока. YAML/Kubernetes-стил. Перфектно за екипи, които искат да започнат бързо.Ниска. Изисква научаване на Rego език.
ГъвкавостВисока за Kubernetes-специфични сценарии.Много Висока. OPA може да пише политики за почти всичко (API, Terraform, SQL).
МутацияПоддържа се нативно. Може автоматично да поправя или добавя полета.Не се поддържа. Фокусът е само върху валидация и одит.
Image SigningПоддържа се нативно с лесно конфигуриране.Сложна за имплементация, изисква custom код.
Общност и поддръжкаГоляма и растяща общност, CNCF проект.Много голяма общност, CNCF graduated проект (по-зрял).
Идеален заБългарски стартъпи и екипи, които искат да имплементират PaC бързо с фокус върху Kubernetes.Големи предприятия, които вече използват OPA за други цели (не само K8s) и имат експертиза в Rego.

Моето мнение за българския контекст: За повечето локални компании – стартъпи, цифрови агенции и дори по-големи екипи, работещи по европейски проекти – Kyverno е очевидният избор. Намалява бариерата за вход и ви позволява да получите 80% от ползите с 20% от усилията. Gatekeeper е отличен избор, ако вашата компания вече е инвестирала в OPA екосистемата или ако имате изисквания, които излизат извън рамките на Kubernetes.

TL;DR Чеклист за Имплементация в CI/CD

Внедряването на Policy as Code не е само за кластъра. Ето как да го интегрирате в вашия pipeline, независимо дали използвате GitLab, Jenkins или GitHub Actions.

  1. Избор на Инструмент: Започнете с Kyverno, освен ако нямате конкретна причина за Gatekeeper.
  2. Локално Тестване: Инсталирайте kyverno cli или conftest (за OPA) в pipeline-а. Тествайте политиките локално върху вашите YAML манифести, преди да ги приложите в кластъра.bash# Пример за Kyverno: kyverno apply ./your-policy.yaml –resource ./deployment.yaml # Пример за OPA/Gatekeeper с conftest: conftest test deployment.yaml -p your-policy.rego
  3. „Shift Left“: Вършете тази проверка още в етапа на Pull Request. Това незабавно информира разработчика да поправи проблема, вместо да чака до деплоймънт и да бъде блокиран.
  4. Внедряване в Кластъра: След като кодът е merge-нат, актуализирайте политиките в кластъра чрез вашия GitOps инструмент (напр., ArgoCD, Flux). Те веднага започват да валидират всички нови деплоймънти.
  5. Започнете с Малко: Не се опитвайте да покриете всичко от ден 1. Внедрете 2-3 критични политики (напр., resource limits, забрана на root потребител) и постепенно добавяйте още.

Въпрос към вас, колеги от българската общност: Вече ли използвате Policy as Code във вашите Kubernetes среди? С какви предизвикателства се сблъсквате? Споделете вашите опити в коментарите!

Ако смятате, че тази статия е полезна за вашия екип или колеги, не се колебайте да я споделите!

Федя Серафиев

Федя Серафиев

е DevOps технологичен ентусиаст с опит в Linux, Docker, Kubernetes и CI/CD. Той споделя практични ръководства и анализи, които помагат на специалистите да изграждат по-добри и ефективни системи. На devopsbg.net Федя предоставя актуални и полезни насоки за автоматизация, сигурност и оптимизация на инфраструктурата.

Вашият коментар

Вашият имейл адрес няма да бъде публикуван. Задължителните полета са отбелязани с *


Колко е 8 - 1 ? (въведете числото)