Перейти к содержимому
GUARDCORE Инженерная база знаний Поиск

Блог

Безопасность цепочки поставки и runtime: где остановить риск, а где его увидеть

РазделБлог
ФорматПрактический разбор
ЦиклGuardCore
Чтение7 минут

Кратко

Контейнерный образ — это не просто файл для запуска. Он несёт код, зависимости, настройки и историю сборки; затем один и тот же артефакт проходит registry, CI/CD, Kubernetes API и runtime узла. Поэтому разговор о «сканировании образов» недостаточен. Нужна цепочка решений: какой артефакт…

Контейнерный образ — это не просто файл для запуска. Он несёт код, зависимости, настройки и историю сборки; затем один и тот же артефакт проходит registry, CI/CD, Kubernetes API и runtime узла. Поэтому разговор о «сканировании образов» недостаточен. Нужна цепочка решений: какой артефакт мы допускаем, кто это проверяет до запуска, что ограничивает сам Pod и какие события после запуска требуют реакции.

Важная оговорка: Kubernetes предоставляет механизмы для запуска образов, admission control и Pod Security Admission, но не даёт готовой универсальной системы сканирования, SBOM, проверки подписи или runtime detection. Эти части выбираются отдельно. Хорошая программа безопасности описывает границы продукта, а не обещает, что настройка Kubernetes сама собой проверит весь supply chain.

От тега к проверяемому артефакту

Тег образа удобен человеку (payments:1.8), но не является неизменяемой идентичностью: тот же тег может указывать на другой образ. Для развертывания и расследования полезно фиксировать digest — точное содержимое образа. Это даёт ответ на вопрос «какой именно артефакт работал», но само по себе не говорит, кто его собрал и безопасен ли он.

Практическая цепочка выглядит так:

  1. CI собирает образ из контролируемого исходного кода и фиксирует версию зависимостей.
  2. Сканер анализирует образ и формирует результат по уязвимостям; при необходимости создаётся SBOM.
  3. Артефакт попадает в registry, где для него сохраняются digest, результат проверки и, если выбрано решение для provenance, подпись/аттестация.
  4. Deployment ссылается на согласованный digest. Admission-проверка сверяет, что объект соответствует минимальным правилам организации.
  5. После запуска Pod Security Admission и securityContext ограничивают опасные параметры запуска, а runtime-датчик либо аудит собирают события процесса и сети.

Каждый этап отвечает на свой вопрос. Сканер отвечает «известна ли уязвимость на момент анализа». Подпись или аттестация — «есть ли проверяемое происхождение». Admission — «можно ли создать этот объект сейчас». Runtime-наблюдение — «что процесс делает после старта». Смешивать эти ответы означает оставлять дыры: например, без admission уязвимый или непроверенный образ всё равно может быть создан вручную, а без runtime можно не заметить эксплуатацию уже запущенного процесса.

Сканирование: риск, а не автоматический приговор

У сканера есть ложные совпадения, неполные базы и уязвимости без исправления. Поэтому правильная политика не звучит как «запрещать всё с CVE». Она определяет контекст: критичность, достижимость компонента, наличие фиксированной версии, публичность сервиса и срок исключения. Исключение должно быть ограниченным по времени, иметь владельца и ссылку на риск-решение. Иначе список исключений превращается в постоянный обход защиты.

Пример рабочего gate: критическая уязвимость в образе, доступном из Internet, блокирует продвижение до исправления или формально оформленного временного исключения. Средняя уязвимость в неиспользуемой утилите не блокирует релиз автоматически, но попадает в backlog с датой пересмотра. Такой подход сохраняет безопасность и не заставляет команды обходить CI.

Проверяйте не только «сканер запустился», а способность восстановить картину: для работающего Deployment можно назвать digest, источник сборки, время сканирования, результат политики и владельца исключения. Если хотя бы одного звена нет, расследование будет опираться на догадки.

Admission — точка, где можно предотвратить запуск

Admission controllers обрабатывают запрос к Kubernetes API до сохранения объекта. Это полезная точка для общих правил: допустимые registries, запрет mutable-тегов, минимальные поля securityContext, проверка подписи выбранным внешним валидатором. Но admission не заменяет CI: он не должен заново выполнять тяжёлый анализ при каждом kubectl apply и не видит дальнейшее поведение процесса.

Начните с малой, объяснимой политики. Например: рабочие namespaces принимают образы только из утверждённого registry и требуют digest; исключение возможно только в специально отмеченном namespace с владельцем и сроком. Сначала включите режим аудита или предупреждения, соберите реальные нарушения и исправьте шаблоны Helm/Kustomize. Блокирующий режим включайте по namespace, а не одним изменением для всей production-среды.

Не делайте admission-webhook единственной критической точкой без плана доступности. Нужно заранее решить, что происходит при его недоступности, кто обновляет сертификаты webhook, как откатить ошибочное правило и где увидеть отклонённые запросы. «Fail-open» снижает защиту во время сбоя; «fail-closed» может заблокировать развёртывания. Выбор зависит от риска и должен быть осознанным.

Pod Security Admission: встроенная защита запуска Pod

Kubernetes имеет встроенный Pod Security Admission (PSA), который применяет уровни Pod Security Standards на уровне namespace. У PSA три режима: warn показывает пользователю предупреждение, audit добавляет аннотацию в audit event, enforce отклоняет Pod с нарушением. Стандарты имеют уровни privileged, baseline и restricted.

Это хороший базовый контроль опасных параметров Pod, но не политика всего бизнеса. PSA не знает список разрешённых образов, не оценивает CVE и не определяет, имеет ли микросервис право обращаться к базе. Его задача уже и яснее: задать согласованный минимум безопасных параметров запуска.

Начните с наблюдения в одном прикладном namespace. Версию стандарта лучше закрепить под используемую версию Kubernetes: так обновление кластера не меняет требования неожиданно.

kubectl label namespace payments \
  pod-security.kubernetes.io/warn=restricted \
  pod-security.kubernetes.io/audit=restricted \
  pod-security.kubernetes.io/warn-version=v<ваша-версия-Kubernetes> \
  pod-security.kubernetes.io/audit-version=v<ваша-версия-Kubernetes>

Плейсхолдер v<ваша-версия-Kubernetes> нужно заменить конкретной поддерживаемой minor-версией, например v1.37 только если именно эта политика выбрана для кластера. После исправления предупреждений добавляют enforce=restricted на пилотный namespace. Перед этим проверьте DaemonSet, Jobs и контроллеры: Pods часто создаются не напрямую, а из шаблонов workload, и принуждение в итоге применяется к созданному Pod.

Runtime: обнаружение не равно предотвращению

Даже проверенный и ограниченный образ может быть скомпрометирован уязвимостью приложения. Runtime-слой ищет сигналы уже после запуска: неожиданный shell, запись в чувствительный путь, запуск бинарника из временного каталога, обращение к необычному адресу, попытку получить привилегии. Конкретный охват зависит от ОС, runtime, датчика и его настроек.

Сильный runtime-сигнал должен вести к готовой процедуре, а не только к алерту. Минимальный сценарий:

  1. Зафиксировать namespace, Pod, контейнер, образ по digest, узел и время события.
  2. Оценить критичность и сохранить логи/метаданные до перезапуска.
  3. Ограничить воздействие: изолировать workload сетевой политикой, остановить rollout или удалить скомпрометированный Pod — действие выбирается по runbook и критичности сервиса.
  4. Проверить соседние workloads с тем же digest и доступы service account.
  5. Устранить первопричину: обновить образ, правило или секрет, затем задокументировать выводы.

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

Как понять, что программа работает

Измеряйте не число установленных инструментов, а закрытие пути. Доля production-workloads с digest, доля образов с актуальным результатом сканирования, число временных исключений старше срока, доля namespaces с PSA в enforce, время от runtime-сигнала до triage и полнота связи «Pod → digest → сборка» — полезные показатели. Они показывают, где защита реальна, а где остаётся декларацией.

Итог: supply chain предотвращает попадание неподходящего артефакта, PSA ограничивает опасный способ его запуска, а runtime даёт шанс обнаружить ситуацию, которую ранние фильтры не остановили. Все три слоя нужны, но у каждого своя честная граница.

Официальные источники

Редакция GuardCore

Материал подготовлен на основе указанных в тексте нормативных источников и практических оснований. При существенном обновлении дата актуализации отображается рядом с датой публикации.

Обсуждение материала

Дополните материал практическим опытом или сообщите о неточности. Комментарий появится после проверки.

Форма защищена от автоматических публикаций. Все комментарии проходят модерацию.