Все уроки
БезопасностьСредний10 мин чтенияПолезно знать

Управление секретами и Vault

Держите пароли, ключи и токены вне кода — и делайте их короткоживущими, проверяемыми и легко ротируемыми.

  • Vault
  • Secret managers
  • Rotation
  • Least privilege
Шаг 1/5
Разработчик вписывает пароль от базы прямо в .env и пушит его в публичный репозиторий. Что может пойти не так?

За 30 секунд

Секреты — это пароли, API-ключи, сертификаты и токены, которые нужны вашему ПО, чтобы общаться с другими системами. Управление секретами — это хранить их в одном защищённом месте, давать каждому приложению только то, что ему нужно, логировать каждый доступ и регулярно их менять. Инструменты вроде HashiCorp Vault, OpenBao и облачных secret manager умеют даже выдавать короткоживущие учётные данные по запросу, так что красть почти нечего.

Не в моём ежедневном стеке — я понимаю принципы и изучу детали, когда это понадобится проекту.

Почему это важно

  • Утёкшие учётные данные — одна из самых частых отправных точек взломов, а секреты, закоммиченные в Git или вставленные в чат, годами остаются доступными для поиска.
  • Централизованные секреты дают одно место, где можно ответить на вопрос «кто может прочитать пароль от продакшен-базы и кто это делал?» — разбросанные .env-файлы на это не ответят.
  • Ротация становится рутиной, а не пугающим ручным проектом, — а это важно, когда уходит сотрудник или взламывают подрядчика.
  • Secret manager нужен команде, как только у неё появляется несколько окружений, сервисов или людей с доступом к продакшену; одиночное приложение на одном сервере может начать с хорошо защищённых env-файлов.

Как это работает

01Что считается секретом и почему .env-файлов недостаточно

Секрет — всё, что даёт доступ: пароли от баз, API-ключи платёжных и почтовых провайдеров, OAuth client secrets, ключи подписи JWT, приватные ключи TLS, SSH-ключи, ключи шифрования и секреты подписи вебхуков. Подход Twelve-Factor — хранить конфигурацию в переменных окружения — был большим шагом вперёд по сравнению с хардкодом, и .env-файлы на сервере по-прежнему разумное начало. Но по мере роста системы появляются проблемы: копии одного и того же .env на ноутбуках, в CI и на серверах; нет записи о том, кто что читал; нет простой ротации; секреты видны в списках процессов, crash dump или страницах ошибок; и вечный риск закоммитить файл. Управление секретами решает это, относясь к секретам как к данным с владельцем, политикой доступа, аудит-логом и жизненным циклом.

  • Никогда в Git, Docker-образах, клиентских бандлах или логах
  • У каждого секрета есть владелец, scope и план ротации
  • Доступ выдаётся по идентичности и записывается

02Как работает secret manager

Представьте банковское хранилище с охранником и журналом. Secret manager хранит секреты зашифрованными at rest, обычно под ключом, защищённым облачным KMS или аппаратным модулем безопасности (HSM). Приложения аутентифицируются по идентичности — облачной IAM-роли, Kubernetes service account, OIDC-токену CI-задачи или AppRole, — а не по общему паролю. Политики сопоставляют идентичности с путями, которые им можно читать: сервис orders может читать secret/prod/orders/* и ничего больше. Каждое чтение и запись попадают в аудит-лог. Основные варианты: HashiCorp Vault (с 2023 года source-available под лицензией BSL, теперь часть IBM), OpenBao (open-source форк Vault под эгидой Linux Foundation), облачные сервисы вроде AWS Secrets Manager, Google Secret Manager и Azure Key Vault, а также платформы для разработчиков вроде Doppler, Infisical или 1Password Secrets Automation.

03Основы Vault: KV-секреты и политики

Vault организует всё по путям. Secrets engine key/value (KV) хранит статические секреты с версионированием, так что можно откатиться. Политики на HCL выдают на пути capabilities вроде read, create, update или list. Приложения входят через auth method, соответствующий месту, где они работают, — kubernetes, aws, jwt/oidc для CI или approle — и получают короткоживущий Vault-токен, ограниченный политикой. Режим разработки (vault server -dev) — только для обучения: он работает в памяти, unsealed, с root-токеном. Продакшену нужны хранилище (обычно выбирают integrated Raft storage), TLS, auto-unseal через облачный KMS или HSM, включённые audit devices и отозванный после настройки root-токен. Те же команды работают с CLI bao от OpenBao.

bash
# Store and read a versioned secret (KV v2)
vault kv put secret/prod/orders db_password='use-a-generated-value'
vault kv get -field=db_password secret/prod/orders
 
# orders-policy.hcl — read-only access to one app's secrets
path "secret/data/prod/orders/*" {
  capabilities = ["read"]
}
 
vault policy write orders orders-policy.hcl
vault audit enable file file_path=/var/log/vault_audit.log

04Динамические секреты: учётные данные, которые истекают сами

Самая сильная идея Vault — динамические секреты. Вместо одного долгоживущего пароля от базы, общего для всех инстансов, Vault по запросу создаёт уникального пользователя базы для каждого инстанса приложения с lease — скажем, на час. Когда lease истекает или отзывается, Vault удаляет этого пользователя. Утёкшие учётные данные быстро становятся бесполезными, каждое подключение можно отнести к конкретному инстансу, а отзыв доступа у скомпрометированного сервиса — одна команда. Тот же паттерн есть для облачных учётных данных (временные ключи AWS), PKI (короткоживущие TLS-сертификаты) и SSH (подписанные сертификаты вместо authorized keys). Облачные провайдеры предлагают похожие идеи нативно: IAM-роли для нагрузок и IAM-аутентификация в базе вообще избавляют от хранимых паролей. Приложения должны обрабатывать продление, и это за вас делают клиентские библиотеки и агенты вроде Vault Agent.

bash
# One-time setup by an admin
vault secrets enable database
vault write database/config/app-db plugin_name=postgresql-database-plugin \
  connection_url="postgresql://{{username}}:{{password}}@db.internal:5432/app" \
  allowed_roles="orders-ro" username="vault_admin" password="initial-admin-pass"
vault write -force database/rotate-root/app-db   # Vault now owns the admin password
 
vault write database/roles/orders-ro db_name=app-db default_ttl=1h max_ttl=24h \
  creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";"
 
# Each app instance asks for its own short-lived user
vault read database/creds/orders-ro

05Как доставлять секреты в приложения

Есть три распространённых паттерна доставки. Прямой API: приложение через SDK читает секреты при старте и продлевает lease — гибко, но связывает код с хранилищем. Sidecar или агент: Vault Agent (или облачный аналог) аутентифицируется, получает секреты и рендерит их в файл или окружение для приложения, автоматически продлевая; приложение просто читает файл. Синхронизация платформой: в Kubernetes External Secrets Operator или Secrets Store CSI driver синхронизируют секреты из secret manager в поды. В CI/CD вообще не храните долгоживущие облачные ключи: GitHub Actions, GitLab и другие могут выпускать OIDC-токен на каждую задачу, который облако или Vault обменивает на короткоживущие учётные данные. Для Docker Compose на VPS простой и надёжный паттерн — env-файлы, принадлежащие root, с правами 600 вне репозитория, или Docker secrets, смонтированные как файлы.

yaml
# GitHub Actions: no stored cloud keys — exchange the job's OIDC token
permissions:
  id-token: write
  contents: read
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/deploy-prod
          aws-region: eu-central-1
      - run: aws secretsmanager get-secret-value --secret-id prod/orders --query SecretString --output text > /dev/null

06Ротация, минимальные привилегии и реакция на утечку

Ротация — это замена секрета новым по расписанию и после любого подозрения на утечку. Чтобы ротировать без простоя, поддерживайте две действующие версии одновременно: создайте новые учётные данные, задеплойте их, убедитесь, что старые никто не использует, затем отзовите старые. Облачные secret manager умеют автоматизировать ротацию для баз; для сторонних API-ключей ротация обычно оформляется как скриптовый runbook. Минимальные привилегии означают, что каждый сервис, человек и пайплайн получают только нужные им секреты, в нужном окружении и в идеале только на чтение. Профилактика: запускайте сканеры секретов вроде gitleaks или TruffleHog в pre-commit-хуках и CI и включите push protection на вашем Git-хостинге. Когда секрет утёк, важен порядок: сначала отзовите или ротируйте его, потом удаляйте из истории, потому что переписывание истории Git не «отменяет утечку» ключа, который уже склонировали или собрали ботами.

  • Ротация: создать новый → задеплоить → проверить → отозвать старый
  • Сканирование: pre-commit + CI + push protection
  • Утечка: сначала отзыв, затем чистка истории, затем разбор логов доступа

Когда применять

  • Несколько сервисов или окружений с общими учётными данными, где копии .env-файлов расползаются.
  • Требования compliance или клиентов к аудит-логам, ревью доступа и ротации (SOC 2, ISO 27001, PCI DSS).
  • Системы, которым полезны короткоживущие учётные данные: базы данных, облачный доступ, внутренние TLS-сертификаты.
  • Команды, где люди приходят и уходят, поэтому доступ нужно быстро выдавать и забирать для каждого человека.

Когда не стоит

  • Небольшое приложение на одном сервере, которое ведёт один человек: защищённых env-файлов, сканера секретов и хороших бэкапов пока может хватить.
  • Self-hosted Vault без ресурсов на его эксплуатацию — запечатанный, непропатченный или без бэкапов Vault становится единой точкой отказа; управляемый облачный secret manager безопаснее.
  • Несекретная конфигурация вроде feature flags или URL — ей место в обычном конфиге.

Альтернативы

  • Облачные secret manager

    AWS Secrets Manager, Google Secret Manager, Azure Key Vault: управляемые, интегрированы с IAM, с хуками для ротации; привязаны к одному облаку.

  • OpenBao

    Open-source форк Vault с совместимым API для команд, которым нужны возможности Vault под open-source лицензией.

  • SOPS + age/KMS

    Шифрует значения секретов внутри файлов, которые коммитятся в Git; простой GitOps-процесс, но без динамических секретов и аудита каждого чтения.

  • Платформы секретов для разработчиков

    Doppler, Infisical, 1Password: простая синхронизация в приложения и CI с хорошим UX, но меньше продвинутых динамических возможностей.

Лучшие практики

  1. Аутентифицируйте нагрузки по идентичности платформы (IAM-роли, Kubernetes service accounts, CI OIDC), а не по хранимым мастер-паролям.
  2. Где целевая система это поддерживает, предпочитайте короткоживущие или динамические учётные данные долгоживущим статическим секретам.
  3. Пишите узкие политики для каждого сервиса и окружения; продакшен-секреты никогда не читаются из development.
  4. Включите аудит-логирование и алерты на необычный доступ — например, когда человек читает учётные данные продакшен-базы.
  5. Автоматизируйте ротацию и репетируйте её, включая перекрытие двух версий для изменений без простоя.
  6. Запускайте сканирование секретов в pre-commit, CI и через push protection в Git.
  7. Не допускайте секретов в логах, на страницах ошибок, в слоях Docker-образов и во фронтенд-бандлах.

Частые ошибки

  • Закоммитить .env-файлы или ключи, а потом «исправить» это удалением файла без отзыва секрета.
  • Зашивать секреты в Docker-образы через ENV или COPY, откуда их может прочитать любой, у кого есть образ.
  • Одни общие админские учётные данные для всех сервисов, из-за чего ни один доступ нельзя отозвать независимо.
  • Запускать Vault в dev-режиме или использовать root-токен в повседневной работе.
  • Никогда ничего не ротировать, потому что никто не знает, какие системы используют ключ.

Глубже

07Архитектура Vault: seal, хранилище и высокая доступность

Модель безопасности Vault держится на барьере: всё, что уходит из Vault в хранилище, зашифровано keyring, защищённым root-ключом. Sealed означает, что Vault не держит ключей в памяти. При Shamir unseal root-ключ разбивается на доли (например, пять, из которых нужны три), которые хранят разные люди; при auto-unseal облачный KMS или HSM расшифровывает его автоматически при старте — это норма в продакшене, потому что перезапуски не должны требовать людей посреди ночи. Integrated storage (Raft) реплицирует данные обычно на три или пять узлов; один — лидер, остальные — standby, которые пересылают запросы, а для записи нужен кворум. Делайте бэкапы через Raft snapshots и тестируйте восстановление. Редакции Enterprise и HCP добавляют performance- и disaster-recovery-репликацию между регионами. С точки зрения эксплуатации Vault — инфраструктура tier-zero: если он лежит, приложения не могут стартовать, поэтому продумайте кэширование, разумные сроки lease и мониторинг статуса seal, смены лидера и числа lease.

hcl
# Production-style server config (excerpt)
storage "raft" {
  path    = "/opt/vault/data"
  node_id = "vault-1"
}
listener "tcp" {
  address       = "0.0.0.0:8200"
  tls_cert_file = "/etc/vault/tls/vault.crt"
  tls_key_file  = "/etc/vault/tls/vault.key"
}
seal "awskms" {
  region     = "eu-central-1"
  kms_key_id = "alias/vault-unseal"
}
api_addr     = "https://vault-1.internal:8200"
cluster_addr = "https://vault-1.internal:8201"

08Secret zero: как доверять первым учётным данным

Любая система секретов сталкивается с проблемой «secret zero»: чтобы получить секреты, приложение сначала должно аутентифицироваться — а каким секретом для этого пользоваться? Современный ответ — опираться на идентичность, которую уже подтверждает платформа. В AWS роль инстанса или задачи подписывает запрос, который Vault или Secrets Manager могут проверить. В Kubernetes projected service-account token пода проверяется кластером. В CI OIDC-токен задачи подписан CI-провайдером. На голых VPS такой идентичности платформы нет, поэтому варианты — AppRole с role id, зашитым в конфигурацию, и secret id, который инструмент деплоя доставляет один раз с коротким TTL и однократным использованием, или клиентский TLS-сертификат, выданный при провиженинге. Что бы вы ни выбрали, привязывайте идентичность к узким политикам и коротким токенам и делайте bootstrap-учётные данные бесполезными после первого использования.

09Шифрование как сервис и envelope encryption

Помимо хранения секретов, transit engine в Vault и облачные KMS шифруют данные для приложений, никогда не раскрывая ключ. Приложение отправляет plaintext, получает ciphertext и хранит его в своей базе; расшифровка требует вызова, проверяемого политикой. Ключи можно ротировать, при этом старые шифротексты остаются расшифровываемыми и их можно перешифровать под новую версию. Для больших данных используйте envelope encryption: сгенерируйте случайный data key, локально зашифруйте им данные (например, AES-256-GCM), затем зашифруйте data key ключом KMS и храните рядом с данными. Вы получаете быстрое локальное шифрование, централизованный аудит и возможность отрезать доступ, отключив один мастер-ключ. На этом паттерне построены шифрование персональных данных на уровне полей, зашифрованные бэкапы и секреты в GitOps-инструментах вроде SOPS.

bash
# Transit: the app never sees the key
vault secrets enable transit
vault write -f transit/keys/customer-pii
 
vault write transit/encrypt/customer-pii plaintext=$(printf '%s' 'AM12345678' | base64)
# -> ciphertext: vault:v1:8SDd3WHDOjf7mq69CyCqYjBXAiQQAVZRkFM13ok481zoCmHnSeDX9vyf7w==
 
vault write transit/decrypt/customer-pii ciphertext='vault:v1:8SDd3WHDOjf7...'
vault write -f transit/keys/customer-pii/rotate   # new version, old data still readable

10Секреты в Kubernetes: чем не является base64

Kubernetes Secret закодирован в base64, а не зашифрован; любой, кто может читать Secrets в namespace или читать бэкапы etcd, видит значения. Укрепляйте защиту слоями. Включите шифрование etcd at rest, в идеале через KMS-провайдера. Ограничьте RBAC так, чтобы get или list для Secrets могли делать только нуждающиеся в них нагрузки и немногие операторы, — «list» на Secrets фактически раскрывает их все. Не коммитьте манифесты Secret в Git; используйте External Secrets Operator для синхронизации из центрального хранилища или Sealed Secrets либо SOPS для GitOps, где значения зашифрованы в репозитории. Предпочитайте монтировать секреты как файлы, а не переменные окружения, — так значения можно ротировать без перезапуска и они реже попадают в crash dump. Наконец, используйте workload identity, чтобы поды могли вызывать облачные API и secret manager вообще без статических ключей в Secrets.

Реальные ситуации

01

Перевод растущей команды с общих .env-файлов

Проблема

Пятеро разработчиков пересылают друг другу продакшен-.env-файлы в чате. Три сервиса работают на двух VPS с Docker Compose, и никто не знает, какие API-ключи ещё используются.

Как решить

Начните с инвентаризации: перечислите каждый секрет, его владельца, где он используется и когда последний раз ротировался. Для такого масштаба выберите управляемый secret manager или платформу секретов для разработчиков, а не self-hosted Vault. Создайте отдельные проекты для каждого окружения, дайте разработчикам доступ только к development, а продакшен ограничьте пайплайнами деплоя и одним-двумя мейнтейнерами. Доставляйте секреты на серверы при деплое как файлы, принадлежащие root, с правами 600. Ротируйте каждый продакшен-секрет во время миграции, ведь старые жили в чате. Добавьте gitleaks в pre-commit и CI.

02

Пароль от базы нужно сменить без простоя

Проблема

Безопасность требует ротировать пароль продакшен-базы раз в квартал. В прошлый раз это вызвало 20-минутный простой, потому что сервисы перезапускались в разное время.

Как решить

Перейдите на ротацию с двумя пользователями. Создайте двух пользователей базы с одинаковыми правами. Сервисы читают текущие имя пользователя и пароль из secret manager. Для ротации задайте новый пароль неактивному пользователю, обновите секрет, чтобы он указывал на него, и постепенно перекатите сервисы; подключения подхватывают новые учётные данные при переподключении. Убедившись, что старого пользователя не использует ни одна сессия (проверьте pg_stat_activity), заблокируйте его или смените ему пароль. Автоматизируйте шаги функцией ротации облачного провайдера или перейдите на динамические учётные данные Vault, чтобы каждый инстанс получал собственного короткоживущего пользователя.

03

API-ключ оказался в публичном репозитории

Проблема

Сканер секретов сообщает, что боевой API-ключ платёжного провайдера десять минут назад запушен в публичный репозиторий в тестовом скрипте.

Как решить

Действуйте в таком порядке. Немедленно отзовите или перевыпустите ключ в дашборде провайдера и задеплойте замену из secret manager. Проверьте логи провайдера на любые вызовы со старым ключом с момента пуша. Удалите файл и вычистите его из истории через git filter-repo, затем сделайте force-push; при необходимости свяжитесь с Git-хостингом, чтобы очистить кэши. Напишите короткий отчёт об инциденте: хронология, последствия, исправление. Предотвратите повторение: включите push protection, добавьте сканирование в pre-commit и выдайте разработчикам ограниченные ключи test-режима, чтобы боевые ключи никогда не лежали на ноутбуках.

Шпаргалка

Запустить одноразовый dev-сервер (никогда не prod)
vault server -dev
Записать KV-секрет
vault kv put secret/prod/app api_key='generated-value'
Прочитать одно поле
vault kv get -field=api_key secret/prod/app
Получить динамические учётные данные БД
vault read database/creds/orders-ro
Отозвать все lease по пути
vault lease revoke -prefix database/creds/orders-ro
Прочитать из AWS Secrets Manager
aws secretsmanager get-secret-value --secret-id prod/app --query SecretString --output text
Просканировать репозиторий на утёкшие секреты
gitleaks detect --source . --verbose
Зашифровать файл через SOPS + age
sops --encrypt --age age1yourpublickey secrets.yaml > secrets.enc.yaml
Закрыть доступ к env-файлу на сервере
chown root:root /etc/app/.env && chmod 600 /etc/app/.env

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

Q1Почему бы просто не использовать переменные окружения?

Переменные окружения — хороший механизм доставки и намного лучше хардкода, но это не система управления. Они ничего не говорят о том, где хранится значение, кто может его прочитать, кто его менял и как оно ротируется. Копии расползаются по ноутбукам, настройкам CI и серверам. Они могут утечь через инспекцию процессов, crash reports или debug-страницы, выводящие окружение. Secret manager становится источником истины с политиками доступа, аудит-логами и ротацией — и при этом всё равно может доставлять значения в приложение как переменные окружения или файлы.

Q2Что такое динамические секреты?

Динамические секреты — это учётные данные, генерируемые по запросу для конкретного клиента со встроенным сроком действия. Например, когда сервис стартует, Vault создаёт для него уникального пользователя базы, действующего один час, и удаляет его, когда lease истекает или отзывается. Плюсы: нет долгоживущего пароля, который может утечь, каждые учётные данные можно отследить до одного потребителя, а отзыв доступа у скомпрометированного сервиса мгновенный и не затрагивает остальных. Цена — приложение или агент рядом с ним должны продлевать учётные данные и обрабатывать переподключение, а целевая система должна поддерживать программное управление пользователями.

Q3Что делать, если секрет закоммитили в Git?

Считайте его скомпрометированным, даже в приватном репозитории, потому что клоны, форки и логи CI уже могут его содержать. Сначала отзовите или ротируйте секрет у провайдера и задеплойте новое значение. Затем проверьте логи провайдера на предмет злоупотреблений за период утечки. После этого удалите его из истории репозитория через git filter-repo или BFG, сделайте force-push и попросите коллег переклонировать репозиторий — но считайте это уборкой, а не исправлением. Наконец, добавьте сканирование секретов в pre-commit и CI, чтобы это не повторилось.

Q4Как Vault защищает хранимые секреты?

Vault шифрует все данные перед записью в хранилище ключом шифрования, который сам защищён root-ключом. При старте Vault находится в состоянии sealed: он ничего не может расшифровать, пока его не распечатают — либо долями ключа у нескольких операторов (Shamir secret sharing), либо автоматически через облачный KMS или HSM (auto-unseal). Клиенты аутентифицируются и получают токены, ограниченные политиками, а каждый запрос может записываться audit devices, причём чувствительные значения в логе хэшируются. Поэтому чтение одного лишь storage backend не даёт ничего полезного.

Q5Как CI/CD-пайплайнам безопасно получать секреты?

Лучший актуальный паттерн — workload identity federation: CI-система выпускает для каждой задачи короткоживущий OIDC-токен с описанием репозитория, ветки и окружения. Облачный провайдер или Vault доверяет этому издателю и обменивает токен на временные учётные данные, ограниченные условиями вроде «только ветка main этого репозитория». Долгоживущие облачные ключи в CI вообще не хранятся. Когда статических секретов не избежать, храните их в защищённых секретах окружений CI-системы, ограничьте защищёнными ветками, требуйте одобрения для продакшен-деплоев и маскируйте их в логах.

Q6Как часто нужно ротировать секреты?

Ротируйте немедленно после любого подозрения на утечку или когда уходит человек с доступом; в остальном следуйте расписанию на основе рисков — типичные политики требуют от 30 до 90 дней для ценных статических секретов, а некоторые compliance-фреймворки задают конкретные сроки. Ответ получше — сделать ротацию настолько простой, чтобы частота перестала иметь значение: автоматизируйте её, поддерживайте две действующие версии во время переключения и предпочитайте динамические или короткоживущие учётные данные, которые истекают за часы. Ключи подписи, например ключи JWT, ротируются с перекрытием: опубликуйте новый ключ, начните подписывать им и выведите старый после истечения токенов.

Вопросы уровня senior

S1Self-hosted Vault или облачный secret manager — как решить?

Облачный secret manager — выбор по умолчанию, когда нагрузка в основном живёт в одном облаке: не нужно держать серверы, есть интеграция с IAM, шифрование на базе KMS, хуки ротации и аудит через облачный trail — ценой оплаты за секрет и за вызов и привязки к вендору. Vault (или OpenBao) окупает затраты на эксплуатацию, когда у вас несколько облаков или on-premise, нужны динамические секреты для многих систем, выпуск PKI- и SSH-сертификатов, transit-шифрование или единая модель политик для всех платформ. Эксплуатировать его — значит отвечать за высокую доступность, unseal, обновления, бэкапы и быть tier-zero во время инцидентов; HCP Vault снимает большую часть этого за деньги. Небольшим командам на VPS обычно прагматичнее взять управляемую платформу секретов для разработчиков или облачный менеджер плюс дисциплину в правах на файлы.

S2Как бы вы спроектировали работу с секретами в multi-tenant SaaS, который хранит сторонние учётные данные клиентов?

Учётные данные клиентов — ключи их платёжных шлюзов или пароли от ERP — это другой класс, чем секреты вашей собственной инфраструктуры. Я бы хранил их зашифрованными по тенантам через envelope encryption: data key для каждого тенанта, обёрнутый ключом KMS или Vault transit, шифротекст — в базе приложения, а расшифровка — только в сервисе, который вызывает третью сторону. Доступ проверяется по тенанту при каждой расшифровке и логируется. Plaintext никогда не попадает в логи, админки или инструменты поддержки; на экранах видны только последние символы. Поддержите ротацию самим клиентом и немедленное удаление при отключении через уничтожение data key тенанта (crypto-shredding). Компромиссы: вызовы KMS добавляют задержку и стоимость, поэтому ненадолго кэшируйте расшифрованные ключи в памяти, а ключи на каждого тенанта увеличивают накладные расходы на управление ключами, но резко сокращают радиус поражения.

S3Как ротировать ключи подписи для JWT или вебхуков, не ломая клиентов?

Используйте перекрывающиеся ключи с идентификатором key id. Для JWT сначала опубликуйте новый публичный ключ в JWKS рядом со старым, дождитесь обновления кэшей у проверяющих, затем начните подписывать новым ключом с его kid. Держите старый публичный ключ опубликованным, пока не истекут все подписанные им токены, затем удалите его. Приватные ключи живут в KMS, HSM или Vault transit, чтобы никогда не покидать защищённое хранилище. Для секретов подписи вебхуков поддерживайте во время ротации два активных секрета на эндпоинт: подписывайте новым, указывайте версию в заголовке подписи и позвольте получателям принимать любой из двух в течение заданного окна. Компромисс — сложность распространения ключей и кэширования, но это гораздо дешевле одномоментной ротации, которая инвалидирует все сессии или теряет вебхуки партнёров.

Глоссарий

Secret (секрет)
Любое значение, дающее доступ: пароль, API-ключ, токен, ключ сертификата или ключ шифрования.
Secret manager
Сервис, который хранит секреты зашифрованными, контролирует доступ по идентичности и логирует каждое использование.
Dynamic secret
Учётные данные, создаваемые по запросу для одного клиента с автоматическим истечением срока.
Lease
Ограничение по времени в Vault для секрета или токена, после которого он отзывается, если его не продлили.
Seal / unseal
Запертое состояние Vault, в котором он не может расшифровывать данные, и процесс загрузки его ключей.
Rotation (ротация)
Замена секрета новым значением и вывод старого из обращения — по расписанию или после утечки.
Secret zero
Первые учётные данные, которые нужны приложению, чтобы аутентифицироваться в самом secret manager.
Envelope encryption
Шифрование данных ключом данных, а затем шифрование этого ключа мастер-ключом из KMS.
Workload identity
Подтверждение идентичности приложения через его платформу (облачная роль, под, CI-задача) вместо хранимых ключей.

Есть идея продукта?Давайте создадим его.

Расскажите о своей идее, продукте или команде. Обычно отвечаю в течение одного рабочего дня.