Ответ
Управление секретами — критически важная часть безопасного CI/CD. В GitLab я использую многоуровневый подход, чтобы токены, ключи и пароли никогда не попадали в исходный код.
1. GitLab CI/CD Variables (основной метод):
Это встроенный и самый простой способ. В настройках проекта (Settings > CI/CD > Variables) создаю переменные:
- Тип
Variable: Для строковых значений (например,DOCKER_REGISTRY_PASSWORD,AWS_ACCESS_KEY_ID).- Обязательно ставлю галочку
Mask variable, чтобы значение скрывалось в логах заданий. - Для секретов, связанных с защищенными ветками (prod), также ставлю
Protect variable. Тогда переменная будет доступна только в пайплайнах, запущенных из этих веток или тегов.
- Обязательно ставлю галочку
- Тип
File: Для целых файлов (например, сертификаты.pem, JSON-ключи сервисного аккаунта). GitLab сохранит содержимое в файл, путь к которому будет доступен через переменную.
Пример использования в .gitlab-ci.yml:
deploy_to_production:
stage: deploy
rules:
- if: $CI_COMMIT_TAG # Запускать только для тегов
script:
# Переменная File type будет доступна как файл
- export GOOGLE_APPLICATION_CREDENTIALS=${SERVICE_ACCOUNT_KEY_JSON}
# Использование обычной masked переменной
- echo "Deploying with user $(echo $DEPLOY_USER | sed 's/@/ at /')" # Маскировка в логах
- kubectl set image deployment/my-app app=my-registry/app:$CI_COMMIT_TAG --token=$K8S_SA_TOKEN
variables:
KUBECONFIG: "$KUBE_CONFIG_FILE" # KUBE_CONFIG_FILE — переменная типа File
2. HashiCorp Vault (для enterprise-среды): Для централизованного хранения секретов многих проектов интегрирую GitLab с Vault.
- Настраиваю аутентификацию JWT: GitLab CI/CD предоставляет
CI_JOB_JWT, который пайплайн может использовать для запроса секретов из Vault.
Пример этапа получения секрета из Vault:
.get_secret_from_vault:
script:
- |
# Аутентификация в Vault и получение секрета
VAULT_TOKEN=$(curl -s --request POST
--data "{"jwt": "$CI_JOB_JWT", "role": "$VAULT_ROLE"}"
$VAULT_ADDR/v1/auth/jwt/login | jq -r .auth.client_token)
DATABASE_PASSWORD=$(curl -s --header "X-Vault-Token: $VAULT_TOKEN"
$VAULT_ADDR/v1/secret/data/myproject/db | jq -r .data.data.password)
# Экспортируем в переменную, но не логируем
export DATABASE_PASSWORD
artifacts:
reports:
dotenv: vault.env # Можно передать секреты между джобами через артефакт типа dotenv
3. External Secrets Operator (для Kubernetes): Если конечная цель — деплой в Kubernetes, то вместо передачи секретов через пайплайн я часто использую паттерн, когда пайплайн ничего о секретах не знает.
- Секреты хранятся в Vault или облачном менеджере (AWS Secrets Manager).
- В кластере Kubernetes установлен External Secrets Operator, который автоматически синхронизирует секреты из внешнего хранилища в Kubernetes Secrets.
- Пайплайн GitLab просто применяет манифесты приложения, которые ссылаются на эти уже созданные Secrets.
4. Критически важные практики безопасности:
- Никогда не использовать
set -x(режим отладки bash) в скриптах, работающих с секретами. - Использовать
rules:ifилиworkflow:rulesдля строгого ограничения этапов, где используются защищенные переменные, только определенными ветками. - Регулярно ротировать секреты (токены, ключи) и использовать автоматические процессы для их обновления в GitLab Variables.