Секреты и окружения: dev, staging, prod

↑ Этап 3 · CI-CD

Обязательно~5 мин чтенияУровень: middle

Зачем это на собесе

Утечка секретов — самая частая причина инцидентов. Спрашивают, где хранить, как передавать и как разделять окружения.

Окружения

ОкружениеДанныеДоступ
devсинтетические/обезличенныеразработчики
stagingприближено к проду (структура, объём), без реальных ПДнкоманда, QA
prodреальныеограниченный круг, аудит

Принципы: изоляция (отдельные кластеры/аккаунты/БД/ключи на окружение), паритет конфигурации (одинаковые образы и шаблоны, отличаются значения), неизменяемые артефакты, наименьшие привилегии (у dev нет доступа к prod-секретам), защита прод-деплоя (ручное подтверждение, protected branches/tags).

Конфигурация и секреты

  • конфигурация (URL, флаги, размеры пулов) — не секрет: переменные окружения, ConfigMap, файлы в Git (per-environment values);
  • секреты (пароли, токены, ключи, сертификаты, строки подключения) — хранятся отдельно, шифруются, ротируются, доступ аудируется;
  • 12-factor: конфигурация через окружение, код не содержит значений окружений.

Где НЕ хранить секреты

Git (даже в приватном репозитории и «удалив» позже — история), образы Docker (ENV, ARG, слои), логи, артефакты пайплайна, аргументы командной строки (видны в ps), чат/вики, .env в репозитории.

Варианты хранения и доставки

ПодходОписаниеОсобенности
CI/CD variables (GitLab/GitHub Secrets)Masked, Protected, scope по окружениюпросто; ограничено по ротации и аудиту
HashiCorp Vaultдинамические секреты, политики, аудит, TTLмощно; требует эксплуатации
Облачные менеджеры (AWS Secrets Manager, Yandex Lockbox, Azure Key Vault, GCP Secret Manager)IAM-доступ, ротация, версииудобно в облаке
Kubernetes Secretsbase64 (не шифрование!)включить шифрование etcd, RBAC; External Secrets Operator / CSI driver синхронизируют из внешних хранилищ
Sealed Secrets / SOPS (age, KMS)зашифрованные секреты в Git (GitOps)расшифровка в кластере/пайплайне
Ansible Vaultзашифрованные файлы переменныхдля конфигурации серверов
OIDC / Workload Identityвременные токены вместо паролейлучший вариант для доступа к облаку из CI

Секреты в пайплайне

deploy-staging:
  stage: deploy
  environment: staging                      # переменные с scope=staging доступны только здесь
  id_tokens:
    VAULT_ID_TOKEN: { aud: https://vault.example.com }
  script:
    - export VAULT_TOKEN=$(vault write -field=token auth/jwt/login role=deploy-staging jwt=$VAULT_ID_TOKEN)
    - DB_PASSWORD=$(vault kv get -field=password secret/clinic/staging/db)
    - ./deploy.sh staging
  • Masked — скрывает значение в логах; Protected — только для защищённых веток/тегов; переменные типа File для сертификатов и ключей;
  • отдельные значения для каждого окружения (scope);
  • не выводить env, set -x, не передавать секреты как аргументы;
  • OIDC вместо статических облачных ключей;
  • токены с минимальными правами и сроком жизни; у CI — CI_JOB_TOKEN.

Секреты в рантайме

  • файлы секретов (/run/secrets/db_password, *_FILE переменные) безопаснее, чем ENV (видны в docker inspect, /proc/<pid>/environ, дампах);
  • Kubernetes: смонтированный Secret (volume) или envFrom; обновляется без пересборки; перезапуск подов по хэшу (checksum/secret в Helm) или Reloader;
  • Vault Agent / CSI: подгрузка секретов с обновлением;
  • приложение читает секрет при старте/обновлении и не логирует.

Разделение по окружениям

deploy/
  values.yaml              # общие
  values-dev.yaml          # отличия dev
  values-staging.yaml
  values-prod.yaml
  • в Git — структура и несекретные значения; ссылки на секреты (existingSecret: clinic-db) или зашифрованные значения (SOPS);
  • одинаковые имена переменных во всех окружениях;
  • различия документированы; проверка дрейфа;
  • разные учётные записи/ключи для каждого окружения (компрометация dev не затрагивает prod);
  • данные: не копировать прод в dev без обезличивания (маскирование ПДн).

Ротация и утечки

  • ротация по расписанию и при увольнении/инциденте; динамические секреты (Vault database engine) с TTL;
  • сканирование репозиториев и истории (gitleaks, trufflehog, GitHub/GitLab Secret Detection) в pre-commit и CI;
  • при утечке: считать скомпрометированным → отозвать и заменить → аудит использования → очистка истории вторична;
  • политики: запрет пушей секретов (push rules), защита от коммитов .env;
  • мониторинг обращения к секретам, алерты на аномалии.

Практика .NET

builder.Configuration
  .AddJsonFile("appsettings.json")
  .AddJsonFile($"appsettings.{env}.json", optional: true)
  .AddEnvironmentVariables()                      // переопределение: ConnectionStrings__Default
  .AddKeyPerFile("/run/secrets", optional: true); // файлы-секреты
// User Secrets — только для локальной разработки (dotnet user-secrets)

Вопросы с ответами