[Перевод] Управление политиками кластера Kubernetes через Gatekeeper OPA

Перевели статью о том, что такое Gatekeeper, зачем он нужен и как работает. Разберёмся с политиками, настроим инфраструктуру Gatekeeper в кластере, протестируем политики.

Что такое OPA Gatekeeper?

Говоря простым языком, Gatekeeper — это инструмент с открытым исходным кодом, который позволяет проводить аудит и применять политики на кластере Kubernetes в автоматическом режиме. Все эти политики написаны на языке rego. Это K8s-специфика OPA [Open Policy Agent], работающая как валидация Admission Controller.

Зачем нужен Gatekeeper?

Допустим, вы работаете в качестве Platform DevOps инженера и управляете несколькими кластерами Kubernetes для нескольких проектов. Но поскольку пользователи имеют доступ к развертыванию приложений на своих кластерах для своих проектов, они могут развернуть любой образ, любое количество реплик, развернуть приложения без соблюдения best practices и т.д. Это очень опасно для проекта. Вот какие с этим есть проблемы:

1. Отсутствует владелец. На многих проектах пользователи не используют метку.

2. Отсутствует лимит ресурсов. В конечном итоге это может привести к большим затратам.

3. Одно плохое приложение, взятое из ненадежного хранилища, может повлиять на все остальные приложения.

4. Возникают проблемы с границами безопасности и применением best practies в кластере.

Следовательно, чтобы упорядочить работу, нам необходимо внедрить такое управление, чтобы мы могли установить некоторые ограничения, правила с помощью политик в соответствии с лучшими практиками. Для настройки этих политик мы можем сконфигурировать OPA Gatekeeper.

Как работает OPA Gatekeeper?

Gatekeeper выполняет роль моста между сервером Kubernetes API и OPA. Это означает, что Gatekeeper проверяет каждый запрос, поступающий в кластер, на предмет нарушения какой-либо из предопределенных политик. OPA генерирует policy решения, оценивая вводимые запросы в соответствии с политиками и данными. Например, если вы пытаетесь создать 10 реплик для своего приложения dev, а ограничение установлено на максимум 5, OPA отклонит развертывание. Вы можете настроить несколько политик в соответствии с потребностями проекта. Некоторые примеры приведены ниже.

1. Лимит реплик, политики безопасности подсистемы.

2. Разрешение реестра образов для извлечения образов.

3. Обязательные метки для объектов и ресурсов.

4. Многое другое.

Источник

Понимание политики

Итак, когда мы говорим о политике, для ее понимания необходимо знать несколько обязательных вещей, таких как CRD, ConstraintTemplate и Constraints. Давайте попробуем разобраться.

CRD:

API CustomResourceDefinition (CRD) позволяет нам определять пользовательские ресурсы. При определении объекта CRD создается новый пользовательский ресурс с указанными нами именем и схемой. API Kubernetes обслуживает и обрабатывает хранение пользовательских ресурсов.

В данном случае Gatekeeper использует CRD для определения шаблонов ограничений и ограничений, позволяющих применять политики.

Constraint Templates:

ConstraintTemplates (шаблоны ограничений) определяют способ проверки некоторого набора объектов Kubernetes в Admission Controller. Здесь вы можете настраивать свои политики и адаптировать их в соответствии с вашими потребностями, а также в случае несоответствия политики вы можете настроить сообщение, чтобы конечный пользователь понял ошибку и мог её исправить. Эта политика должна быть написана на языке Rego.

Constraints:

Constraints (ограничение) — это объявление требований, которым должна удовлетворять система. Другими словами, ограничения используются для информирования Gatekeeper о том, что администратор хочет, чтобы шаблон ConstraintTemplate выполнялся, и каким образом. Говоря простым языком, это аргумент для вашей функции. Здесь вы можете ссылаться на функцию как на свой ConstraintTemplates.

Источник

Настройка Gatekeeper

Существует несколько способов установки Gatekeeper: Helm, Make File или запуск отдельных файлов манифеста в кластере Kubernetes.

Здесь я использую HELM, так как он мне больше нравится, чем другие способы, но да, если вы хотите знать, какие объекты мы используем, я бы рекомендовал просмотреть файлы манифеста.

Через Helm:

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

Здесь в качестве имени Helm Release используется «gatekeeper». Итак, когда все это будет сделано, вы должны увидеть, что некоторые подсистемы, сервисы, роли кластера, секреты и CRD созданы.

После установки Gatekeeper

После установки Gatekeeper

Также будут созданы ресурсы mutating webhook configuration и validating webhook configuration.

После установки Gatekeeper

После установки Gatekeeper

Итак, с установкой Gatekeeper мы разобрались. Теперь давайте настроим некоторые политики поверх него и поиграем с ними.

Тест политик Gatekeeper

Для начала мы введем политику, согласно которой вы не сможете создать пространство имен без ярлыков владельца проекта «owner». Ниже я добавил шаблоны ограничений и ограничения, а также несколько комментариев в разделе кода, чтобы вы могли лучше понять его.

apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8srequiredlabels
  annotations:
    metadata.gatekeeper.sh/title: "Required Labels"
    metadata.gatekeeper.sh/version: 1.0.0
    description: >-
      Requires resources to contain specified labels, with values matching
      provided regular expressions.
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredLabels
      validation:
        openAPIV3Schema:
          type: object
          properties:
            message:
              type: string
            labels:
              type: array
              description: >-
                A list of labels and values the object must specify.
              items:
                type: object
                properties:
                  key:
                    type: string
                    description: >-
                      The required label.
                  allowedRegex:
                    type: string
                    description: >-
                      If specified, a regular expression the annotation's value
                      must match. The value must contain at least one match for
                      the regular expression.
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        ## Defines the package name of the module
        package k8srequiredlabels

        get_message(parameters, _default) = msg {
          not parameters.message
          msg := _default
        }

        get_message(parameters, _default) = msg {
          msg := parameters.message
        }
        ## Defining the violation rule. The violation rule schema must be followed for it to be considered a valid ConstraintTemplate, which is {"msg": string, "details" set}
        violation[{"msg": msg, "details": {"missing_labels": missing}}] {
          ## 'provided' variable is a set with all the labels from the object currently being evaluated by gatekeeper
          provided := {label | input.review.object.metadata.labels[label]}
          ## 'required' variable is a set with all the labels from the Constraint parameters 
          required := {label | label := input.parameters.labels[_].key}
          ## 'missing' variable is a set the difference in value between required and provided
          missing := required - provided
          ## if there are more than zero values in the set 'missing' evaluate to true
          count(missing) > 0
          ## 'msg' variable is declared.
          def_msg := sprintf("you must provide labels: %v", [missing])
          msg := get_message(input.parameters, def_msg)
        }

        violation[{"msg": msg}] {
          value := input.review.object.metadata.labels[key]
          expected := input.parameters.labels[_]
          expected.key == key
          # do not match if allowedRegex is not defined, or is an empty string
          expected.allowedRegex != ""
          not re_match(expected.allowedRegex, value)
          def_msg := sprintf("Label <%v: %v> does not satisfy allowed regex: %v", [key, value, expected.allowedRegex])
          msg := get_message(input.parameters, def_msg)
        }
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
  name: ns-must-have-owner
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Namespace"]
  parameters:
    message: "All namespaces must have an `owner` label that points to your company username"
    labels:
      - key: owner
        allowedRegex: "^[a-zA-Z]+.LearnOps$"

После применения обоих файлов для существующих пространств имен обнаружено 7 нарушений.

Шаблон ограничений и ограничения

Шаблон ограничений и ограничения

Хорошо, попробуем создать пространство имен без метки и посмотрим, отклонит он запрос или нет.

apiVersion: v1
kind: Namespace
metadata:
  name: expected-to-be-fail

f91565bcbe39c4e40f3b89f59084f92a.png

Запрос на создание пространства имен отклонен, как и ожидалось, поскольку в нем отсутствует тег «owner». Попробуем теперь добавить тег «owner» и попытаемся создать его снова.

apiVersion: v1
kind: Namespace
metadata:
  name: expected-to-be-working
  labels:
    owner: mondeepmaity.LearnOps

05c99ccb2c6dd2d5b04b53ed47ccc131.png

Вуаля! Наше пространство имен создано.

Таким образом, можно настроить и другие политики в соответствии с потребностями проекта.

Вот ссылки, которые могут быть полезны для настройки политик вашего кластера:

Принудительный Dry Run

При внедрении новых ограничений в работающие кластеры может быть полезна функция Dry Run. Она позволяет развернуть ограничения в кластере без внесения фактических изменений. Это позволяет протестировать ограничения на работающем кластере без их принудительного применения. Ресурсы кластера, затронутые ограничением Dry Run, отображаются как нарушения в поле status ограничения.

Чтобы использовать функцию «сухого прогона», добавьте в спецификацию ограничения параметр enforcementAction: dryrun, чтобы гарантировать отсутствие фактических изменений в результате действия ограничения. По умолчанию для параметра enforcementAction установлено значение deny, так как по умолчанию запросы на допуск с любыми нарушениями отклоняются.

Предупреждение о принудительном действии

Предупреждение о принудительном выполнении предлагает те же преимущества, что и dry run. Например, тестирование ограничений без их принудительного выполнения. Кроме того, в этом случае можно сразу же получить информацию о том, почему данное ограничение было отклонено.

Config Resource

Config Resource может использоваться для исключения пространств имен и синхронизации ресурсов с определенными процессами для всех ограничений в кластере. Звездочка может использоваться для сопоставления с подстановочным знаком (например, kube-*). Чтобы исключить пространства имен на уровне ограничений, используйте excludedNamespacesв ограничении.

Некоторые ограничения невозможно написать без доступа к большему количеству состояний, чем просто тестируемый объект. Например, невозможно узнать, является ли имя хоста ingress уникальным среди всех ингрессов, если правило не имеет доступа ко всем остальным ингрессам. Чтобы сделать такие правила возможными, мы включаем синхронизацию данных в OPA.

Функция аудита по умолчанию не требует репликации. Однако если флаг audit-from-cache установлен в true, то кэш OPA будет использоваться в качестве источника истины для запросов аудита; таким образом, объект должен быть сначала помещен в кэш, прежде чем он будет подвергнут аудиту на предмет нарушения ограничений.

Данные Kubernetes могут быть реплицированы в OPA с помощью sync config resource. В настоящее время в OPA будут синхронизироваться ресурсы, для которых задано значение syncOnly. Обновление syncOnly должно динамически обновлять синхронизируемые объекты. Ниже приведен пример:

apiVersion: config.gatekeeper.sh/v1alpha1
kind: Config
metadata:
 name: config
 namespace: "gatekeeper-system"
spec:
  sync:
    syncOnly:
      - group: ""
        version: "v1"
        kind: "Namespace"
      - group: ""
        version: "v1"
        kind: "Pod"
  match:
    - excludedNamespaces: ["kube-*"]
      processes: ["*"]
    - excludedNamespaces: ["audit-excluded-ns"]
      processes: ["audit"]

Итоги

  1. Валидирующие и мутирующие политики в Kubernetes можно реализовать с помощью OPA gatekeeper.

  2. Rego позволяет определять сложную логику для политик. Но изучить rego нелегко. Однако «Gatekeeper-Library» — это очень хорошее репо для начала и изучения. Потом вы можете начать писать самостоятельно.

  3. Вы можете создать ограничение определенного вида только в том случае, если шаблон ограничения этого вида уже определен.

  4. При обкатке новых ограничений на работающих кластерах может быть полезна функция сухой прогона dry run.

Если вы хотите узнать об Open Policy Agent (OPA), заменить устаревший PSP, внедрить Gatekeeper в работающий кластер, то приходите на курс Kubernetes: Мега. Это продвинутый курс для тех, кто уже имеет опыт работы с K8s, хочет заглянуть под капот, научиться тонкой настройке и кастомизации. В курсе 7 онлайн-встреч со спикерами, практика на стендах и сертификация. 

Ознакомиться с программой и оставить заявку можно на нашем сайте.

© Habrahabr.ru