Ошибки, best practices и пример

Сводим всё воедино: чего нельзя делать, что делать правильно и как выглядит реальный поток получения кредов БД.

Vault безопасен ровно настолько, насколько грамотно настроен. Большинство инцидентов — не дыры в Vault, а ошибки эксплуатации.

Типичные ошибки

ОшибкаЧем грозит
root token в проде / в скриптахвсемогущий долгоживущий доступ, катастрофа при утечке
нет ротации (статика годами)старые скомпрометированные креды работают вечно
широкие политики (secret/*)один токен вскрывает всё хранилище
нет аудитаслепота при инциденте
unseal-ключи рядом с Vaultкража диска раскрывает всё
HTTP без TLSсекреты по сети открыто
хардкод токена в образеsecret zero расползается с артефактом

Best practices

  • Отзовите initial root token после настройки; генерируйте root только разово при необходимости.
  • Least privilege в политиках — узко, по приложению/роли/среде, разделяя чтение и запись.
  • Динамика вместо статики там, где можно (БД, облако) — авто-ротация и короткое окно.
  • Короткие TTL у токенов и аренд; полагайтесь на renew, а не на вечные креды.
  • Включите аудит (минимум два устройства) и защитите сами логи.
  • TLS, авто-unseal, HA, снапшоты Raft — продакшн-гигиена.
  • response wrapping для доставки SecretID и других чувствительных bootstrap-данных.

Сквозной пример: приложение берёт креды БД динамически

Соберём всё в один поток. Цель: сервис orders в Kubernetes получает временные креды PostgreSQL без единого статического пароля.

1. Настройка движка и роли (один раз, админом):

vault secrets enable database
vault write database/config/orders-db \
  plugin_name=postgresql-database-plugin \
  allowed_roles="orders-ro" \
  connection_url="postgresql://{{username}}:{{password}}@db.internal:5432/orders" \
  username="vault_admin" password="admin-pass"

vault write database/roles/orders-ro \
  db_name=orders-db \
  creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
  default_ttl=1h max_ttl=8h

2. Политика по least privilege:

path "database/creds/orders-ro" {
  capabilities = ["read"]
}
vault policy write orders-ro orders-ro.hcl

3. Kubernetes auth для пода:

vault write auth/kubernetes/role/orders \
  bound_service_account_names=orders-sa \
  bound_service_account_namespaces=prod \
  token_policies=orders-ro ttl=1h

4. Под с инъекцией секретов:

metadata:
  annotations:
    vault.hashicorp.com/agent-inject: "true"
    vault.hashicorp.com/role: "orders"
    vault.hashicorp.com/agent-inject-secret-db: "database/creds/orders-ro"
spec:
  serviceAccountName: orders-sa

5. Что происходит в рантайме:

под стартует
  --> init Agent логинится (k8s auth, SA orders-sa)
  --> Vault проверяет SA через TokenReview, выдаёт токен (orders-ro)
  --> Agent читает database/creds/orders-ro
  --> Vault CREATE ROLE в Postgres, отдаёт временные креды + lease(1h)
  --> Agent пишет /vault/secrets/db, приложение читает файл и коннектится
  --> sidecar Agent продлевает аренду; у потолка max_ttl берёт новые
  --> под удалён --> токен/аренда отозваны --> Vault DROP ROLE

Итог потока: ни одного статического пароля БД нигде — ни в образе, ни в манифесте, ни в etcd. Креды живут час, уникальны на под, отзываются вместе с подом, и каждое обращение записано в audit-лог.

Частые ошибки в этом потоке

  • Дать роли orders-ro лишние гранты в SQL — временный юзер станет опасным.
  • Широкая политика вместо одного пути creds — нарушение least privilege.
  • Не ограничить namespace/SA в роли — чужой под получит креды.

Итог

  • Большинство проблем — ошибки эксплуатации: root token, статика без ротации, широкие политики, отсутствие аудита.
  • Best practices: least privilege, динамика, короткие TTL, аудит, TLS/HA/авто-unseal, response wrapping.
  • Сквозной пример показывает рантайм без единого статического пароля: уникальные часовые креды БД на под с авто-отзывом.
Проверьте себя
1. Почему root token в проде — серьёзная ошибка?
AОн медленный
BЭто всемогущий долгоживущий доступ; его утечка — катастрофа
CОн не работает с KV
DОн требует TLS
2. Какое свойство сквозного примера ключевое с точки зрения безопасности?
AПриложение знает Vault API
BНигде нет статического пароля БД: креды уникальны на под, живут час и отзываются с подом
CИспользуется один общий пароль
DСекреты хранятся в etcd
3. Какая практика напрямую ограничивает радиус поражения при утечке токена?
AДлинные TTL
BУзкие политики по least privilege на конкретные пути
CХранение unseal-ключей рядом с Vault
DОтключение аудита