Kubernetes: забытые уровни безопасности и как их настроить на практике

«Kubernetes приносит безопасность на новой границе, где инфраструктура становится кодом. Главная проблема — не в самих механизмах, а в том, что их применяют отрывочно, не выстраивая целостную оборону по принципу слоёной защиты.»

Поверхность атаки в Kubernetes гораздо шире, чем кажется

Типичный взгляд на безопасность кластера сводится к изоляции Worker-узлов и настройке RBAC. Это важные шаги, но они охватывают лишь часть возможных векторов. Поверхность атаки Kubernetes состоит из нескольких взаимосвязанных уровней:

  • Конфигурация самого кластера: параметры API Server, etcd, kubelet.
  • Сетевые политики (Network Policies): изоляция трафика между подами внутри кластера.
  • Взаимодействие с образами контейнеров: уязвимости, сигнатуры, сканирование.
  • Runtime-безопасность: контроль действий запущенных контейнеров.
  • Конфигурация безопасности пода (Pod Security): Security Context и Security Policies.
  • Управление секретами: хранение и доступ к чувствительным данным.

Настройка одного уровня без учёта других создаёт бреши. Атака, начавшись с уязвимости в образе контейнера, может через скомпрометированный под перейти на узел, а оттуда — в другие неймспейсы или в etcd.

Упущение №1: Неадекватная изоляция уровня Runtime

Подавляющее большинство развёртываний полагается на базовые возможности контейнеризации, не используя механизмы, которые резко сужают возможности потенциального злоумышленника внутри контейнера.

Security Context и возможности Linux

Security Context в манифесте пода, это минимальная, но критически важная настройка.

securityContext:
  runAsNonRoot: true
  runAsUser: 1000
  allowPrivilegeEscalation: false
  capabilities:
    drop:
      - ALL
    add:
      - NET_BIND_SERVICE
  seccompProfile:
    type: RuntimeDefault

Ключевые моменты:

  • runAsNonRoot: Запрещает запуск пода от имени root, что является базовой практикой.
  • capabilities.drop: Убирает все привилегированные возможности (capabilities), а затем добавляет только необходимые минимальные (например, NET_BIND_SERVICE для веб-сервера).
  • allowPrivilegeEscalation: false: Блокирует возможность для процессов внутри пода повысить свои привилегии, даже если есть уязвимость в SUID-бинарнике или другом механизме.
  • seccompProfile: Применяет дефолтный профиль seccomp, который ограничивает множество системных вызовов, доступных контейнеру.

Эти настройки часто опускают, особенно в Helm-чартах сторонних приложений, что оставляет контейнеры с избыточными правами.

AppArmor и SELinux — забытые оболочки

Если seccomp работает на уровне системных вызовов, то AppArmor и SELinux добавляют ещё один уровень контроля на основе путей к файлам, прав доступа и возможностей процессов. В Kubernetes можно применять готовые или кастомные профили AppArmor к подам. Профиль, запрещающий запись в каталоги, не предназначенные для данных приложения, или блокирующий выполнение посторонних бинарников, способен остановить многие виды атак на этапе выполнения. В российских окружениях чаще встречается SELinux, чью политику также можно адаптировать для контейнеров, хотя это требует большей подготовки.

Упущение №2: Сетевая изоляция «по умолчанию запрещено»

Сетевые политики (Network Policies) в Kubernetes, это stateful firewall на уровне pod’ов. Главная ошибка — их отсутствие или политика «разрешить всё». Идеальная начальная точка — политика «по умолчанию запрещено» (default-deny).

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
spec:
  podSelector: {}
  policyTypes:
  - Ingress

Эта политика, применённая ко всему неймспейсу, блокирует весь входящий трафик к подам. После этого вы явно разрешаете только необходимые соединения между компонентами. Например, разрешаете доступ к подам frontend только от ingress-контроллера, а к подам backend — только от frontend и из определённого CIDR админской сети. Такой подход резко сокращает поверхность для lateral movement внутри кластера.

Упущение №3: Игнорирование политик безопасности пода (PSP и их наследники)

Pod Security Policies (PSP) устарели, но их идея жива в новых механизмах: Pod Security Admission (PSA) и сторонних валидаторах, таких как Kyverno или OPA Gatekeeper. Суть в том, чтобы централизованно задавать требования к безопасности всех пода в кластере или неймспейсе, не полагаясь на сознательность разработчиков.

Pod Security Admission использует встроенные в Kubernetes Labels для неймспейсов и определяет три уровня: privileged, baseline и restricted. Наиболее строгий уровень restricted требует соблюдения всех современных практик, включая запрет root, отказ от привилегий и использование seccomp. Настройка уровня restricted для рабочих неймспейсов автоматически отклоняет или предупреждает о подах с небезопасными настройками.

apiVersion: v1
kind: Namespace
metadata:
  name: production
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/enforce-version: latest

Это простейший способ внедрить базовый стандарт безопасности, который многие пропускают.

Упущение №4: Работа с секретами как с конфигами

Secret в Kubernetes — не шифрованный объект, а закодированный в base64. Он хранится в etcd в открытом виде, если не включено шифрование на уровне etcd. Даже с шифрованием, секрет доступен в виде plaintext любому поду, которому он смонтирован или передан как переменная окружения.

Критические упущения:

  • Нет ротации секретов: Пароли и токены живут годами.
  • Секреты в логах и переменных окружения: При аварийном дампе переменные окружения могут попасть в логи.
  • Отсутствие интеграции с внешними Vault: Такие системы, как HashiCorp Vault или его аналоги, предоставляют динамические секреты, аудит и автоматическую ротацию.

Подход «хранить секреты в Kubernetes Secrets и обновлять их вручную» не соответствует требованиям регуляторики 152-ФЗ, где необходимы контроль доступа и учёт операций.

Упущение №5: Слепота к событиям кластера и аудит

API Server Kubernetes ведёт детальный аудит событий: кто, когда и что сделал с каким объектом. По умолчанию политика аудита часто настроена минимально или логи теряются в общем потоке системных логов.

Для соответствия требованиям необходимо:

  1. Настроить политику аудита, которая записывает события создания, изменения и удаления критических объектов (Secrets, ConfigMaps, Roles, Pods).
  2. Направлять аудит-логи в защищённое внешнее хранилище (не в etcd), куда у привилегированных пользователей кластера нет прямого доступа.
  3. Реализовать мониторинг и алертинг на подозрительные события: массовое создание подов, попытки доступа к Secrets из неожиданных неймспейсов или service accounts.

Без этого вы не сможете обнаружить и восстановить ход компрометации.

Практический чеклист: с чего начать усиление

Не пытайтесь внедрить всё сразу. Двигайтесь от наиболее критичных и простых в реализации пунктов.

Приоритет Область Действие
Высокий Конфигурация пода Во всех манифестах добавить runAsNonRoot: true и allowPrivilegeEscalation: false.
Высокий Сетевая безопасность Применить политику default-deny-ingress ко всем production-неймспейсам.
Высокий Управление доступом Проверить и ограничить права service accounts, особенно default в каждом неймспейсе.
Средний Безопасность образов Внедрить сканирование образов в CI/CD на уязвимости и внедрить политики (например, запрет образов с critical-уязвимостями).
Средний Политики безопасности Включить Pod Security Admission на уровне restricted для ключевых неймспейсов.
Средний Аудит Настроить и вынести в отдельную систему логи аудита Kubernetes API Server.
Низкий Runtime-защита Рассмотреть внедрение специализированных инструментов (Falco, Tracee) для детектирования аномалий.

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

Оставьте комментарий