Стадия жизненного цикла модуля: Общедоступная версия

У модуля есть требования для установки

Карта рантайм-поведения — это предварительная функция, по умолчанию она отключена.

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

Что содержит карта

При включении карты на каждом узле работает агент, который наблюдает за поведением каждого контейнера с помощью eBPF. Наблюдения агрегируются по рабочим нагрузкам (Deployment, DaemonSet, StatefulSet, …) в два объекта:

  • ApplicationProfile — процессы, которые запускает рабочая нагрузка, файлы, которые она открывает, а также используемые ею Linux capabilities и системные вызовы (отпечаток приложения);
  • NetworkNeighborhood — входящие и исходящие соединения рабочей нагрузки с указанием другой стороны соединения и порта (карта сети).

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

Требования

Для работы карты рантайм-поведения требуется:

  • ядра узлов Linux 5.4 или новее, предоставляющие BTF в /sys/kernel/btf/vmlinux;
  • возможность запуска привилегированного агента с доступом к host PID. По умолчанию агент запускается на всех узлах; ограничьте его параметром nodeAgent.nodeSelector, если часть узлов не удовлетворяет требованию к ядру. Опциональный параметр nodeAgent.tolerations управляет запуском на узлах с taint;
  • StorageClass для данных модуля на базе блочных сетевых или локальных устройств или локальных путей (localpath). Модуль хранит карту в собственной встроенной базе данных (security-storage), а не в etcd кластера. Не используйте StorageClass на базе сетевых файловых или объектных хранилищ, например NFS, CephFS или S3. Параметр apiServerStorageClass задаёт StorageClass для security-storage. Размер PVC задаётся параметром securityStoragePVCRequest (по умолчанию 10 ГиБ).

Включение

Включите карту рантайм-поведения в ModuleConfig operator-trivy:

apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
  name: operator-trivy
spec:
  settings:
    nodeAgent:
      enabled: true
      learningPeriod: "1h"
  version: 2

learningPeriod задаёт, сколько времени наблюдается каждый контейнер, прежде чем его профиль считается завершённым. В течение этого окна карта продолжает вбирать вновь увиденное поведение; после — профиль фиксируется. Для рабочих нагрузок, поведение которых меняется в течение суток, используйте большее значение (например, 24h).

Просмотр карты

Объекты карты — namespaced-объекты, они находятся в тех же неймспейсах, что и рабочие нагрузки, которые они описывают.

Чтобы получить отпечатки приложений по всему кластеру, выполните:

d8 k get applicationprofiles -A

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

d8 k get networkneighborhoods -A

Чтобы получить полный отпечаток одной рабочей нагрузки, выполните:

d8 k -n <NAMESPACE> get applicationprofile <NAME> -o yaml

Где:

  • <NAMESPACE> — неймспейс рабочей нагрузки;
  • <NAME> — имя ApplicationProfile из вывода команды d8 k get applicationprofiles -A.

Записанные детали (процессы, файлы, capabilities, соединения) возвращает только запрос конкретного объекта по имени, например d8 k -n <NAMESPACE> get applicationprofile <NAME> -o yaml. Любой списочный запрос, с -A или без, возвращает объекты без этих полей, поэтому в списке они всегда выглядят «пустыми».

Данные начинают появляться в течение нескольких минут после старта контейнера; профиль продолжает расти и помечается завершённым по истечении периода обучения контейнера. Дайте только что включённой рабочей нагрузке хотя бы learningPeriod, прежде чем ожидать полную карту.

Генерация политик с минимальными привилегиями

Когда карта рабочей нагрузки построена, модуль может превратить её в политики с минимальными привилегиями. Включите одну или обе генерации:

spec:
  settings:
    nodeAgent:
      enabled: true
      generatePolicies:
        networkPolicy: true
        seccomp: true
  version: 2

Сетевые политики

При networkPolicy: true из наблюдаемого NetworkNeighborhood каждой рабочей нагрузки вычисляется GeneratedNetworkPolicy — готовая к проверке Kubernetes NetworkPolicy, описывающая ровно тот трафик, который у рабочей нагрузки наблюдался.

Чтобы получить сгенерированные политики по всему кластеру, выполните:

d8 k get generatednetworkpolicies -A

Чтобы получить политику одной рабочей нагрузки, выполните:

d8 k -n <NAMESPACE> get generatednetworkpolicy <NAME> -o yaml

Где:

  • <NAMESPACE> — неймспейс рабочей нагрузки;
  • <NAME> — имя GeneratedNetworkPolicy из вывода команды d8 k get generatednetworkpolicies -A.

Объект содержит стандартную NetworkPolicy в .spec. Проверьте её, затем извлеките и примените, чтобы ограничить трафик минимально необходимым:

d8 k -n <NAMESPACE> get generatednetworkpolicy <NAME> -o json | jq '.spec' | d8 k apply -f -

Seccomp-профили

При seccomp: true модуль генерирует SeccompProfile из наблюдаемых системных вызовов каждой рабочей нагрузки и обновляет его каждые 10 минут. SeccompProfile содержит отдельный профиль для каждого контейнера рабочей нагрузки в .spec.containers[].spec. Профили генерируются только для архитектур x86 (SCMP_ARCH_X86_64, SCMP_ARCH_X86, SCMP_ARCH_X32), поэтому используйте их только для подов, которые запускаются на узлах x86-64.

Чтобы получить список сгенерированных профилей, выполните:

d8 k get seccompprofiles.spdx.softwarecomposition.kubescape.io -A

Модуль не копирует профили на узлы. Чтобы использовать профиль, выполните следующие шаги:

  1. Извлеките профиль одного контейнера в файл:

    d8 k -n <NAMESPACE> get seccompprofiles.spdx.softwarecomposition.kubescape.io <NAME> -o json | jq '.spec.containers[] | select(.name == "<CONTAINER_NAME>") | .spec' > <PROFILE_FILE>.json

    Где:

    • <NAMESPACE> — неймспейс рабочей нагрузки;
    • <NAME> — имя SeccompProfile из вывода предыдущей команды;
    • <CONTAINER_NAME> — имя контейнера;
    • <PROFILE_FILE> — имя файла профиля.
  2. Скопируйте файл в директорию seccomp kubelet <KUBELET_ROOT>/seccomp/ на каждом узле, где может запускаться под. <KUBELET_ROOT> — корневая директория kubelet, по умолчанию /var/lib/kubelet.

  3. Укажите профиль в security context контейнера. Путь в localhostProfile задаётся относительно <KUBELET_ROOT>/seccomp/:

    spec:
      containers:
        - name: <CONTAINER_NAME>
          securityContext:
            seccompProfile:
              type: Localhost
              localhostProfile: <PROFILE_FILE>.json

Всегда проверяйте сгенерированную политику перед её применением. Профиль отражает только то поведение, которое наблюдалось в период обучения; редко используемые ветки кода могут отсутствовать, поэтому сначала проверьте под характерной нагрузкой.