«Vault сам себя запечатывает» — нет, он просто никогда не распечатывается
Под Vault днями висел в Ready 0/1, пока кворум raft тихо держался на двух пирах. Никто его не запечатывал: Shamir без auto-unseal оставляет запечатанным каждый рестарт.
В Optimacros в self-managed кластере Kubernetes работает HashiCorp Vault — HA-кластер raft из трёх узлов. Однажды утром один под Vault показывал Ready 0/1, и так было уже давно. vault status говорил Sealed: true, Unseal Progress: 0/3. Мне это описали так: «Vault сам себя запечатывает».
Почему никто не заметил
Raft нужно большинство. При трёх пирах хватает двух, поэтому секреты продолжали выдаваться и все приложения, читающие из Vault, работали. В этом и опасность: «запечатан, но кворум держится» — тихое состояние, от которого до аварии один рестарт. Если перезапустится второй пир, кластер потеряет кворум, и каждое чтение секрета упадёт.
Никто его не запечатывал
Фраза «сам запечатывает» подразумевает активный процесс — баг, политику, ошибку конфигурации, которая снова запечатывает Vault. Ничего такого не было.
Тип seal был Shamir без auto-unseal. С Shamir Vault стартует запечатанным после каждого перезапуска процесса и ждёт, пока человек введёт пороговое число долей ключа. Никто его не запечатывает заново: каждый рестарт просто оставляет его запечатанным, и ничто его не возвращает.
Подсказка была в самом поде: restartCount=0 и довольно солидный возраст. Он запечатался один раз — при (пере)создании — и его просто так и не распечатали. За этим стояли рестарты из-за нестабильной ноды: каждый раз, когда под Vault оказывался на ней и нода моргала, под возвращался запечатанным.
Распечатываем
Listener внутри кластера работал без TLS, а VAULT_ADDR был задан в поде, так что CLI работал напрямую через kubectl exec — обходной путь через HTTP API не понадобился:
kubectl -n <ns> exec <vault-pod> -- vault operator unseal # три раза, три разные доли
kubectl -n <ns> exec <vault-pod> -- vault status | grep -iE 'Sealed|HA Mode|Raft Applied'
После третьей доли узел распечатался, вернулся в raft через retry-join и догнал applied index лидера.
Настоящее решение
Ручное распечатывание восстанавливает работу, но ничего не чинит. Настоящее решение — auto-unseal (transit или облачный KMS) в Helm values Vault, чтобы перезапущенный под распечатывался сам. Вскоре после этого мы перешли на transit auto-unseal. А до того — держать поды Vault подальше от нестабильных нод и убедиться, что алерт VaultSealed действительно срабатывает.
Про ключи
Доли unseal никогда не попадают в чаты, тикеты, логи и коммиты. Если они засветились, vault operator rekey обязателен, и выполнять его должен человек в защищённом терминале: rekey печатает новые доли, и пропустить их через тот же скомпрометированный канал — значит обнулить смысл. И помните, что доли, переданные аргументами команды, на мгновение видны в списке процессов; на общих машинах безопаснее stdin.
Выводы
- «Сам запечатывается» обычно значит «так и не распечатали». Проверьте
restartCountи возраст пода, прежде чем искать механизм запечатывания. - Shamir без auto-unseal превращает каждое моргание ноды в ручную работу и скрытую потерю резерва.
- «Запечатан, но кворум держится» невидимо для пользователей и обязано быть видимым для мониторинга.
- Решение — auto-unseal; ключи распечатывания — это break-glass, а не рабочая процедура.