Контейнеры в DevOps – понятие не новое. Они представляют собой виртуальные песочницы со всеми необходимыми инструментами для запуска микросервисов, в том числе и крупных приложений. Контейнеры можно рассматривать как упаковочные системы, позволяющие централизованно хранить все необходимое для запуска приложения (например, время выполнения и бинарные коды). Контейнеры помогают разработчикам переносить приложения из одной среды в другую (например, переносить приложение с локальной машины в виртуальную среду или переводить его с начальной стадии на производственную), устраняя все проблемы, связанные с различиями в программном обеспечении и настройках конфигурации на стороне разработчиков и на производстве.
Отчет Statista о контейнерных технологиях показывает, что 50% организаций в мире внедрили оркестровку контейнеров. Несмотря на то, что эта технология получила широкое распространение благодаря своим преимуществам, контейнеры могут открыть ворота для атак кибербезопасности, если их не контролировать. CVE Details, основной источник данных об уязвимостях в системе безопасности, на данный момент зарегистрировал 62 уязвимости, связанные с Docker. Разве это не требует применения лучших практик для разработчиков, чтобы устранить эти подводные камни и защитить контейнеры для успешного выполнения процессов DevOps? В этой статье мы рассмотрим концепцию безопасности контейнеров, выделим некоторые проблемы и расскажем о лучших практиках, которые следует применять при использовании контейнерных технологий.
Что такое безопасность контейнеров?

Обеспечение безопасности контейнеров – это непрерывный процесс, в котором используются протоколы безопасности (инструменты и политики) для защиты контейнеров и их окружения от потенциальных угроз. Если угрозы не будут устранены, они могут нанести вред приложению, его инфраструктуре, времени выполнения, системным библиотекам, операционной системе, ядру и т.д. Учитывая, что контейнеры доступны в переходные периоды (мгновенно), а также предназначены для динамического развертывания и масштабирования, возникает необходимость в автоматизированной защите на всех этапах жизненного цикла разработки ПО (SDLC).
Какие проблемы возникают при обеспечении безопасности контейнеров?

Несмотря на то что контейнеры имеют множество преимуществ (например, ускорение доставки программного обеспечения), они не лишены проблем, главным образом потому, что нуждаются в мерах безопасности (им не хватает возможностей самозащиты). Это связано с тем, что контейнеры получают доступ к аппаратному обеспечению через размещенную операционную систему (ОС). Это означает, что один контейнер может иметь несколько базовых образов контейнеров, что расширяет возможности для атак и создает некоторые проблемы.
Первая из них – неправильная конфигурация контейнера, когда разработчики забывают о настройке и используют стандартные конфигурации контейнеров, которые имеют ряд недостатков, таких как открытые небезопасные порты, которые могут не подходить для вашего приложения, утечка учетных данных, таких как пароли и маркеры аутентификации, а также чрезмерная выдача прав на выполнение контейнера (при запуске от имени root). Если эти настройки по умолчанию не отменить, то они открывают возможности для атак.
Далее следует уязвимость контейнерной инфраструктуры. Здесь уязвимости создают пакеты, встроенные в контейнер, такие как код приложений, библиотеки и конфигурации, или пакеты, находящиеся в операционной системе хоста. Уязвимость может быть внесена на любом этапе жизненного цикла приложения, например, при встраивании внешних зависимостей в образ контейнера, установке библиотек с открытым исходным кодом в составе приложения, получении базовых образов контейнеров из сторонних реестров контейнеров и хостов, которые могут эксплуатироваться через сети и конечные точки.
Видимость контейнерных рабочих нагрузок является одной из самых серьезных проблем, связанных с контейнерами. Это связано с высокой динамичностью контейнеров, из-за которой средства мониторинга не могут определить, какие контейнеры запущены, и проследить за их сетевым поведением. Улучшение видимости позволяет предотвратить нарушения и увеличить время реакции на них в случае возникновения.
Кроме того, контейнер подвержен риску, если на любом этапе CI/CD-конвейера отсутствует безопасность, как в коде приложения, так и в инфраструктуре рабочей нагрузки контейнера. Хотя разработчики должны заниматься вопросами безопасности в конце жизненного цикла приложения, администрирование на каждом этапе разработки защищает ваши приложения от подобных неудач.
Какие инструменты могут решить проблемы безопасности контейнеров?
Обеспечить безопасность развернутых корпоративных решений можно с помощью средств обеспечения безопасности и целостности контейнеров. Эти средства сканируют контейнеры на наличие уязвимостей и постоянно отслеживают их на предмет атак, ошибок или каких-либо проблем. Независимо от того, ищете ли вы инструменты для обеспечения безопасности контейнеров с открытым исходным кодом или коммерческий тип, все они служат одной цели.
Все они работают на основе аудита контейнерной инфраструктуры и проверки на наличие распространенных уязвимостей и уязвимых мест (CVE). Вот несколько инструментов, которые можно попробовать: Pingsafe Editors Choice, Datadog Cloud SIEM, Anchore, Sophos Cloud-Native Security, Bitdefender GravityZone, Sysdig secure, Aqua Security и RedHat Advanced Cluster Security for Kubernetes.
Лучшие практики обеспечения безопасности контейнеров
Несмотря на вышеперечисленные проблемы, связанные с безопасностью контейнеров, ниже приводится список лучших практик, которые можно применить для оптимизации безопасности контейнеров на всех этапах жизненного цикла приложений.
Защита образов
Для создания контейнеров используются образы контейнеров. Малейшая ошибка в конфигурации или злонамеренные действия могут привести к появлению уязвимостей в используемых контейнерах. Для борьбы с этим необходимо:
- Использование надежных образов – если не создавать образы с нуля, то лучше работать с образами из надежных источников. В публичных репозиториях, таких как Docker Hub, имеются образы, в том числе с вредоносным ПО и неправильной конфигурацией.
- Включение только необходимых компонентов – Если есть компоненты, которые не нужны вашему приложению, лучше их удалить. Например, в системе UNIX естественным образом присутствуют двоичные файлы ‘awk’ и ‘sed’.
- Включение вашего приложения в образ контейнера – В образ контейнера помещается подмножество операционной системы (ОС) и выполняемого приложения. Каждый инструмент и библиотека, попавшие в контейнер, представляют собой потенциальную угрозу. Для решения этой проблемы лучше всего включить приложение в образ контейнера. Для этого используется статически скомпилированный двоичный файл со всеми необходимыми зависимостями.
Автоматизация сканирования на уязвимости и управления

Регулярное сканирование уязвимостей и управление контейнером и хостами позволяет обнаружить уязвимости на любом этапе жизненного цикла приложения. В этом случае можно задействовать сканирование кода для обнаружения ошибок и статическое тестирование безопасности приложений (SAST) для поиска уязвимостей в коде приложения. Анализ состава программного обеспечения (SCA) позволяет получить представление о компонентах ПО с открытым исходным кодом, формируя спецификацию ПО, которая может быть сопоставлена с задокументированными уязвимостями открытого ПО.
Кроме того, сканирование изображений позволяет проанализировать содержимое и процесс создания образа контейнера на предмет уязвимости. С помощью таких инструментов, как Clair, можно сканировать известные уязвимости. В качестве альтернативы можно использовать динамическое тестирование безопасности приложений (DAST), которое выявляет риски безопасности на основе поведения контейнеров.
Средства DAST могут также выполнять сканирование хоста, при котором проверяются компоненты хоста контейнера (ядро и ОС хоста) на предмет неправильной конфигурации. Хотя перечисленные выше меры принимаются в процессе жизненного цикла контейнера, можно воспользоваться философией “сдвига влево”. Это означает внедрение безопасности с самого начала жизненного цикла разработки. Хорошим инструментом при выборе такого подхода является Trivy.
Защита реестров контейнеров
Реестры контейнеров – это эффективный централизованный способ хранения образов и их распространения. Часто в организациях тысячи образов хранятся в публичных или частных реестрах. Существует несколько мер, позволяющих обеспечить использование образов без уязвимостей всеми членами команды и сотрудниками. Во-первых, реализация контроля доступа пользователей (для частных реестров) определяет, кто может публиковать изображения и получать к ним доступ.
Хотя это и базовая мера безопасности, она позволяет предотвратить публикацию, изменение или удаление изображений неавторизованными лицами. Следующей мерой является подписание образов, которое привязывает каждый образ к тому, кто его подписал, и затрудняет подмену образа на скомпрометированный. Для добавления цифровых подписей к данным, отправляемым и получаемым из реестров, можно использовать технику Docker Content Trust. Наконец, не забывайте, что сканирование образов (постоянное) помогает обнаружить любые критические уязвимости.
Мониторинг контейнеров
Оптимизировать видимость контейнерных рабочих нагрузок можно с помощью инструментов наблюдаемости. Эти средства должны обеспечивать мониторинг и тестирование на наличие уязвимостей во всех компонентах, а также регистрацию реальных событий в контейнерных средах. Средства наблюдаемости обнаруживают угрозы путем аудита метрик и журналов всех компонентов контейнерного стека и их анализа на предмет аномалий. Такой подход позволяет сразу же устранить обнаруженные ошибки в конфигурации. Для сбора метрик использования ресурсов используются такие инструменты, как cAdvisor или kube-state-metrics.
Для мониторинга активности контейнеров и производительности кластеров используются такие инструменты, как Grafana или Prometheus. Если необходимо проанализировать сетевой трафик между контейнерами, используйте Wireshark или tcpdump. Если вы используете управляемый сервис Kubernetes, например (AKS), используйте Azure Monitor для отслеживания ресурсов и угроз безопасности. Кроме того, Azure Log Analytics может собирать и анализировать ваши ресурсы AKS. Если вы выбрали Amazon EKS, то для ведения журнала и наблюдения хорошо подходит Amazon CloudTrail; используйте Amazon Cloud Watch.
Реализация сетевой безопасности
Меры контроля сетевой безопасности позволяют защитить контейнеры от несанкционированного доступа. В качестве критерия здесь используется сегментация сети, которая изолирует контейнеры, ограничивая их доступ только к необходимым сервисам. Если вы запускаете контейнерные приложения на Kubernetes, то с помощью сетевых политик K8s можно настроить входящий и исходящий трафик в кластерах. Это, в свою очередь, позволяет ограничить трафик для определенных капсул на основе меток. Для связи между стручками может быть использована дополнительная защита транспортного уровня (TLS). Для обеспечения безопасности связи между сервером API и другими компонентами можно использовать либо TLS, либо SSL.
Балансировщики нагрузки – хорошее решение, если вы хотите ограничить поступление трафика в кластеры. Если в кластерах имеются микросервисы, то обеспечить безопасный трафик можно с помощью таких инструментов сетки сервисов, как Meshery или Linkerd. Наконец, защитите свою сеть, если для размещения кластеров используется “облачный” провайдер. Если вы используете Azure Kubernetes Service (AKS), используйте группы сетевой безопасности (NSG) для управления трафиком. Если вы используете Amazon Elastic Kubernetes Service (EKS), то лучше всего использовать группы безопасности виртуального частного облака (VPC) Amazon.
Сокращение поверхности атак
Минимизация поверхности атак имеет два преимущества: повышение скорости обслуживания и снижение вероятности нарушения безопасности. Используя многоступенчатую сборку, можно создавать облегченные образы с небольшой поверхностью атаки и улучшенным временем загрузки и производительностью. Для этого существует несколько решений. Если вы работаете в Linux, то можете использовать Alpine Linux, BusyBox или Tiny Core Linux. Для Ubuntu существует Ubuntu Minimal. Можно также использовать Scratch, специальный образ Docker – по сути, открытый контейнер, для создания минималистичных образов с самого начала.
Ограничение привилегий контейнера
Принцип, используемый здесь, заключается в предоставлении минимальных прав для выполнения той или иной задачи. Когда контейнеры запускаются от имени root, они предоставляют пользователю различные привилегии, такие как установка пакетов или право на чтение и запись операционной системы. Риск заключается в том, что при компрометации злоумышленники могут использовать эскалацию прав на время выполнения контейнера. В связи с этим существует два возможных решения. Можно запускать контейнеры в режиме rootless или ограничить возможности ядра LINUX только теми, которые необходимы для работы контейнеров.
Безопасное управление секретами

Конфигурационные файлы контейнера и docker не должны содержать секретов. К таким секретам относятся сертификаты, пароли, ключи интерфейса прикладных программ (API) и токены. И хотя это лучшая практика, часто можно увидеть, что эти секреты жестко закодированы в процессе сборки или в образах исходного кода. В таких случаях конфиденциальные данные попадают в контейнеры и кэшируются на промежуточных уровнях контейнеров даже после их удаления. В таких случаях для хранения и управления секретными учетными данными лучше всего развернуть решение для управления секретами, например AWS Secrets Manager и Vault.
Расширение возможностей вашей команды

Обучение сотрудников передовым методам обеспечения безопасности, как последняя мера защиты, имеет решающее значение. Это означает, что все члены команды смогут определять угрозы безопасности и реагировать на них. Хорошим способом решения этой задачи является включение вопросов безопасности контейнеров в процесс обучения команды. Практическое обучение, непрерывное обучение и регулярные оценки безопасности позволяют команде DevOps выделяться на фоне других, поскольку они владеют современными тенденциями в области безопасности.
Заключительные размышления
Обеспечение безопасности контейнеров – важнейший непрерывный процесс жизненного цикла разработки ПО. Наилучшим подходом к решению этой задачи является обеспечение безопасности на всех этапах – от кода приложения до среды выполнения контейнера, операционной системы хоста и базовой сетевой инфраструктуры. Реализовать это можно, следуя стратегическому плану, предусматривающему проверку контейнеров и использование только контейнеров из надежных источников. Усилить защиту контейнеров, чтобы обеспечить наличие в них только необходимых сервисов. Внедрить методы протоколирования, которые легко реализуются с помощью средств мониторинга.
Сегментируйте сеть таким образом, чтобы контейнеры были отделены от общей инфраструктуры. Всегда подписывайте свои образы, чтобы подтвердить правильность ввода и вывода данных через службы. Кроме того, необходимо регулярно проводить сканирование и тесты на проникновение для выявления уязвимостей и незамедлительного принятия мер по их устранению. По мере развития технологического ландшафта всегда следите за новейшими методами обеспечения безопасности.