В света на 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=prod
, team=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?
Критерий | Kyverno | OPA 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.
- Избор на Инструмент: Започнете с Kyverno, освен ако нямате конкретна причина за Gatekeeper.
- Локално Тестване: Инсталирайте
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 - „Shift Left“: Вършете тази проверка още в етапа на Pull Request. Това незабавно информира разработчика да поправи проблема, вместо да чака до деплоймънт и да бъде блокиран.
- Внедряване в Кластъра: След като кодът е merge-нат, актуализирайте политиките в кластъра чрез вашия GitOps инструмент (напр., ArgoCD, Flux). Те веднага започват да валидират всички нови деплоймънти.
- Започнете с Малко: Не се опитвайте да покриете всичко от ден 1. Внедрете 2-3 критични политики (напр., resource limits, забрана на root потребител) и постепенно добавяйте още.
Въпрос към вас, колеги от българската общност: Вече ли използвате Policy as Code във вашите Kubernetes среди? С какви предизвикателства се сблъсквате? Споделете вашите опити в коментарите!
Ако смятате, че тази статия е полезна за вашия екип или колеги, не се колебайте да я споделите!