ADG Оставить заявку
Блог Информационная безопасность 5 мин чтения

Vault 1.8 и ротация паролей БД: убираем сервисные учётки из конфигов под аудит ЦБ

HashiCorp Vault 1.8 расширяет database secrets engine: MongoDB Atlas, Redis, улучшенная ротация. Разбираем как внедрили автоматическую выдачу TTL-учёток для клиента под аудитом ЦБ.

Контекст момента

HashiCorp Vault 1.8 расширяет database secrets engine: добавляет поддержку MongoDB Atlas и Redis, улучшает управление ротацией статических учётных записей

HashiCorp выпустил Vault 1.8, и в этом релизе нас интересует прежде всего database secrets engine: поддержка MongoDB Atlas, Redis, и переработанное управление ротацией статических учётных записей. Совпало с тем, что мы как раз заканчиваем внедрение Vault для клиента из финансового сектора - там предстоит аудит ЦБ, и один из предметных вопросов аудитора звучит примерно так: «покажите, где хранятся пароли к базам данных». До Vault ответ был неудобным.

Откуда задача

У клиента - несколько десятков микросервисов, каждый со своим подключением к PostgreSQL. Исторически учётные данные жили в конфигах: либо в переменных окружения в docker-compose, либо в секретах Kubernetes, созданных один раз руками и никогда больше не менявшихся. Формально секреты в k8s - это уже лучше чем .env в репозитории, но по сути пароль к базе живёт годами, ротируется «когда вспомнят» (то есть никогда), и доступен всем, кто может читать секреты в неймспейсе.

Аудитор ЦБ смотрит на это просто: сервисная учётка с паролем, который не менялся два года - это нарушение политики управления доступом. Неважно, что пароль «длинный и сложный».

Задача: убрать долгоживущие пароли из конфигов, ввести автоматическую ротацию, обеспечить аудитный след.

Что делает Vault с базами данных

Database secrets engine в Vault работает в двух режимах.

Динамические учётки - Vault сам создаёт пользователя в БД при каждом запросе, выдаёт логин/пароль с заданным TTL, и по истечении TTL удаляет пользователя. Сервис при старте запрашивает учётку, работает с ней, при рестарте запрашивает новую. Пароль никогда не живёт дольше TTL - это может быть час, 24 часа, что угодно.

Статические учётки с ротацией - существующий пользователь в БД остаётся, но Vault берёт на себя периодическую смену его пароля. Сервис всегда берёт актуальный пароль из Vault, а не хранит его у себя. Удобно для случаев где нельзя менять имя пользователя (приложение захардкодено, legacy, и так далее).

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

Что изменилось в 1.8

До 1.8 ротация статических учёток работала, но с ограничениями: нельзя было вручную инициировать немедленную ротацию без CLI-команды, и мониторинг состояния ротации был довольно скудным. В 1.8 добавили явный API для ручной ротации (/rotate-root и /rotate), и улучшили отображение в UI - теперь видно когда последний раз менялся пароль и когда следующая ротация.

MongoDB Atlas и Redis как новые бэкенды нам пока не нужны - у клиента PostgreSQL - но факт появления Redis интересен: Redis часто используется как кеш с авторизацией, и это типичное место где пароль вписывают в конфиг и забывают.

Как выглядит схема у нас

Vault развёрнут на трёх нодах с HA через Consul. Приложения в Kubernetes получают Vault Agent Injector - sidecar-контейнер, который при старте пода запрашивает секрет из Vault и кладёт его в файл или переменную окружения. Само приложение ничего не знает про Vault - оно просто читает DATABASE_URL из файла.

pod startup
  -> vault-agent init container
  -> authenticate via k8s service account token
  -> request dynamic DB credentials (TTL: 12h)
  -> write to /vault/secrets/db-config
  -> main container reads /vault/secrets/db-config

Vault Agent также обновляет учётку до истечения TTL - этот механизм называется lease renewal. Если renewal не проходит (Vault недоступен), агент может подать сигнал приложению или просто ждать - настраивается через template и exec директиву.

Что пришлось решать

PostgreSQL и CREATE ROLE. Для динамических учёток Vault нужно право создавать пользователей в БД. Мы создаём отдельного пользователя для Vault с ограниченными правами: только CREATEROLE и право выдавать гранты в нужных схемах. Шаблон создания учётки выглядит как SQL-запрос в конфиге Vault, где он создаёт роль с нужными привилегиями и ставит expiry.

Приложения, которые кешируют соединение. Часть сервисов держит connection pool на весь срок жизни процесса. Когда TTL учётки истекает, соединения в пуле разрываются. Нужно либо перезапускать соединения по событию от Vault Agent, либо ставить TTL достаточно длинным (24 часа) и полагаться на перезапуск пода при деплое. Мы выбрали второй путь для большинства сервисов - ежедневный деплой и так происходит.

Аудитный лог. Vault умеет писать полный аудит всех запросов: кто запросил секрет, когда, с каким результатом. Включили file audit backend с ротацией логов и настроили отправку в ElasticStack. Теперь на вопрос аудитора «кто и когда имел доступ к учётке сервиса X» есть конкретный ответ с таймстампами.

Где сейчас

Vault работает в проде около двух месяцев. Динамические учётки выданы для большинства сервисов, оставшиеся три на статических ротируемых учётках - ротация каждые 24 часа, последняя ротация видна в UI.

Один раз Vault Agent не смог получить обновление учётки из-за временного сетевого сбоя между неймспейсами в k8s. Приложение продолжило работу на старой учётке (она ещё не истекла), после восстановления соединения агент получил свежую. Ситуация прошла без инцидента, но подсветила важное: мониторить нужно не только доступность Vault, но и успешность renewals на стороне агента.

По итогам: конфигов с паролями не осталось, аудитный след есть, ротация работает без ручного вмешательства. Для клиента это переход от «пароль живёт вечно и лежит в git-истории» к «пароль живёт сутки и нигде не хранится дольше TTL». Для managed-сопровождения Vault стал частью стандартной инфраструктурной обвязки для проектов, где к доступу есть вопросы - будь то внутренние политики или внешний аудит.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.