Секреты для CI в GitLab: переменные, а не репозиторий

0
5
Обложка статьи: Секреты для CI в GitLab: переменные, а не репозиторий

Токен деплоя, пароль базы и ключ реестра образов не живут в .gitlab-ci.yml и не ездят в чате. Положите их в переменные проекта GitLab, включите маскирование и ограничьте защищёнными ветками. Если секрет уже в истории репозитория — сначала отзыв и поиск: секреты в git. Здесь только как хранить, чтобы туда больше не попадал.

Статья опирается на логику направления «Безопасность данных» из методики зрелости Группы Сбер (источник); это методика для крупных компаний, мы используем её как ориентир и пересказываем своими словами. Официальные переменные GitLab: docs.gitlab.com/ci/variables. Практика OWASP — не держать секреты в коде: Secrets Management Cheat Sheet. Это не российский закон.

Куда класть

Нужна роль Maintainer проекта (для группы — Owner). Settings → CI/CD → Variables → Add variable:

Поле Для секрета
Key Имя вроде DB_PASSWORD, без пробелов
Value Само значение; в статью его не копируйте
Type Variable для пароля; File для закрытого ключа (в job это путь к файлу)
Protect variable Включите, если секрет только для защищённых веток и тегов (продуктив)
Visibility Masked, не Visible. Если в вашей версии GitLab есть Masked and hidden — лучше оно: значение потом не открыть в UI
Environment scope Для продакшена — конкретная среда, не *, если среды разведены

В .gitlab-ci.yml в блоке variables: оставляйте только несекретное: имена образов, флаги, URL без пароля. Документация прямо говорит: чувствительные значения — в UI, не в YAML. Риск: merge request из форка, запущенный в родительском проекте, получает переменные родителя. Не гоняйте такие pipeline к продуктивным секретам; форкам оставляйте только тестовый контур.

Как использовать в job

Подставляйте имя переменной, не печатайте значение. Включите маскирование: GitLab прячет точное совпадение в журнале, но куски и set -x его показывают. Перед работой с секретом отключите трассировку:

deploy:
  stage: deploy
  script:
    - set +x
    - test -n "$DB_PASSWORD"
    - echo "password is set, length suppressed"
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
  environment: production

Не пишите echo "$DB_PASSWORD", не передавайте секрет в curl через query string, не кладите его в артефакты job. Проверка «переменная задана» — непустой test -n, без вывода значения. Закрытый ключ типа File читайте как файл: chmod 600 "$SSH_KEY_FILE", не копируйте содержимое в переменную окружения повторно.

Токены SonarQube и Dependency-Track в том же UI, с Masked и Protected — как в статье про GitLab CI. Перед выкладкой команда ещё раз смотрит, что секретов нет в образе: чек-лист релиза, Trivy.

Кто видит и когда менять

Кто может читать и менять переменные проекта — Maintainer. Не раздавайте эту роль всем разработчикам «чтобы самим крутить CI». Заявку на доступ к продуктовому проекту оформляйте как доступ к системе: заявка на доступ. При увольнении или смене подрядчика ротируйте токены, которые этот человек мог увидеть в UI или в незамаскированном журнале — удаление учётки GitLab само пароль базы не меняет.

Отдельный секрет на среду: тестовый пароль не равен боевому. Иначе утечка стенда открывает продуктив. Боевые ПДн на стенде — другая ошибка: тестовые данные.

Vault, облачный менеджер секретов и динамические пароли на каждый job — следующий уровень. Пока его нет, GitLab Variables с Protect и Mask — гигиена. Не держите второй «настоящий» список секретов в таблице Confluence.

Диагностика

Симптом Причина и что делать
Job на feature-ветке не видит DB_PASSWORD Включён Protect, ветка не protected. Либо снимите Protect для тестового секрета, либо не требуйте боевой пароль на feature
В журнале виден пароль кусками Маска ловит только полное совпадение. Уберите set -x и echo
Секрет в YAML «на время отладки» Он уже в git. Отзовите, перенесите в UI, дальше — статья про секреты в истории
Все разработчики — Maintainer Любой может прочитать Visible и часть Masked в настройках. Сузьте роли

Где это в модели зрелости

Материал относится к направлению «Безопасность данных» (хаб: данные, карта: карта зрелости). Для SSDLC это гигиена конвейера: секрет не в репозитории и не в журнале job. Процесс находок сканера — рядом: SAST и SCA как процесс. Это не менеджер паролей сотрудников и не DLP.

Как проверить

  1. В репозитории нет файлов .env с значениями; в YAML нет паролей и токенов.
  2. Боевые переменные: Masked (или hidden) и Protected, среда не *, если среды разделены.
  3. В журнале последнего деплоя нет значения секрета; set -x перед работой с ним выключен.
  4. Список Maintainer проекта короткий и совпадает с теми, кому можно видеть продуктивные секреты.
  5. После ухода человека, который был Maintainer, токены деплоя и пароль, который он мог знать, сменены.

Источники

Комментарии закрыты.