Привет, хабравчане!
Слышали ли вы, что такое Kyverno и зачем он нужен? В этой статье расскажу и покажу на примерах, как мы его используем.
Меня зовут Макарий Балашов, я SRE в Ak Bars Digital. Наша команда занимается подготовкой и развитием инфраструктуры для команд разработки.
Что такое этот ваш Kyverno?
Kyverno — policy engine разработанный специально для Kubernetes.
Kyverno позволяет администраторам кластеров управлять специфическими конфигурациями среды независимо от конфигураций ресурсов, применять передовые методы настройки для своих кластеров. Kyverno можно использовать для сканирования существующих ресурсов на наличие best practises или для соблюдения их путем блокировки или изменения запросов API.
Вот небольшой список крутых фишек Kyverno:
-
policy как ресурсы kubernetes (yaml манифесты);
-
возможность валидировать, изменять или создавать ресурсы k8s;
-
проверка образов контейнеров для обеспечения безопасности цепочки поставок ПО;
-
проверка метадаты образов;
-
синхронизация конфигурации в Namespace’ах;
-
блокировка несовместимые ресурсы с помощью элементов управления доступом или сообщать о нарушениях политики;
-
управление политиками как кодом с помощью знакомых инструментов, таких как
gitиkustomize; -
постоянно расширяемая библиотека готовых политик (уже 244).
В качестве альтернатив Kyverno можно выделить OPA/Gatekeeper, Kubewarden и jsPolicy.
Про сравнение этих решений есть много информации в сети, например тут сравнивают Kyverno и Gatekeeper.
Зачем это нам?
В 1.21 PodSecurityPolicy стала депрекейтед фичей Kubernetes, а в 1.25 была вовсе удалена.
Перед нами стал вопрос, а как дальше жить? И мы решили потестить разные решения, выбор остановился на Kyverno. Нас она очень сильно порадовала и удовлетворила наши потребности, как замена PSP.
На фоне альтернатив Kyverno выделился большим функционалом сразу из коробки и простой лексикой (обычный yaml), что позволяет новым сотрудникам гораздо быстрее разобраться, как с ним работать.
Как она работает?
Kyverno работает как динамический контроллер допуска в кластере Kubernetes. Kyverno получает проверяющие и изменяющие вебхуки допуска от kube-apiserver. Применяет соответствующие политики для возврата результатов, которые применяют политики допуска или отклоняют запросы.

Для чего используем?
Изначально мы планировали использовать Kyverno только как замену PodSecurityPolicy. Начали с переписования уже существующих манифестов PSP в манифесты политик Kyverno c Validate правилами.
Validate Resources
Например, мы сразу хотели запретить запуск privilege контейнеров, так как это чревато тем, что под может получить доступ к ресурсам хоста и возможностям ядра.
Политика которую мы используем
apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: disallow-privileged-containers annotations: policies.kyverno.io/title: Disallow Privileged Containers policies.kyverno.io/category: Pod Security Standards (Baseline) policies.kyverno.io/severity: medium policies.kyverno.io/subject: Pod kyverno.io/kyverno-version: 1.6.0 kyverno.io/kubernetes-version: "1.22-1.23" policies.kyverno.io/description: >- Privileged mode disables most security mechanisms and must not be allowed. This policy ensures Pods do not call for privileged mode. spec: validationFailureAction: audit background: true rules: - name: privileged-containers match: any: - resources: kinds: - Pod validate: message: >- Privileged mode is disallowed. The fields spec.containers[*].securityContext.privileged and spec.initContainers[*].securityContext.privileged must be unset or set to `false`. pattern: spec: =(ephemeralContainers): - =(securityContext): =(privileged): "false" =(initContainers): - =(securityContext): =(privileged): "false" containers: - =(securityContext): =(privileged): "false"
Mutating Resources
Далее, мы решили сразу выставлять нужный нам securityContext для всех ресурсов, которые будут создаваться в нашем кластере. Вот что у нас получилось:
Политика для добавления ресурсам securityContext
apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: add-default-securitycontext annotations: policies.kyverno.io/title: Add Default securityContext policies.kyverno.io/category: Sample policies.kyverno.io/subject: Pod policies.kyverno.io/description: >- A Pod securityContext entry defines fields such as the user and group which should be used to run the Pod. Sometimes choosing default values for users rather than blocking is a better alternative to not impede such Pod definitions. This policy will mutate a Pod to set default securityContext spec: background: false rules: - name: add-default-securitycontext-containers match: any: - resources: kinds: - Pod preconditions: all: - key: "{{request.operation}}" operator: In value: - CREATE - UPDATE mutate: foreach: - list: "request.object.spec.containers" patchStrategicMerge: spec: securityContext: runAsUser: 10001 runAsGroup: 10001 fsGroup: 10001 seccompProfile: type: RuntimeDefault containers: - name: "{{ element.name }}" securityContext: runAsUser: 10001 runAsGroup: 10001 capabilities: drop: - ALL runAsNonRoot: true allowPrivilegeEscalation: false privileged: false seccompProfile: type: RuntimeDefault - name: add-default-securitycontext-initContainers match: any: - resources: kinds: - Pod preconditions: all: - key: "{{request.operation}}" operator: In value: - CREATE - UPDATE - key: "{{ request.object.spec.initContainers[] || '' | length(@) }}" operator: GreaterThanOrEquals value: 1 mutate: foreach: - list: "request.object.spec.initContainers" patchStrategicMerge: spec: securityContext: runAsUser: 10001 fsGroup: 10001 seccompProfile: type: RuntimeDefault initContainers: - name: "{{ element.name }}" securityContext: runAsUser: 10001 runAsGroup: 10001 capabilities: drop: - ALL runAsNonRoot: true allowPrivilegeEscalation: false privileged: false seccompProfile: type: RuntimeDefault
Generate Resources
Как пример использования generate-политик сразу приходит в голову копирование секрета с кредами от private registry (dockerconfigjson) в каждый Namespace.
Мы также нашли следующее применение — копирование секрета с самоподписанным рутовым сертификатом, который генерирует cert-manager, в каждый namespace для последующей инъекции при помощи другой политики в контейнеры. Обратите внимание на synchronize, который позволяет Kyverno автоматически обновлять содержимое всех созданных ею ресурсами при изменении изначального. В нашем случае — это обновление сертификата во всех секретах после автоматического перевыпуска cert-manager’ом.
Копирование секрета по Namespac’ам
apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: clone-cert annotations: policies.kyverno.io/title: Clone Certificate's secret policies.kyverno.io/category: Cert-Manager policies.kyverno.io/subject: Certificate, Namespace policies.kyverno.io/description: >- Clone certificate's secret to every namespace spec: background: true rules: - name: clone-cert match: any: - resources: kinds: - Namespace exclude: any: - resources: namespaces: - "kube-system" - "kube-public" - "default" generate: synchronize: true apiVersion: v1 kind: Secret name: base-cert namespace: "{{request.object.metadata.name}}" clone: namespace: cert-manager name: base-cert
Пример политики, которой делаем инъекцию
apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: add-certificates-volume annotations: policies.kyverno.io/title: Add Certificates as a Volume policies.kyverno.io/category: Sample policies.kyverno.io/subject: Pod,Volume kyverno.io/kyverno-version: 1.5.2 kyverno.io/kubernetes-version: "1.21" policies.kyverno.io/minversion: 1.5.0 pod-policies.kyverno.io/autogen-controllers: DaemonSet,Deployment,Job,StatefulSet policies.kyverno.io/description: >- In some cases you would need to trust custom CA certificates for all the containers of a Pod. It makes sense to be in a Secret so that you can automount them by only setting an annotation. This policy adds a volume to all containers in a Pod containing the certificate if the annotation called `inject-certs` with value `enabled` is found. spec: background: true rules: - name: add-ssl-certs match: any: - resources: kinds: - Pod exclude: any: - resources: namespaces: - "kube-system" - "kube-public" - "default" preconditions: all: - key: "{{request.operation}}" operator: In value: - CREATE - UPDATE mutate: foreach: - list: "request.object.spec.containers" patchStrategicMerge: spec: containers: - name: "{{ element.name }}" volumeMounts: - name: ssl-certs mountPath: /etc/ssl/certs volumes: - name: ssl-certs secret: secretName: base-cert
Verify Image
Также, при помощи Kyverno и Sigstore Cosign можно проверять и подписывать образы контейнеров. Мы только внедряем эти фичи. Подборку статей по этой теме можно посмотреть в телеграмм канале k8s (in)security
Заключение
Kyverno великолепен, потому что позволяет нам последовательно управлять нашими кластерами на уровне кластера без реального кода. Недопустимые ресурсы могут быть заблокированы с всплывающими сообщениями об ошибках для пользователей. Неправильно настроенные ресурсы могут быть исправлены на лету, а новые ресурсы могут быть динамически созданы. С этим инструментом мы получили очень приятный опыт управления кластерами Kubernetes. И будем дальше его использовать.
Ссылки, которые могут быть вам полезны, если захотите использовать Kyverno в своих проектах:
-
Документация — https://kyverno.io/docs/
-
Набор готовых полиси — https://kyverno.io/policies/
-
Replacing PSPs? Keep Bad Pods out of your cluster using Kyverno — https://youtu.be/AmJUFH7n33c
-
PodSecurityPolicy Migrator — https://appvia.github.io/psp-migration/ , https://github.com/appvia/psp-migration
-
Governing Multi-Tenant Kubernetes Clusters with Kyverno — https://medium.com/compass-true-north/governing-multi-tenant-kubernetes-clusters-with-kyverno-3e11ba4a64ad
ссылка на оригинал статьи https://habr.com/ru/company/akbarsdigital/blog/711102/
Добавить комментарий