Утечки секретов в пайплайнах CI/CD
и что с ними делать

Секреты регулярно просачиваются в конвейеры CI/CD, так как рабочие процессы требуют от разработчиков учетных данных для сторонних ресурсов, с которыми взаимодействует их конвейер.


Рассказываем что же делать, чтобы этого не случилось – ротация секретов, управление их привилегиями, анализ логов на наличие чувствительной информации и не только.

Хотите автоматически развертывать изменения кода на экземпляр EC2? Предоставьте ключ доступа AWS. Хотите развернуть артефакт в NPM? Предоставьте ключ API NPM.


Вместо хранения открытых секретов в виде обычного текста в Git-репозитории разработчики часто используют встроенные функции платформ CI/CD для внедрения секретов во время выполнения. Например, пользователи CircleCI и Travis CI могут настраивать задачи с заранее установленными переменными среды, содержащими их ключи API и пароли. Пользователи GitHub Action могут добавить объект рабочего процесса "secrets". Некоторые разработчики предпочитают обойти платформу CI/CD и использовать сторонний менеджер секретов, такой как HashiCorp Vault или AWS Secrets Manager.


В отличие от частных репозиториев, конвейеры CI/CD, работающие с проектами с открытым исходным кодом, раскрывают файлы журналов задач CI/CD. Злоумышленники могут легко проанализировать выходные данные журнала и найти раскрытые секреты.


Как секреты могут попасть в файлы журналов?


Использование флага --verbose в команде curl может раскрыть чувствительный заголовок, или скрипт тестирования может выводить все переменные окружения. Существует бесчисленное множество способов, как секреты могут попасть в журналы CI/CD.


В качестве меры защиты некоторые платформы CI/CD пытаются замаскировать внедренные секреты в журналах задач. Кроме того, некоторые платформы активно сканируют все данные журналов на наличие потенциальных утечек, независимо от того, является ли значение результатом переменной окружения или объекта секретов. Например, Travis CI использует сканеры открытых исходных кодов для сравнения строк журнала с общими форматами ключей API, токенов и другой чувствительной информации.

Маскирование секретного значения NPM_TOKEN в журнале задачи CircleCI

На первый взгляд, злоумышленникам не удастся найти утекшие секреты в общедоступных журналах заданий; однако секретная защита CI/CD далека от совершенства. Форматирование вывода и секретов затрудняет усилия по их маскировке в CI/CD; секреты второго порядка остаются незамеченными; и в артефактах может содержаться чувствительная информация.


Результат: распространение личной информации злоумышленниками.

Форматирование вывода и секретов вызывает путаницу

Задачи CI/CD, которые значительно преобразовывают секреты и затем выводят их в файл журнала, могут избежать редактирования. Например, следующая задача CircleCI выводит в эхо внедренную переменную окружения NPM_TOKEN, а затем направляет ее на вход команды rev, которая переворачивает строку.


- run:
      	name: Authenticate with npm
      	command: |
        	echo "TOKEN VALUE: $NPM_TOKEN" | rev
        	npm set "//registry.npmjs.org/:_authToken=$NPM_TOKEN"

После отправки коммита журнал задачи CircleCI раскрывает токен npm (в обратном порядке).

Журнал задачи CircleCI с выставленным наружу токеном учетной записи npm в обратном порядке.

Кроме того, формат хранения секретов может привести к утечкам. Например, GitHub рекомендует избегать группировки секретов в структурированных форматах данных, таких как JSON (как, например, делает GCP при выставлении ключей служебных аккаунтов), так как это затрудняет обнаружение утечек. Платформы CI/CD обычно проверяют точное совпадение строк, поэтому они могут не обнаружить частичную утечку из структурированных данных.


Полные утечки строк также могут запутать средства редактирования платформы. Несмотря на активное сканирование журналов Travis CI на наличие чувствительных утечек, публичные файлы журналов по-прежнему раскрывают секретные данные. Например, в публичном журнале, показанном ниже, действительный персональный токен доступа GitHub виден в открытом виде.

В этом журнале сборки Travis CI произошла утечка токена личного доступа GitHub на этапе «Установка переменных окружения из настроек репозитория».

Travis CI выставил эти значения в журналах инициализации переменных среды, поэтому, скорее всего, разработчики внедрили переменные окружения, но не отметили их как скрытые. Удивительно, но токен GitHub имел множество привилегий:

Терминальный вывод ответа от API GitHub, показывающий, что этот токен имеет различные административные области, а также области доступа к репозиторию, пользователю и рабочему процессу

Кодирование

Кодирование добавляет дополнительную сложность в определении и редактировании секретов в журналах задач CI/CD. Иногда разработчики кодируют секрет или блок JSON в своих переменных окружения в формате base64; раскодированный секрет никоим образом не будет соответствовать исходному значению. Обратное может произойти также, в случаях, например, базовой аутентификации, когда пароль загружается в открытом виде, а затем кодируется для фактической аутентификации. Большинство систем редактирования CI/CD не раскодируют данные при анализе журналов на предмет утечек секретов.


Стоит отметить, что TruffleHog автоматически раскодирует base64, который обнаруживает в процессе поиска секретов.

Секреты второго порядка

Если бы разработчик хотел включить секрет без использования переменной окружения или объекта секретов, как бы он это сделал?


Он бы не стал (или не должен был) размещать чувствительную информацию в публичном файле репозитория. Он мог бы хранить все конфиденциальные данные в зашифрованном файле репозитория и внедрить ключ расшифровки в переменную окружения CI/CD.


Однако платформы CI/CD, которые не редактируют секреты, кроме переменных окружения, не смогут редактировать никакие расшифрованные данные из этого файла. Платформа осведомлена только о ключе расшифровки и будет маскировать только его, так как он находится в переменной окружения. Ниже приведен пример утечки такого секрета второго порядка в журнале задачи CircleCI:

Журнал задачи CircleCI, в котором утекает токен учетной записи npm из зашифрованного файла.

Еще одним вариантом внедрения чувствительных данных является использование стороннего решения для хранения секретов, такого как Vault от Hashicorp. К сожалению, этот метод также может привести к утечкам секретов на платформах, не осведомленных о внешних секретах.


Отдельно стоит отметить, что маркеры обновления OAuth и ключи AWS часто обменивают на временные маркеры доступа и подписанные URL-адреса аутентификации соответственно. Большинство таких учетных данных второго порядка также избегают обнаружения.

Дырявые артефакты

Утечки не ограничиваются только журналами. Часто конвейеры CI/CD создают и загружают артефакты, такие как релизы GitHub или пакеты npm. Типичный рабочий процесс включает тестирование, сборку и публикацию пакета. Что произойдет, если рабочий процесс экспортирует секрет в общедоступный артефакт?


Для наглядности этого примера мы создали простое приложение на Node.js, которое взаимодействует с API ChatGPT для предоставления рекомендации по выбору еды. Приложение использует файл конфигурации, содержащий тип кухни и ключ API OpenAI. Используя эту информацию, приложение предоставляет рекомендацию по еде от ChatGPT:

Терминал с примером вывода инструмента для рекомендации еды.

Для публикации пакета в npm мы указали следующий файл конфигурации CircleCI:


version: 2.1
jobs:
  test_and_publish:
    docker:
      - image: cimg/node:lts
    steps:
      - checkout
      - run:
          name: Install Dependencies
          command: npm install
      - run:
          name: Run tests
          command: |
            echo "{\"chatgpt_api_key\": \"$CHATGPT_API_KEY\", \"cuisine\": \"Italian\"}" > test-config.json
            npm test
      - run:
          name: Authenticate with npm
          command: |
            npm set "//registry.npmjs.org/:_authToken=$NPM_TOKEN"
      - run:
          name: Publish npm package
          command: npm publish

workflows:
  version: 2
  test_and_publish:
    jobs:
      - test_and_publish

Задание (1) создает тестовый файл конфигурации с ключом API и кухней, (2) выполняет тесты, (3) выполняет аутентификацию в npm с помощью токена и (4) публикует пакет.


Эта настройка кажется безопасной до тех пор, пока вы не осознаете, что команда npm publish публикует файл test-config.json. Другими словами, рабочий процесс утекает с ключом API в общедоступный пакет!

Страница пакета npm для «foode-gpt-demo» с файлом тестовой конфигурации и общедоступным токеном API ChatGPT.

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

Как смягчить последствия

В первую очередь определите, какие журналы и задачи выставляют наружу секреты. Не забудьте также просканировать старые журналы!


TruffleHog поддерживает сканирование текущих и предыдущих журналов CircleCI именно с этой целью. Используйте следующую команду:


trufflehog circleci –token=<your CircleCI API token>
Запустив это на тестовом аккаунте, TruffleHog обнаружил умышленно выставленный наружу токен npm в демонстрации выше.
Вывод командной строки при запуске TruffleHog на тестовой учетной записи. Он обнаружил утечку токена учетной записи npm.

TruffleHog также можно запускать на других платформах CI/CD, см. документацию.


Ниже приведены некоторые дополнительные рекомендации по предотвращению утечки секретов в заданиях CI/CD:

  • Размещайте отдельные задачи в отдельных заданиях. Инструменты CI/CD изолируют задания. Это означает, что сохранение секрета в одной задаче не делает его доступным для другой. В примере пакета ChatGPT, если бы мы изолировали шаги тестирования рабочего процесса от общедоступных шагов, ключ API не просочился бы в общедоступный артефакт.
  • Практикуйте хорошую гигиену секретов. Часто меняйте свои секреты, назначайте им минимальные возможные привилегии и ограничивайте их воздействие на разные процессы.
  • Правильно храните секреты. Используйте встроенные средства внедрения переменных окружения / секретов платформы и не объединяйте секреты в структурированные данные. Воспользуйтесь возможностью маскировки внутри платформы в случае утечки.
  • Защитите свои секреты от вывода в журналы. Избегайте использования секретов в отладочных операторах, выполняющем коде, который выводит переменные окружения, или выполнении команд с флагом verbose (подробный вывод).
  • Выберите стандартный рабочий процесс вместо кастомного. GitHub Actions позволяет импортировать рабочие процессы. Аналогично, CircleCI поддерживает "орбы", предварительно созданные шаги, которые могут безопасно обрабатывать секреты. Например, орб Slack для CircleCI позволяет разработчикам взаимодействовать с Slack и безопасно обрабатывать переменную окружения SLACK_ACCESS_TOKEN.
  • Активно сканируйте ваши журналы. Как мы сделали с помощью TruffleHog, важно постоянно искать утечки в журналах задач, несмотря на то, насколько безупречной может быть ваша конфигурация рабочего процесса. Вы никогда не знаете, какие нежелательные эффекты могут возникнуть из-за утечек секретов.

Заключение

Рабочие процессы CI/CD являются неотъемлемой частью современной разработки программного обеспечения. Они позволяют проектам тестировать пулл-реквесты, создавать новые релизы, сканировать на наличие уязвимостей в безопасности и многое другое.


Однако, когда разработчики делают журналы задач и артефакты общедоступными, организация должна отслеживать весь вывод рабочего процесса на предмет утечек секретов. Платформы CI/CD могут помочь залатать утечку через редактирование, но это не всегда достаточно. С неограниченным распространением секретов, неясными форматами, секретами второго порядка и утечками артефактов организации сталкиваются с серьезной угрозой утечки секретов. Следование безопасным практикам хранения секретов и рабочим процессам помогает предотвратить попадание ключей API и токенов учетных записей в неправильные руки.

Получите бесплатную консультацию по DevOps-услугам

Если не уверены в том, что вам нужно, наши менеджеры подскажут и помогут с выбором услуги.

Получить консультацию