Ошибки, 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Отключение аудита