Безопасность контейнеров и образов: проверки без стопа релизов
Безопасность контейнеров и образов: как настроить сканирование, политики и runtime-защиту в Aqua, Prisma Cloud и Sysdig без задержек релиза и с ясными исключениями.

Зачем это нужно и почему релизы начинают буксовать
Безопасность контейнеров и образов нужна не ради галочки. Она закрывает вполне приземленные риски: уязвимости в базовом образе, случайно попавшие секреты, опасные настройки (например, запуск от root), а также подмену образов в цепочке поставки.
Runtime-защита дополняет это тем, что ловит проблемы уже в работе: неожиданные сетевые подключения, запуск подозрительных процессов, попытки доступа к файлам, которые сервису не нужны.
Релизы обычно начинают тормозить после резкого включения проверок без понятных правил. В CI/CD внезапно появляется десятки критичных находок, сборки падают, команды спорят, что считать блокером, а что можно отложить. При этом нет нормального механизма исключений: кто согласует, на какой срок и что происходит, когда срок закончился. В итоге безопасность превращается в «стоп-кран», а не в управление риском.
Чаще всего пробуксовка происходит по трем причинам:
- пороги выставлены слишком жестко с первого дня (все Critical блокируют, даже если уязвимость не эксплуатируема в вашем контексте)
- нет разделения на новые и «наследованные» проблемы (то, что было в образе годами, начинает блокировать сегодня)
- нет прозрачного процесса исключений с владельцем и датой окончания
Успех здесь измеряется просто: меньше инцидентов и меньше сюрпризов в проде, а очередь на выпуск не растет. Хороший признак - когда команда заранее знает, что именно сломает сборку и как это исправить за часы, а не за недели.
Пример: команда обновила базовый образ и получила 40 уязвимостей. Если политика говорит только «запрещено», релиз встанет. Если политика отличает новые уязвимости от старых, допускает временное исключение на 14 дней и требует план обновления пакета, релиз выйдет, а риск останется управляемым.
Базовые понятия: что именно мы проверяем
Чтобы настроить проверки и не тормозить релизы, важно договориться о терминах. Иначе один человек говорит про CVE, другой - про права контейнера, а третий - про события в проде.
Образ (image) - это шаблон приложения: файловая система, зависимости, настройки запуска. Контейнер - запущенный экземпляр образа, который уже выполняет код и делает реальные действия в сети и в системе. Реестр (registry) - место, где образы хранятся и откуда их забирают CI/CD и кластер.
Обычно проверяют три разные вещи, и у каждой свой момент в цепочке:
- Сканирование образа: какие пакеты и библиотеки внутри, какие у них CVE, есть ли известные вредоносные компоненты.
- Проверка конфигурации: как собран образ и как он будет запущен (Dockerfile, Kubernetes-манифесты, права, сети, секреты).
- Runtime-события: что контейнер делает после запуска (неожиданные процессы, попытки эскалации прав, странные сетевые соединения).
Цепочка чаще ломается в мелочах. Берут старый base image, в котором накопились критические уязвимости. Копируют секрет в образ через Dockerfile, и он уезжает в реестр надолго. Запускают контейнер с правами root и лишними capabilities, потому что так «быстрее завелось».
Чтобы политики были рабочими, нужны не только данные сканера, но и контекст. Минимум:
- кто владелец сервиса (кому придет задача)
- насколько сервис критичен (прод для банка и учебный стенд - разные правила)
- какие сроки допустимы для исправления
Тогда пороги и исключения выглядят как договоренности, а не как случайные запреты.
Aqua, Prisma Cloud и Sysdig: как смотреть на выбор
У Aqua, Prisma Cloud и Sysdig есть общий базовый набор задач: найти уязвимости и небезопасные настройки в образах, применить понятные политики (что можно выпускать, а что нет) и защитить контейнеры во время работы. Если держать в голове эту тройку (образы, политики, runtime), сравнивать становится проще.
Разница чаще всего в акцентах и в том, где инструмент чувствует себя «родным». Одни решения сильнее в контроле цепочки поставки (сканирование образов, подписи, контроль базовых образов и реестров). Другие шире смотрят на облачную безопасность и комплаенс, связывая контейнеры с настройками облака и IAM. Третьи делают ставку на runtime-защиту и видимость происходящего в Kubernetes: кто куда ходит по сети, какие процессы запускаются, какие действия выглядят подозрительно.
Как выбрать под ваш контекст
Начните с простого вопроса: где живет прод и какие ограничения реальны - on-prem, облако или гибрид. Для госсектора и крупных организаций часто важны развертывание в собственном ЦОД, изоляция контуров и отчеты под аудит. В таких случаях важно, чтобы инструмент поддерживал ваши правила, а не пытался навязать чужую модель.
Заранее проверьте четыре вещи, которые чаще всего ломают внедрение:
- интеграции с реестром образов и поддержка ваших форматов, тегирования и жизненного цикла
- подключение к CI/CD без постоянных падений (мягкие пороги, отчеты, комментарии в MR)
- интеграция с Kubernetes (admission-контроль, политики на namespaces, исключения)
- выгрузка событий в SIEM и понятные алерты для SOC
Хороший тест - пилот на одном сервисе: включите сканирование, заведите 2-3 политики и одно исключение с датой окончания, затем посмотрите, сколько шума дает runtime. Если нужен пилот в on-prem или гибриде, этим обычно занимается системный интегратор - например, такие задачи закрывают в проектах уровня GSE.kz.
Цели, роли и пороги: без этого правила не заработают
Контейнерная безопасность ломается не на сканере, а на ожиданиях. Если команда думает, что проверка «для отчета», а безопасность ждет «ноль уязвимостей до прода», релизы начнут буксовать уже на первой неделе. Сначала договоритесь о целях и о том, что считается успехом.
Практично разделить цели на три уровня:
- информировать: показываем уязвимости и плохие практики, но ничего не останавливаем;
- ограничивать: задаем требования к новым изменениям (например, нельзя добавлять новые критические уязвимости), но старый долг не блокирует;
- блокировать: останавливаем сборку или деплой, если нарушены четкие правила.
Кто за что отвечает
Роли лучше назначить заранее, иначе все будет «между командами». Обычно работает такая схема:
- Dev отвечает за зависимости, базовый образ и исправление уязвимостей в коде.
- DevOps отвечает за пайплайн, реестр, политики в CI/CD и параметры запуска.
- Sec задает методику, требования, подтверждает исключения и следит за рисками.
- Владелец сервиса решает, что важнее при конфликте: срок релиза или снижение риска.
- Эксплуатация следит за тем, как это живет в проде: алерты, runtime-защита, инциденты.
Пороги и сроки, которые не тормозят релизы
Порог должен быть измеримым и понятным. Например: «Критические уязвимости - исправить за 7 дней, высокие - за 30, средние - по плану». И отдельно правило для релиза: «Нельзя выпускать, если в изменении появились новые критические и нет согласованного исключения».
Чтобы не утонуть в обсуждениях, держите правила в одном месте и пишите простым языком:
- что проверяем
- где проверяем (сборка, merge, деплой)
- что будет при нарушении
- кто может выдать исключение и на какой срок
Тогда Aqua, Prisma Cloud и Sysdig становятся инструментами исполнения, а не поводом для споров.
Пошаговая схема: проверки в CI/CD без стоп-крана
Хорошая схема строится как несколько «ворот», где ранние этапы дают быстрый сигнал разработчику, а поздние защищают прод. Тогда проверки становятся частью процесса, а не причиной ночных откатов.
Схема из четырех ворот
Чем ближе к продакшену, тем строже правила и тем выше уверенность в результате:
- Сборка: сканируйте образ сразу после build - пока контекст свежий и исправление дешевое.
- Публикация в реестр: повторная проверка перед push, чтобы в реестр попадали только проверенные версии.
- CI-политики: быстрые проверки на секреты, опасные инструкции в Dockerfile и критичные CVE (без попытки покрыть все сразу).
- Перед деплоем в кластер: admission-проверка по политикам, чтобы в Kubernetes не попадали образы, нарушающие правила.
Важно разделять «найдено» и «запрещено». Например, High CVE может быть предупреждением, а Critical с известным эксплойтом - блокировкой.
Как не останавливать релизы
Чтобы не превращать CI/CD в стоп-кран, начните с наблюдения и повышайте строгость по плану:
- Режим предупреждений: первые 1-2 недели не блокируйте, а собирайте статистику по командам и сервисам.
- Grace period: давайте срок на исправление (например, 14 дней) и показывайте дату, после которой правило станет блокирующим.
- Фича-флаги: включайте новые правила как переключатель, чтобы быстро откатить из-за ложных срабатываний.
- Пошаговые блокировки: сначала самые критичные правила и только для новых релизов, затем расширение на весь парк.
- Разделение по риску: публичные сервисы и платежные контуры ужесточайте раньше, внутренние - позже.
Такой подход одинаково реализуем в Aqua, Prisma Cloud или Sysdig: сначала видимость и понятные пороги, потом аккуратная блокировка. Например, в кластере на серверах GSE S200 Series можно начать с admission-проверки только для интернет-фронта, а затем подключать остальные сервисы, когда команда привыкнет к правилам и исключениям.
Как писать политики, чтобы они были выполнимыми
Политика - не «запретить все опасное», а правило, по которому команда понимает:
- что нужно изменить прямо сейчас
- что можно принять как риск
- кто это решение подтверждает
Хороший тест: разработчик должен за 2 минуты понять, что поправить в Dockerfile или манифесте.
Каркас понятного правила
В каждом правиле зафиксируйте:
- цель: что защищаем
- область: где действует (ветка, окружение, namespace, тип сервиса)
- условие: «если X, то Y» (конкретные поля, теги, настройки)
- порог: что блокирует, а что только предупреждает
- действие: кто и как исправляет, и где запрашивать исключение
Практика: политики, которые реально живут
Для образов проще всего начать с проверок, которые редко ломают релиз: список разрешенных базовых образов, запрет latest, требование неизменяемых тегов или digest, подписи образов. SBOM разумно вводить сначала для критичных сервисов.
Для CVE разделяйте уязвимости на фиксируемые и нефиксируемые.
Фиксируемые (есть патч) можно блокировать по порогу, например Critical и High в проде. Нефиксируемые лучше переводить в «разрешено с исключением», но с понятной причиной (нет обновления, ложное срабатывание, компонент не используется) и сроком пересмотра.
В Kubernetes полезно начинать с простых рисков: запрет privileged, запрет hostPath без явного списка, ограничение capabilities, запрет запуска от root без обоснования.
Сетевые политики часто начинают с «запрещено по умолчанию» внутри namespace и явных разрешений: кому можно ходить в базу, кто имеет выход в интернет, какие порты допустимы.
Минимальный стартовый набор, который обычно дает эффект без лишней боли:
- базовый образ только из списка и без
latest - подпись образа обязательна для прод
- блок по CVE: Critical с патчем
- в кластере: запрет
privilegedиrunAsRootпо умолчанию - NetworkPolicy: запрет входящего трафика без явного allow
Правила исключений: прозрачно и с датой окончания
Исключения неизбежны. Вопрос не в том, будут ли они, а в том, будут ли они управляемыми. Хорошее исключение помогает выпускать вовремя, но не делает вид, что риска нет.
Исключение обычно оправдано, когда: уязвимость не имеет доступного фикса (нет патча в базовом образе), исправление зависит от вендора и сроки неясны, или бизнес-сроки важнее, а риск можно временно снизить другими мерами. Причина уровня «потом разберемся» не считается.
Чтобы исключения одинаково работали в Aqua, Prisma Cloud или Sysdig, задайте простой стандарт. В карточке исключения должны быть:
- причина и что именно исключаем (CVE, пакет, образ, тег)
- владелец (конкретная команда или человек)
- срок действия (дата окончания)
- компенсирующие меры (например, запрет внешнего доступа, ограничение прав, включенный runtime-контроль)
- критерий закрытия (что должно случиться, чтобы исключение убрать)
Есть вещи, которые лучше запретить сразу: исключения без срока, массовые whitelist «на весь образ», исключения на критические уязвимости без компенсирующих мер.
Проверка исключений должна быть регулярной: короткий еженедельный разбор активных исключений и автоматические напоминания за 7-14 дней до окончания. Так команды успевают обновиться или осознанно продлить срок.
Пример: сервису в проде нужен образ с библиотекой, где фикс ожидается через месяц. Команда делает исключение на конкретный CVE только для одного репозитория и одного тега, ставит дату окончания, включает ограничение исходящего трафика и правило runtime на запуск shell и подозрительные процессы. Через месяц исключение либо закрывают после обновления базового образа, либо продлевают с новым обоснованием.
Чтобы исключения не стали дырой, полезны простые метрики: сколько активных исключений по сервису, средний возраст исключения, доля просроченных, сколько раз продлевали одно и то же.
Runtime-защита: как включать без лавины ложных срабатываний
Runtime-защита нужна там, где сканирование уже не помогает. Контейнер может быть «чистым» на сборке, но в рантайме начать вести себя странно: запускается неожиданный процесс, уходит трафик на неизвестный адрес, появляются записи в файловые пути, где им не место.
Как начать безопасно: сначала наблюдение
Не включайте блокировки в первый день. Сначала соберите «норму» поведения сервиса: какие процессы он запускает, какие порты слушает, куда ходит по сети, какие директории пишет. Обычно хватает нескольких дней реального трафика плюс пары типичных операций (деплой, прогрев кэшей, плановые задачи).
Потом переведите правила в режим алертов и смотрите не на количество событий, а на долю полезных. Если половина уведомлений не имеет владельца и не приводит к действию, значит правила слишком общие.
Минимальный набор правил, который почти всегда оправдан
Начните с короткого набора, понятного эксплуатационной команде и владельцам сервисов:
- запрет интерактивных шеллов в контейнере (bash, sh) для prod-неймспейсов
- детект запуска неожиданных бинарников (например, curl, nc), если они не нужны приложению
- запрет записи в системные пути (например, /bin, /usr/bin, /etc), кроме явно разрешенных случаев
- алерт на исходящие соединения к редким внешним адресам или нестандартным портам
- контроль монтирования чувствительных директорий и привилегированных режимов
Чтобы снизить шум, делайте исключения не «для всего кластера», а на уровне сервиса и с объяснением причины. Хорошая практика - ограниченный срок и владелец, который подтверждает, что риск понятен.
События отправляйте туда, где на них реально реагируют: критичные алерты - в SOC, технические и «серые» - в эксплуатацию, то, что требует решения о функционале, - владельцам сервисов.
Типовые ошибки при внедрении и как их избежать
Самая частая причина конфликтов с релизами - попытка включить максимальную строгость в первый же день. Команды получают десятки блокировок, не понимают, что именно исправлять, и начинают обходить правила.
Пять типовых ошибок:
- Сразу блокировать все критичное для всех репозиториев и команд. Лучше начать с 1-2 сервисов, собрать статистику и включать блокировки поэтапно.
- Смешивать политики для dev, stage и prod. В проде уместны жесткие пороги и подписи образов, в dev важнее скорость и подсказки.
- Игнорировать базовые образы. Закрепляйте версии, ведите список разрешенных base images и обновляйте их по расписанию.
- Думать, что сканер решит проблему сам. Сканирование показывает риск, но не отвечает на вопрос «кто чинит и когда».
- Делать исключения без срока и без владельца. Это быстро превращается в постоянные дыры.
Что обычно помогает:
- вводить пороги по этапам: сначала предупреждения, потом блокировки, и в первую очередь для prod
- разделить политики по средам и явно это зафиксировать
- назначить владельцев базовых образов и календарь обновлений
- держать простой поток: найдено -> тикет -> исправление -> повторная проверка
- любое исключение оформлять с причиной, ответственным и датой окончания
Пример: команда выпускает сервис для внутреннего портала. На первой неделе включают только уведомления и собирают топ повторяющихся проблем. На второй неделе блокируют только новые критические уязвимости в prod, а для старых заводят план исправления.
Быстрый чек-лист перед запуском в прод
Перед выпуском полезно сделать короткую проверку, которая ловит самые частые проблемы. Смысл не в том, чтобы «вспомнить про безопасность», а в том, чтобы решение было предсказуемым.
Минимальный набор вопросов, который реально пройти за 10 минут:
- Пороги и сроки: есть ли единые правила по критичности (что блокирует прод, а что допускается) и сроки исправления.
- Контрольные точки в пайплайне: проверяется ли образ при сборке и повторно перед деплоем.
- Базовые образы и теги: зафиксированы ли разрешенные base images, запрещены ли плавающие теги вроде
latest, понятна ли схема версионирования. - Исключения: есть ли единый шаблон (причина, владелец, сервис, тикет) и обязательна ли дата окончания.
- Runtime-наблюдение: включен ли хотя бы режим наблюдения и понятно ли, куда уходят алерты (канал, ответственные, время реакции).
Ориентир простой: если на релизе нашли критическую уязвимость, решение должно быть заранее описано. Например: «блокируем прод, но разрешаем тест, если есть исключение на 7 дней и владелец подтвердил план патча».
Если по любому пункту ответ «не уверены», остановитесь на 15 минут и договоритесь о правиле. Это почти всегда дешевле, чем разбирать инцидент после выката.
Пример сценария: как внедрить и не остановить поставку
Команда делает сервис для банка или госоргана. Релизы выходят раз в неделю, требования по ИБ строгие: отчеты по уязвимостям нужны быстро, но остановка релиза из-за каждого CVE недопустима.
Через пару запусков сканера выясняется неприятное: в base image десятки CVE, часть - в пакетах, которые сервис не использует напрямую. Если включить жесткий блок на все, поставка встанет. Значит, правила вводят поэтапно и с понятными исключениями.
Практичный план на первые 3-4 недели:
- Неделя 1: сканирование образов в CI/CD в режиме предупреждений. Отчет видят разработчики и ИБ, пайплайн не падает.
- Неделя 2: блок только на Critical, если уязвимость имеет фикс и попадает в используемые пакеты. Для High пока только предупреждения.
- Неделя 3: согласование «золотого» base image и расписание обновлений, чтобы CVE не копились.
- Неделя 4: runtime-наблюдение в режиме detect-only: сбор событий без автоматических блокировок.
Если критичная уязвимость в base image не чинится быстро, оформляют исключение на 30 дней: причина, затронутые образы и сервисы, компенсирующие меры (например, запрет shell в контейнере, ограничения egress, запуск не под root), владелец и дата окончания.
Через месяц смотрят метрики:
- среднее время прохождения пайплайна и доля релизов без ручных согласований
- количество активных исключений и доля просроченных
- сколько Critical закрыто обновлением base image
- сколько runtime-событий оказалось реальными инцидентами, а сколько - шумом
Если показатели улучшаются, повышают строгость: расширяют блок на часть High и переводят runtime из наблюдения в точечные блокировки для самых опасных действий.
Следующие шаги: план на 2-4 недели и кому поручить
Чтобы проверки не превратились в «стоп-кран», начните с короткой инвентаризации: где хранятся образы (реестры и теги), как идет деплой (Helm, GitOps, вручную), кто владеет сервисами, кто принимает решения по уязвимостям. Это быстро подсветит спорные места: «кто должен чинить» и «кто может согласовать исключение».
План на 2-4 недели
Темп, который обычно не ломает релизы и дает быстрый результат:
- Неделя 1: инвентаризация реестров, CI-джобов, кластеров и критичных сервисов. Выбор пилотного сервиса с понятным владельцем.
- Неделя 2: сканирование образов в CI/CD в режиме отчета. Набор правил, которые реально выполнить (запрет root-пользователя, базовые метки, базовый образ из списка).
- Неделя 3: перевод части правил в «soft gate» (предупреждаем, но не блокируем), запуск процесса исключений с датой окончания и ответственным.
- Неделя 4: минимальная runtime-защита на пилоте (наблюдение или блокировка самых опасных действий), расширение на 2-3 сервиса.
Правила формулируйте так, чтобы разработчик понимал следующий шаг: «обнови базовый образ», «пересобери с фиксированной версией», «убери пакет». Для исключений держите один шаблон: причина, риск, компенсирующая мера, владелец, срок.
Кому поручить
Разделите ответственность заранее:
- Платформа/DevOps: реестры, CI-агенты, политики в кластере.
- Команды сервисов: исправления в Dockerfile и зависимостях, пересборка.
- ИБ: пороги, подтверждение исключений, контроль сроков.
- Владельцы продукта: приоритеты, что чиним первым.
Если нужен подбор Aqua, Prisma Cloud или Sysdig под ваш контур и внедрение в on-prem или гибриде, это удобно делать вместе с системным интегратором. В проектах GSE.kz такой подход часто дополняют инфраструктурой (включая серверы), интеграцией с существующими системами и поддержкой 24/7.
FAQ
Как внедрить проверки контейнеров так, чтобы релизы не встали в первую неделю?
Начните с режима наблюдения: собирайте результаты сканирования и проверок, но не блокируйте сборки 1–2 недели. Затем вводите блокировки только для новых критичных проблем и только в прод-контуре, оставляя «наследованный» долг в плане работ с датами.
В чем разница между образом и контейнером, и почему это важно для безопасности?
Образ — это шаблон с файловой системой, зависимостями и настройками запуска. Контейнер — это запущенный экземпляр образа, который выполняет процессы, пишет файлы и ходит по сети, поэтому для него важны runtime-события и поведение в кластере.
Что именно нужно проверять: CVE, настройки или поведение в рантайме?
Обычно проверяют содержимое образа на CVE и вредоносные компоненты, конфигурацию сборки и запуска (Dockerfile и манифесты Kubernetes), а также события во время работы. Эти три слоя дополняют друг друга: сканирование не видит подозрительное поведение, а runtime не отменяет необходимость обновлять базовые пакеты.
Какие пороги по критичности уязвимостей реально работают в CI/CD?
Установите простые правила по срокам исправления и отдельное правило для релиза. Практичный вариант: критичные с доступным фиксом исправлять быстро, а релиз блокировать только если в текущем изменении появились новые критичные и нет согласованного исключения.
Как правильно отличать новые уязвимости от тех, что давно сидят в base image?
Разделяйте проблемы на новые и «наследованные». Новые уязвимости должны ухудшать ситуацию только если они появились из-за текущего изменения, а старый долг лучше фиксировать через план обновления базового образа и зависимостей, чтобы не превращать безопасность в вечный стоп.
Как избежать попадания секретов в образ и реестр?
Секреты нельзя копировать в образ, потому что они останутся в слоях и могут утечь через реестр или кэш. Держите секреты вне образа и подавайте их на запуске через штатные механизмы платформы, а в CI добавьте быстрые проверки на утечки, чтобы ловить ошибки до публикации.
Как оформить исключение, чтобы оно не стало дырой в защите?
Хорошее исключение всегда точечное и временное: что именно разрешаем, кто владелец, когда истекает срок, и какие компенсирующие меры включены. Исключения без даты окончания и массовые разрешения «на весь образ» быстро превращаются в постоянные дыры и их сложно контролировать.
Как включать runtime-защиту без лавины ложных срабатываний?
Включайте runtime сначала в detect-only, чтобы собрать «норму» поведения сервиса, и только потом ужесточайте. Если алертов слишком много, сужайте правила до конкретного сервиса и действия, и назначайте владельца события, иначе уведомления будут игнорироваться.
На что смотреть при выборе Aqua, Prisma Cloud или Sysdig под свой контур?
Выбор проще, если сравнивать по трём задачам: контроль образов и цепочки поставки, политика и контроль запуска в Kubernetes, наблюдение и защита в рантайме. Сразу проверьте интеграции с вашим реестром, CI/CD, admission-контролем и выгрузкой событий в SIEM, потому что именно на этих стыках чаще всего ломается пилот.
Что учесть, если прод on-prem или гибридный, а не только облако?
Для on-prem и гибридных сред заранее уточняйте, что решение нормально разворачивается в вашем ЦОД и поддерживает изоляцию контуров и аудит. На практике пилот удобнее делать на одном сервисе в реальном кластере, где можно проверить политики деплоя, интеграцию с мониторингом и процесс исключений; такие пилоты часто проводят вместе с системным интегратором, например в проектах уровня GSE.kz.