Блог BearPass

Секреты в DevOps и CI/CD: как не хранить пароли в коде

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

Секрет, попавший в репозиторий (repository), живёт там вечно — даже если вы его удалили. По данным исследований, после появления секрета в публичном коде до первой попытки его использовать проходит меньше 15 минут. Боты сканируют GitHub и GitLab непрерывно.
Но проблема глубже, чем «не коммить пароли». В реальной DevOps-среде секреты нужны везде: скриптам деплоя (deploy scripts), конвейерам сборки (build pipelines), сервисам мониторинга, миграциям баз данных, инструментам инфраструктуры. Вопрос не в том, нужны ли секреты в автоматизации — нужны. Вопрос в том, как ими управлять правильно.

Что такое секрет и почему это не только «пароль»

В контексте инфраструктуры и разработки секрет (secret) — это любые чувствительные данные, которые нельзя хранить в открытом виде:
  • пароли к базам данных и сервисам
  • ключи программного интерфейса (API keys)
  • токены доступа (access tokens) — к реестрам Docker, облачным провайдерам, внешним сервисам
  • ключи шифрования (encryption keys)
  • сертификаты (certificates) и закрытые ключи (private keys)
  • SSH-ключи для доступа к серверам
  • строки подключения (connection strings) к базам данных
Всё это — одна категория риска. И все они встречаются в типичном конвейере непрерывной интеграции и доставки (CI/CD pipeline).

Типичные антипаттерны: как секреты попадают туда, куда не должны

Прежде чем говорить о правильных подходах — стоит честно перечислить то, что происходит в большинстве команд.
Захардкоженные секреты в коде (hardcoded secrets). Классика жанра: DB_PASSWORD = "super_secret_123" прямо в файле конфигурации или скрипте. Попадает в репозиторий, расходится по форкам, оседает в истории коммитов навсегда.
Секреты в переменных среды (environment variables) без управления. Лучше, чем в коде — но только если эти переменные не утекают в логи сборки, не копируются между окружениями (environments) вручную и не хранятся в .env-файлах, которые случайно коммитятся.
Общие токены на всю команду. Один API-ключ на всех разработчиков и все сервисы. Если утёк — непонятно, чей. Отозвать — значит сломать всё сразу.
Секреты в артефактах сборки (build artifacts). Docker-образ, собранный с паролем внутри через ENV или ARG, хранит его в слоях образа — даже если финальный слой его «удаляет».
Ротация раз в никогда. Секрет создали при запуске проекта три года назад. С тех пор он не менялся, знают его пятеро уволившихся сотрудников и два подрядчика.

Правильная модель: централизованное хранилище секретов

Основной принцип — секреты не живут там, где их используют. Они хранятся в одном месте, доступ к ним — программный, строго по необходимости, с журналированием каждого обращения.
Это называется управлением секретами (secrets management), и правильно выстроенный процесс выглядит так:
  1. Секрет создаётся и хранится в централизованном хранилище с контролем доступа.
  2. Конвейер или скрипт при запуске запрашивает секрет через программный интерфейс (API) — с авторизацией.
  3. Секрет передаётся в переменную среды или файл конфигурации на время выполнения.
  4. Секрет не сохраняется в артефактах, логах и промежуточных файлах.
  5. Каждое обращение фиксируется в журнале (audit log).
Отозвать доступ у уволенного сотрудника или скомпрометированного токена — одно действие, которое применяется немедленно ко всем местам использования.

Как авторизовать конвейер в хранилище секретов: три подхода

Здесь возникает рекурсивная проблема: чтобы получить секрет из хранилища, конвейер должен как-то туда аутентифицироваться. А значит — нужен ещё один секрет?
Есть несколько архитектурных решений.
Статические ключи API (API keys) с ограниченными правами. Наиболее распространённый подход. Создаётся отдельная сервисная учётная запись (service account) с минимально необходимыми правами — только на чтение конкретных папок. Ключ передаётся через переменные среды платформы сборки (GitLab CI Variables, GitHub Secrets). Главное — регулярная ротация и один ключ на одну интеграцию.
JWT от внешних провайдеров по протоколу OIDC (OpenID Connect). Более современный и безопасный подход. Платформа сборки (GitLab, GitHub Actions) сама выпускает короткоживущий токен (JWT, JSON Web Token) для каждого запуска конвейера. Хранилище проверяет токен через механизм публичных ключей (JWKS) — без хранения статических секретов. Токен живёт минуты, а не годы. Именно этот подход реализован в BearPass начиная с версии 2.25.0.
Инъекция секретов через агент (secrets injection agent). Специализированное решение, которое подставляет секреты в переменные среды до старта процесса — секрет вообще не появляется в коде конфигурации конвейера. Используется в комплексных инфраструктурах с HashiCorp Vault.

BearPass в DevOps-процессах: что доступно прямо сейчас

BearPass изначально строился как корпоративный менеджер паролей (password manager) с on-premise размещением. Но набор инструментов для автоматизации там уже достаточно серьёзный.
Программный интерфейс (REST API). Полный доступ к хранилищу через HTTP — получение записей, управление доступами, работа с папками. Подходит для интеграции в скрипты и пайплайны на любом языке.
Интерфейс командной строки (CLI). Консольный инструмент для DevOps-сценариев: получить секрет, подставить в переменную среды, выполнить ротацию. Не требует написания кода на уровне HTTP.
JWT-аутентификация через OIDC (с версии 2.25.0). Конвейер авторизуется временным токеном от системы автоматизации — без хранения долгоживущих ключей. Это закрывает основную уязвимость статических API-ключей.
Ролевая модель (RBAC). Для каждой интеграции создаётся отдельная роль с доступом строго к нужным папкам. Сервисный пользователь конвейера не видит ни одного лишнего секрета.
Журнал всех обращений. Каждый запрос к API фиксируется — кто, когда, к какой записи. При инциденте понятно, какой сервис мог получить какой секрет и когда.
Шифрование на стороне клиента (client-side encryption). Хранилище находится на инфраструктуре компании, данные зашифрованы по принципу нулевого знания (zero-knowledge). Даже при компрометации сервера зашифрованный массив бесполезен без ключа.

Практические правила для DevOps-команды

Независимо от того, какой инструмент используется, несколько правил работают везде.
Один секрет — одна цель. Не используйте один и тот же API-ключ для разных сервисов или окружений. При компрометации — отзыв точечный, без каскадных последствий.
Минимальные привилегии (least privilege). Сервисная учётная запись конвейера видит только то, что ей нужно для конкретной задачи. Доступ к продакшн-базе у сборочного агента — это уже нарушение принципа.
Ротация секретов (secret rotation). Особенно для долгоживущих токенов. В идеале — автоматизированная, с фиксацией в журнале. Хотя бы раз в квартал — вручную.
Никаких секретов в логах сборки. Большинство платформ (GitLab CI, GitHub Actions) маскируют переменные, помеченные как секреты, в выводе конвейера. Убедитесь, что это включено — и что ваши скрипты не выводят значения явно через echo или отладочные режимы.
Разделение окружений (environments). Секреты для разработки (development), тестирования (staging) и эксплуатации (production) — разные сущности с разными правами доступа. Разработчик не должен иметь доступ к продакшн-базе через инструмент разработки.
Сканирование репозитория на утечки секретов (secret scanning). Инструменты вроде GitLeaks или встроенные механизмы GitLab/GitHub проверяют каждый коммит на наличие паттернов, похожих на секреты. Это не замена правильному хранению — но ловит случайные ошибки.

Корпоративный менеджер паролей vs. специализированный secrets manager

Частый вопрос: нужен ли отдельный инструмент вроде HashiCorp Vault, или корпоративный менеджер паролей справится?
Ответ зависит от сложности инфраструктуры.
Для большинства компаний малого и среднего бизнеса, команд до 200 человек, без нескольких сотен микросервисов — корпоративный менеджер паролей с API закрывает 95% сценариев. Хранение статических секретов, доступ из конвейеров, ротация вручную или по расписанию, журналирование обращений — всё это есть.
HashiCorp Vault оправдан, когда нужны динамически генерируемые короткоживущие учётные данные (dynamic secrets), встроенный центр сертификации (PKI engine), шифрование как сервис (Transit engine) или очень большое количество сервисов с независимыми политиками. Это инструмент другого уровня сложности — и другого уровня затрат на администрирование.
Разумный подход для большинства команд: корпоративный менеджер паролей как основное хранилище + API для автоматизации. При росте сложности инфраструктуры можно добавить специализированный инструмент для конкретных задач — не переписывая всё с нуля.

Итог: что нужно сделать прямо сейчас

Если в вашей кодовой базе или конфигурациях конвейеров есть хоть один захардкоженный секрет — это технический долг с прямым влиянием на безопасность.
Минимальный набор шагов:
  • Провести аудит репозиториев и конфигурационных файлов на наличие секретов в открытом виде
  • Перенести все секреты в централизованное хранилище с контролем доступа
  • Выдать конвейерам и сервисам отдельные учётные записи с минимально необходимыми правами
  • Включить журналирование всех обращений к секретам
  • Настроить ротацию хотя бы для критичных учётных данных
BearPass решает это в on-premise-исполнении данные остаются на инфраструктуре компании, API и CLI доступны сразу после установки, JWT-интеграция с внешними провайдерами OIDC закрывает задачу авторизации конвейеров без статических ключей.
Попробовать BearPass бесплатно или изучить документацию по API — если хотите разобраться в деталях интеграции перед тем, как принимать решение.
2026-03-23 18:47 Экспертиза