> For the complete documentation index, see [llms.txt](https://book.konstantinsecurity.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.konstantinsecurity.com/readme/architect/kubernetes/control-plane-security/kyverno/policy-as-a-code-kyverno.md).

# Policy as a code. Kyverno

<https://habr.com/ru/companies/slurm/articles/722264/>

![](/files/ZG1MeRYztc7iOofZDayC)

Kubernetes смог произвести революцию в облачной экосистеме, позволив людям запускать распределенные приложения на масштабе. Хотя Kubernetes – это многофункциональная и надежная платформа для оркестрации контейнеров, она имеет свои собственные сложности. Управлять Kubernetes в таком масштабе, когда над ним работают сразу несколько команд, непросто. Трудно контролировать правильность действий пользователей и их возможный выход за рамки допустимого.

Kyverno является самым подходящим инструментом для этого. Это движок политик безопасности Kubernetes с открытым исходным кодом, который помогает вам определять политики с помощью простых манифестов Kubernetes. Он может проверять, изменять и генерировать ресурсы Kubernetes. Таким образом, это может позволить организациям определять и применять политики так, чтобы разработчики и администраторы придерживались определенного стандарта.

## Как работает Kyverno?

Kyverno работает на основе dymanic admission controller, который проверяет каждый запрос, который вы отправляете через kubectl на сервер Kube API. Если запрос соответствует политике, Kyverno пропускает его. В противном случае он отклоняет запрос с определенным сообщением.

Это позволяет Kyverno осуществлять такие функции, как:

* Проверку ограничений CPU и памяти.
* Контроль за тем, чтобы пользователи не меняли сетевые политики, установленные по умолчанию.
* Проверку, соответствует ли имя ресурса определенному шаблону.
* Обеспечение того, чтобы определенные ресурсы всегда содержали соответствующую метку.
* Запрет удалений и изменений для определенных ресурсов.
* Автоматическое изменение imagePullPolicy на Always, если тег изображения latest.
* Создание сетевой политики по умолчанию для каждого нового namespace.

Kyverno использует CRD (пользовательские определения ресурсов) для определения политик, поэтому написание политик настолько просто, как их применение с помощью kubectl.

Есть три основные функции, предоставляемые Kyverno:

* проверка (validation)
* изменение (mutation)
* генерация (generation)

Давайте взглянем на некоторые примеры манифестов для каждой из них.

## Проверка

Прекрасным примером использования является обеспечение того, чтобы все поды имели установленные значения для requests/limits. Следующий пример прекрасно объясняет это:

```
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: check-resources
spec:
  validationFailureAction: enforce
  rules:
    - name: check-pod-resources
      match:
        resources:
          kinds:
            - Pod
      validate:
        message: "CPU and memory resource requests and limits are required"
        pattern:
          spec:
            containers:
              - name: "*"
                resources:
                  limits:
                    memory: "?*"
                    cpu: "?*"
                  requests:
                    memory: "?*"
                    cpu: "?*"
```

Хотя большая часть примера сама себя документирует и объясняет, давайте разберем параметр validationFailureAction Он указывает, следует ли соблюдать это требование (с помощью enforce) или следует только проверить его (с помощью audit) и сообщить о нарушениях.

## Изменение (mutation)

Mutation означает изменение ресурсов, если они соответствуют определенному шаблону. Отличным примером этого яцвляется изменение imagePullPolicy на Always, если тег образа контейнера latest.

```
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: image-pull-policy-always
spec:
  rules:
    - name: image-pull-policy-latest
      match:
        resources:
          kinds:
            - Pod
      mutate:
        overlay:
          spec:
            containers:
              - (image): "*:latest"
                imagePullPolicy: "Always"
```

## Генерация (generation)

Генерирование, как следует из названия, генерирует (создает) ресурс для определенного события. Например, если кто-то создает новый namespace, мы можем захотеть применить сетевую политику по умолчанию.

```
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: "default"
spec:
  rules:
  - name: "default-deny"
    match:
      resources:
        kinds:
        - Namespace
        name: "*"
    exclude:
      namespaces:
        - "kube-system"
        - "default"
        - "kube-public"
        - "kyverno"
    generate:
      kind: NetworkPolicy
      name: default-deny-all-traffic
      namespace: "{{request.object.metadata.namespace}}"
      data:
        spec:
          podSelector: {}
          policyTypes:
          - Ingress
          - Egress
```

## Переходим к практике

Теперь давайте перейдем к практике и посмотрим на Kyverno в работе. Мы установим Kyverno, а затем применим политику валидации для осуществления проверки наличия определенной метки. Если метка не существует, Kyverno отклонит запрос. В противном случае он будет одобрен.

### Предпосылки

Для начала работы нам нужен функциональный кластер Kubernetes.

### Устанавливаем Kyverno

Установка Kyverno проста. Вы можете либо применить манифест Kyverno Kubernetes, доступный на GitHub, либо установить последнюю версию helm chart.

## Применение манифеста

```
kubectl create -f
https://raw.githubusercontent.com/kyverno/kyverno/master/definitions/
release/install.yaml
```

## Использование Helm chart

```
helm repo add kyverno https://kyverno.github.io/kyverno/
kubectl create ns kyverno
helm install kyverno --namespace kyverno kyverno/kyverno
```

Чтобы проверить, успешно ли мы установили Kyverno, перечислите все ресурсы в namespace kyverno:

```
# kubectl get all -n kyverno
NAME                           READY   STATUS    RESTARTS   AGE
pod/kyverno-5f7769d697-x8lkj   0/1     Running   0          21s
NAME                  TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
service/kyverno-svc   ClusterIP   10.96.167.8   <none>        443/TCP   21s
NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/kyverno   0/1     1            0           21s
NAME                                 DESIRED   CURRENT   READY   AGE
replicaset.apps/kyverno-5f7769d697   1         1         0       21s
```

## Применение политик

Теперь мы подошли к вопросу о политике. Давайте применим политику, которая гарантирует, что все поды должны содержать метку (label) с именем app. Создайте файл с именем require-app-label.yaml с приведенным ниже содержанием:

```
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-app-label
spec:
  validationFailureAction: enforce
  rules:
  - name: check-for-app-label
    match:
      resources:
        kinds:
        - Pod
    validate:
      message: "label `app` is required"
      pattern:
        metadata:
          labels:
            app: "?*"
```

Если вы посмотрите на YAML, мы увидим, что там есть раздел match, который содержит типы ресурсов, которые мы должны сопоставить. В этом примеры мы видим сущность типа Pod. Секция validate определяет сообщение, которое мы должны вывести, если проверка завершится неудачей, и шаблон, объясняющий, что нам нужно сопоставить.

Поскольку это пользовательский ресурс kubernetes, мы можем применить его напрямую и получить желаемый результат:

```
kubectl apply -f require-app-label.yaml
```

## Проверка

Итак, пришло время для небольшого тестирования! Давайте создадим pod без метки (label) и посмотрим, что у нас получится:

```
kubectl run nginx --image=nginx
```

![](/files/PuJycHXTcjnF3m5NGDB7)

Итак, как мы видим, проверка завершилась неудачей по причине, указанной ниже:

```
Error from server: admission webhook "nirmata.kyverno.resource.validating-webhook" denied the request:
resource Deployment/default/nginx was blocked due to the following policies
require-app-label:
  autogen-check-for-app-label: 'Validation error: label `app` is required; Validation rule autogen-check-for-app-label failed at path /spec/template/metadata/labels/app/'
```

Здесь всё работает, как и ожидалось, поскольку мы еще не предоставили метку (label). Теперь давайте попробуем с меткой name=nginx:

```
kubectl run nginx --image=nginx --labels="name=nginx" --generator=run-pod/v1
```

![](/files/plM75dWd9mEymrDtZGKg)

Этот запуск тоже терпит неудачу, так как метка (label) приложения по-прежнему отсутствует. Давайте создадим под NGINX с меткой app=nginx:

```
kubectl run nginx --image=nginx --labels="app=nginx" --generator=run-pod/v1
```

![](/files/unyZlzIe7cXPOPQx1fxD)

Как мы можем видеть, под был создан успешно. Теперь давайте используем kubectl для получения пода и меток:

```
kubectl get pod nginx --show-labels
```

![](/files/Xy9YqiGQvEh7gkVd6A6q)

Под запущен и содержит метку app=nginx.

## Заключение

Kyverno – это отличный инструмент policy-as-code, который очень эффективен в применении лучших практик на уровне компании. Поскольку он является родным для Kubernetes, он прост в написании и эксплуатации и не требует обслуживания специализированными разработчиками.
