
Linux даёт мощные механизмы безопасности уровня ядра — seccomp, SELinux и AppArmor, — которые ограничивают возможности контейнеризированных рабочих нагрузок. Если коротко: seccomp фильтрует системные вызовы процесса, SELinux и AppArmor накладывают мандатные политики доступа к файлам, сети и возможностям. Каждый из них работает через профили, которые описывают разрешённое поведение, но писать, распространять и поддерживать такие профили вручную утомительно и легко ошибиться.
Security Profiles Operator (SPO) снимает эту боль: профилями безопасности можно управлять как пользовательскими ресурсами Kubernetes, записывать их с работающих нагрузок и декларативно привязывать к подам.
С выходом v1.0.0 Security Profiles Operator переводит все восемь своих API типа Custom Resource Definition (CRD, определение пользовательского ресурса Kubernetes) на версию v1. Это первый стабильный релиз проекта, подкреплённый сторонним аудитом безопасности, полным циклом работ по усилению защиты и путём миграции без простоя с любой предыдущей версии API.
Команда VK Cloud перевела статью о том, как проект Security Profiles Operator за шесть лет довёл свои API до версии v1, прошёл сторонний аудит безопасности и теперь влияет на развитие самого Kubernetes. Это будет полезно тем, кто отвечает за безопасность кластеров — DevOps- и SRE-инженерам, специалистам по ИБ и разработчикам, которые пишут профили seccomp, SELinux и AppArmor для контейнеров.
Шесть лет эволюции API
SPO появился в апреле 2020 года как оператор, который работал только с seccomp. За следующие годы проект вырос и охватил SELinux (конец 2020 года), AppArmor (конец 2021 года), запись профилей через журналы аудита и eBPF, распространение профилей на основе OCI и многое другое. Каждая функция добавляла новые CRD, и эти CRD оставались на стадии alpha или beta, пока API дозревали в реальной эксплуатации.
Некоторые из этих API на практике были стабильными уже годами: SeccompProfile поставлялся в версии v1beta1 более четырёх лет, SPOD — в версии v1alpha1 более пяти лет. Потребителям ниже по цепочке нужна была стабильная версионная метка, на которую можно опереться при долгосрочной поддержке. SPO доступен в OperatorHub с 2022 года и входит в состав Red Hat OpenShift начиная с версии 4.12. Окно перед v1 было последней возможностью внести ломающие изменения, и команда ею воспользовалась.
Эта чистка вылилась во множество pull request’ов:
-
Структурные изменения. Все CRD теперь используют общий тип статуса на основе conditions из upstream Kubernetes. Спецификацию SPOD реорганизовали: вместо плоского списка из 30+ полей — логические группы (SELinux, Enricher, Webhook, Scheduling, Security). Общие базовые типы вынесли отдельно, чтобы не дублировать их между CRD.
-
Исправления типов. Несколько типов полей обновили под конвенции API Kubernetes: в частности, беззнаковые целые числа заменили на знаковые. Внешние типы, которые создавали лишние зависимости импорта, перенесли внутрь.
-
Приведение к конвенциям. Значения enum перевели в PascalCase (например,
logsвLogs,RUNNINGвRunning). Каждое поле получило маркер+optionalили+required. Ко всем типам добавили маркеры валидации.
Единственное намеренное исключение: константы seccomp SCMP_ACT_* и SCMP_CMP_* сохраняют имена в верхнем регистре, чтобы дословно соответствовать спецификации OCI runtime и заголовкам ядра Linux.
Аудит безопасности и усиление защиты
Перед переходом на v1 SPO прошёл аудит кода на безопасность. Аудит не нашёл ни одной критической уязвимости. Он подтвердил, что:
-
пути к файлам, записываемым на хост, выводятся из метаданных объекта, а не из управляемых пользователем полей
spec; -
команды формируются как массивы аргументов — поверхности для shell-инъекций нет;
-
значения RBAC (управление доступом на основе ролей) по умолчанию не дают лишних привилегий пользователям без прав администратора.
При этом аудит выявил области для усиления защиты — особенно на границе, где пользовательский ресурс арендатора транслируется в состояние LSM (Linux Security Module, модуль безопасности ядра Linux) на уровне ядра. Релиз v1.0.0 устраняет эти находки.
RawSelinuxProfile: ограничение и валидация. RawSelinuxProfile позволяет писать произвольную SELinux-политику на CIL (Common Intermediate Language, промежуточный язык политик SELinux), которую оператор устанавливает на узле. Аудит отметил этот путь как самый рискованный. В v1.0.0 новое поле enableRawSelinuxProfiles в конфигурации SPOD позволяет администраторам кластера полностью отключить поддержку сырых профилей SELinux. Валидирующий admission-вебхук теперь отклоняет некорректные сырые политики, а не даёт им упасть на этапе reconciliation.
SelinuxProfile: управление permissive-режимом. Булево поле permissive у SelinuxProfile заменили на enum mode (Enforcing или Permissive), что снимает риск случайно включить permissive-режим при незаданном поле.
Санитизация ввода AppArmor. Профили AppArmor принимают шаблонные входные данные для имён профилей, путей к исполняемым файлам и capabilities. Аудит отметил, что эти данные загружались без валидации содержимого. SPO теперь применяет к каждому из них строгую regex-валидацию и не даёт перезаписать профили, уже загруженные в ядро.
Ограничения размера полей и маркеры валидации. Поле RawSelinuxProfile.spec.policy теперь несёт maxLength в 500 КБ, ограничивая размер ввода до того, как он достигнет компилятора SELinux CIL на узле. Маркеры валидации добавили ко всем типам CRD.
Дополнительное усиление защиты за рамками аудита
-
Откат regex (backtracking): жадные regex-операторы в парсерах журналов seccomp, SELinux и AppArmor заменили на ограниченные шаблоны, чтобы специально подготовленные строки журнала аудита не вызывали чрезмерного отката.
-
Ограничение путей:
HostProcVolumePathтеперь проверяется на соответствие только/proc.seccomp-ListenerPathограничен директорией сокета оператора. -
Лимиты ресурсов eBPF-рекордера: eBPF-рекордер профилей теперь ограничивает число записываемых файлов и максимальную длину пути, предотвращая OOM на нагрузках с высокой активностью файловой системы.
-
Точность кэша процессов: кэш процессов теперь использует ключ из PID плюс время старта процесса, что предотвращает устаревшие попадания в кэш после повторного использования PID.
-
Обработка аннотаций записи: вебхук записи корректно перезаписывает существующие аннотации, а не пропускает молча уже аннотированные поды.
-
Кардинальность метрик: неограниченные метки убрали из счётчиков Prometheus, чтобы предотвратить метрики высокой кардинальности.
Миграция без простоя
Обновление до v1.0.0 не требует ручных шагов миграции. Конвертирующие вебхуки прозрачно обрабатывают трансляцию между старыми и новыми версиями API:
-
Старые манифесты по-прежнему работают: вы можете и дальше применять ресурсы через версии API v1alpha1, v1alpha2 или v1beta1. Конвертирующий вебхук транслирует их в v1 перед сохранением.
-
Старые версии API по-прежнему обслуживаются:
kubectl getсо старой версией API возвращает ресурсы со значениями enum в старом стиле, даже когда версией хранения является v1. -
Значения enum сопоставляются в обе стороны: слой конвертации транслирует между значениями enum старого стиля (
logs,RUNNING) и нового стиля (Logs,Running) в обоих направлениях.
Вот как ProfileRecording выглядит до и после:
# До (v1alpha1)
apiVersion: security-profiles-operator.x-k8s.io/v1alpha1kind: ProfileRecordingmetadata: name: my-recordingspec: kind: SeccompProfile recorder: logs mergeStrategy: none podSelector: matchLabels: app: my-app
# После (v1)
apiVersion: security-profiles-operator.x-k8s.io/v1kind: ProfileRecordingmetadata: name: my-recordingspec: kind: SeccompProfile recorder: Logs mergeStrategy: None podSelector: matchLabels: app: my-app
Для CRD без изменений enum меняется только строка apiVersion. Полное руководство по миграции охватывает обновления для потребителей Go API, изменения констант enum и регистрацию схемы. Старые версии API останутся доступными для обратной совместимости и будут удалены в одном из будущих релизов.
От оператора к upstream Kubernetes
SPO всегда был тесно связан с upstream-работой над профилями безопасности в Kubernetes. Проект построен на GA API-поверхности seccomp (Kubernetes 1.19) и рос вместе со связанными предложениями — seccomp-профилями на основе ConfigMap и встроенными seccomp-профилями с режимом complain.
Свежайший пример этой связи — KEP 6061: распространение профилей безопасности на основе OCI-артефактов, KEP (Kubernetes Enhancement Proposal, предложение по развитию Kubernetes), предложенный для одного из будущих релизов Kubernetes в статусе alpha. SPO стал пионером распространения профилей на основе OCI ещё годы назад: пользователи могли публиковать профили seccomp, SELinux и AppArmor в OCI-реестры и ссылаться на них напрямую из спецификаций подов. KEP 6061 переносит эту концепцию нативно в kubelet, добавляя вызов CRI (Container Runtime Interface, интерфейс среды выполнения контейнеров) API PullSecurityProfileArtifact, чтобы среды выполнения контейнеров могли по требованию получать профили из OCI-реестров.
KEP следует той же модели доверия, что и localhost-профили: список разрешений с запретом по умолчанию на уровне kubelet, при этом Pod Security Admission относится к OCI-профилям так же, как к localhost. SPO продолжит давать высокоуровневые возможности, которые kubelet не охватывает: запись профилей с работающих нагрузок, структурированное написание SELinux-политик, привязку профилей к образам контейнеров и обогащение журналов аудита.
Что дальше
Теперь, когда v1 вышел, приоритеты проекта таковы:
-
Удаление старых версий API минимум через один цикл релизов.
-
Продолжение усиления защиты: более узкое ограничение области RBAC и более безопасные операции с путями в привилегированных компонентах.
-
Интеграция KEP 6061 — связывание возможностей распространения OCI у SPO с нативной поддержкой в kubelet по мере её созревания через alpha и beta.
Попробуйте v1.0.0, прочитайте руководство по миграции и присоединяйтесь к обсуждению в #security-profiles-operator в Kubernetes Slack.
SPO создан более чем 70 контрибьюторами из множества организаций. Спасибо всем, кто вносил код, заводил issues, тестировал пре-релизы и участвовал в аудите безопасности. v1 — это в той же мере ваш, что и наш.
ссылка на оригинал статьи https://habr.com/ru/articles/1056812/