Ротация секретов без простоя: четыре фазы вместо одного вечера
Короткий ответ: ротацию откладывают не потому, что она сложная, а потому, что
классический сценарий «поменять пароль и разнести по сервисам» гарантированно
рвёт работающие соединения. Выход — разрезать замену на четыре фазы
create → set → test → finish, где потребители до последнего момента читают
старое значение, а новое становится текущим только после успешной проверки.
В env-master этот автомат встроен: значение сохраняется durable до того, как
начинает применяться, а неудачная проверка поднимает событие, вебхук и метрику
вместо тихого простоя.
Почему ротацию откладывают до инцидента
Спросите команду, когда она в последний раз меняла пароль от базы, и чаще всего услышите «при увольнении того админа». Причина рациональна: ротация вручную — это окно, в котором часть инстансов уже читает новое значение, а часть ещё старое, и одно из двух обязано не работать. Риск известный и немедленный, а выгода — отложенная и абстрактная. Поэтому секреты живут годами, пока утечка не сделает ротацию аварийной.
Вывод из этого не «дисциплинировать людей», а убрать окно. Если новое значение становится текущим атомарно и только после проверки, ротация перестаёт быть событием — и её можно делать по расписанию, а не по поводу.
Четыре фазы
Автомат ротации в env-master одинаков для любого целевого секрета:
- create — получить новое значение: у встроенного ротатора PostgreSQL это сгенерированный пароль, базу фаза не трогает вовсе;
- set — применить его там, где оно должно действовать;
- test — убедиться, что оно работает;
- finish — перенести метку
current, чтобы потребители начали читать новое.
Прогон всегда идёт с начала: возобновления с фазы нет, и сбой посередине не
оставляет систему в неопределённом состоянии — следующий прогон просто
начинается заново. Порядок фаз выбран так, что «заново» ничего не ломает:
пароль генерируется без участия базы, а метка current переносится последней.
Подробности и ограничения — в документации по ротации.
Почему test нельзя пропустить
Ротация без проверки нового значения хуже её отсутствия: вы получаете
уверенность вместо работающего доступа. Пароль создан, записан, разошёлся по
сервисам — и не подходит: ошиблись в грантах, в имени базы, в хосте. Поэтому
фаза обязательна, и только после неё finish переносит метку current.
Неудачный прогон не замаливается: событие rotation.failed, вебхук
администраторам и метрика.
Метка pending: durable раньше, чем применяется
Между create и finish новое значение уже лежит в хранилище под меткой
pending. Это не деталь реализации. Если процесс упадёт после создания пароля
в базе, но до записи в хранилище, пароль будет потерян — а он уже действует,
и восстановить его неоткуда. Значение становится durable до того, как начинает
применяться. Потребители в это время по-прежнему читают current и ничего не
замечают.
Откат идёт вперёд
Откат — одно действие: прежнее значение публикуется новой версией. Указатели не переставляются назад, история остаётся монотонной, и по ней видно, что откат вообще был — событие, которое при расследовании важнее самого факта смены значения. Повторный откат тоже идёт вперёд, а не качает значение туда-обратно. Модель версий и меток описана в модели данных.
Что готово из коробки
Сейчас есть ротатор PostgreSQL с двумя стратегиями: сменить пароль одному пользователю или чередовать двух. Уже открытые соединения не рвутся ни в одной из них — PostgreSQL проверяет пароль при подключении, а не на каждом запросе. Каркас движка не завязан на конкретную СУБД: добавить ротатор для своей системы значит реализовать четыре метода — по одному на фазу.
Ротация — одна из тех вещей, которые не урезаны в бесплатном плане: как и шифрование с аудитом, она работает с первой минуты на любом тарифе.