docs(ops): vault unseal runbook + auto-unseal migration plan
Triage card для on-call: где взять unseal-keys (1Password placeholder, уточнить с DevOps lead), как запустить script либо ручную процедуру, что проверить после, troubleshooting типовых проблем. Также: §7 — план миграции на auto-unseal (Transit / Yandex KMS) когда определимся с master Vault или KMS-backend.
This commit is contained in:
@@ -0,0 +1,138 @@
|
|||||||
|
# Runbook: Vault unseal (staging / prod)
|
||||||
|
|
||||||
|
**Когда использовать:** Vault на кластере залип в `Sealed=true` после reboot
|
||||||
|
ноды или manual seal. Признаки:
|
||||||
|
- Spring Boot pod'ы (`ordinis-app`, `ordinis-read-api`, `ordinis-projection-writer`)
|
||||||
|
стоят в `Init:0/1`.
|
||||||
|
- В логах `vault-agent-init` контейнера: `Vault is sealed`, error 503 на
|
||||||
|
`auth/kubernetes/login`.
|
||||||
|
- `kubectl exec -n config vault-0 -- vault status` → `Sealed: true`.
|
||||||
|
|
||||||
|
**Auto-unseal сейчас НЕ настроен** (v1 closure backlog: Transit secret engine
|
||||||
|
с master Vault либо Yandex Cloud KMS). До миграции — ручная процедура ниже.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Где взять unseal-ключи
|
||||||
|
|
||||||
|
Ключи Shamir, threshold **3 из 5**. Хранение:
|
||||||
|
|
||||||
|
- **Corporate 1Password** — vault `Ordinis НСИ ЦУОД`:
|
||||||
|
- `vault-staging-unseal-keys` — для cluster.265 (192.168.100.161)
|
||||||
|
- `vault-prod-unseal-keys` — для cluster.142 (192.168.100.142)
|
||||||
|
- **Резерв** (cold storage) — у DevOps lead в KeePass.
|
||||||
|
|
||||||
|
Доступ к 1Password vault — у списка инженеров с on-call. При расширении —
|
||||||
|
добавлять через 1Password admin. Никогда не пересылать ключи в Slack /
|
||||||
|
Telegram / email.
|
||||||
|
|
||||||
|
> ⚠️ **При утере 5 из 5 ключей:** Vault инициализируется заново → ВСЕ
|
||||||
|
> secrets потеряны (postgres passwords, Kafka SASL, Keycloak signing keys
|
||||||
|
> в K8s secrets — отдельно). Plan: получить root token + replay `setup.sh` +
|
||||||
|
> заново положить secrets из 1Password (Postgres backup + Vault: писать
|
||||||
|
> только в зеркало). Делать только с письменным разрешением tech lead.
|
||||||
|
|
||||||
|
## 2. Быстрый unseal (script)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/code/ordinis-infra/k8s/vault
|
||||||
|
|
||||||
|
# staging
|
||||||
|
./unseal.sh staging "<KEY_1>" "<KEY_2>" "<KEY_3>"
|
||||||
|
|
||||||
|
# prod
|
||||||
|
./unseal.sh prod "<KEY_1>" "<KEY_2>" "<KEY_3>"
|
||||||
|
```
|
||||||
|
|
||||||
|
Скрипт делает:
|
||||||
|
|
||||||
|
1. Pull kubeconfig с ноды (если ещё не скачан).
|
||||||
|
2. Проверяет `vault status` — если уже unsealed, выходит.
|
||||||
|
3. Применяет 3 ключа последовательно через `vault operator unseal`.
|
||||||
|
4. Проверяет `Sealed: false`.
|
||||||
|
5. Force-deletes Spring Boot pod'ы — vault-agent-init иначе ждёт backoff
|
||||||
|
до 3+ минут на следующую попытку auth.
|
||||||
|
|
||||||
|
После — `kubectl get pods -n ordinis-{env}` показывает `2/2 Running`
|
||||||
|
через ~2 минуты.
|
||||||
|
|
||||||
|
## 3. Ручной unseal (если script недоступен)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Получить kubeconfig
|
||||||
|
ssh root@192.168.100.161 "cat /etc/kubernetes/admin.conf" > /tmp/kc-161
|
||||||
|
sed -i '' 's|server: https://[^:]*:|server: https://192.168.100.161:|' /tmp/kc-161
|
||||||
|
export KUBECONFIG=/tmp/kc-161
|
||||||
|
|
||||||
|
# 2. Проверить статус
|
||||||
|
kubectl exec -n config vault-0 -- vault status
|
||||||
|
|
||||||
|
# 3. Применить 3 ключа (по одному)
|
||||||
|
kubectl exec -n config vault-0 -- vault operator unseal '<KEY_1>'
|
||||||
|
kubectl exec -n config vault-0 -- vault operator unseal '<KEY_2>'
|
||||||
|
kubectl exec -n config vault-0 -- vault operator unseal '<KEY_3>'
|
||||||
|
|
||||||
|
# 4. Убедиться Sealed: false
|
||||||
|
kubectl exec -n config vault-0 -- vault status
|
||||||
|
|
||||||
|
# 5. Перезапустить Spring Boot pod'ы
|
||||||
|
kubectl delete pod -n ordinis-staging \
|
||||||
|
-l 'app.kubernetes.io/name in (ordinis-app,ordinis-read-api,ordinis-projection-writer)' \
|
||||||
|
--grace-period=0 --force
|
||||||
|
|
||||||
|
# 6. Проверить
|
||||||
|
kubectl get pods -n ordinis-staging
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. Подтверждение что всё работает
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# read-api
|
||||||
|
curl -sk --resolve ordinis.k8s.265.nstart.cloud:443:192.168.100.161 \
|
||||||
|
https://ordinis.k8s.265.nstart.cloud/api/v1/spacecraft/records?lang=ru-RU \
|
||||||
|
| jq 'length'
|
||||||
|
# → должно вернуть число > 0
|
||||||
|
|
||||||
|
# admin
|
||||||
|
curl -sk -o /dev/null -w "%{http_code}\n" \
|
||||||
|
--resolve ordinis.k8s.265.nstart.cloud:443:192.168.100.161 \
|
||||||
|
"https://ordinis.k8s.265.nstart.cloud/api/v1/admin/audit?page=0&size=5"
|
||||||
|
# → 200
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. Эскалация / проблемы
|
||||||
|
|
||||||
|
| Симптом | Что делать |
|
||||||
|
|------------------------------------------------------|--|
|
||||||
|
| `vault status` → `connection refused` | Pod `vault-0` не Running. `kubectl get pods -n config` + `kubectl describe`. |
|
||||||
|
| `unseal` принимает ключ но Sealed остаётся true | Проверить count `Unseal Progress` — может нужен 4-й ключ если threshold увеличили. |
|
||||||
|
| Все 3 ключа отвергает (`invalid key`) | Whitespace / обрезанные символы. Скопировать заново из 1Password (полное поле). |
|
||||||
|
| Pod'ы Spring Boot не поднимаются после unseal | `kubectl logs <pod> -c vault-agent-init` — могут быть policy/role миграции после изменений. |
|
||||||
|
| Consul backend (Vault использует Consul) недоступен | `kubectl get pods -n config consul-server-0` + `kubectl logs`. |
|
||||||
|
|
||||||
|
При 30+ минут downtime → эскалация tech lead → решение о переносе
|
||||||
|
prod-нагрузки на запасной кластер либо публичная коммуникация в SLA-канал.
|
||||||
|
|
||||||
|
## 6. Связанные документы
|
||||||
|
|
||||||
|
- Установка Vault с нуля: `ordinis-infra/k8s/vault/setup.sh`
|
||||||
|
- Архитектура auth: `ordinis-auth/.../{ScopeContext,SecurityConfig}.java`
|
||||||
|
- Список секретов в Vault: `secret/ordinis/cuod/` (postgres, kafka, redis)
|
||||||
|
|
||||||
|
## 7. Переход к auto-unseal (TODO для v1 closure)
|
||||||
|
|
||||||
|
Когда будет master Vault либо Yandex Cloud KMS:
|
||||||
|
|
||||||
|
1. Добавить `seal "transit"` либо `seal "yandexcloudkms"` stanza в vault config
|
||||||
|
ConfigMap (`config/vault-config`).
|
||||||
|
2. Запустить migration:
|
||||||
|
```
|
||||||
|
kubectl exec -n config vault-0 -- vault operator unseal -migrate KEY_1
|
||||||
|
kubectl exec -n config vault-0 -- vault operator unseal -migrate KEY_2
|
||||||
|
kubectl exec -n config vault-0 -- vault operator unseal -migrate KEY_3
|
||||||
|
```
|
||||||
|
3. После миграции существующие Shamir-keys больше не работают — выдаются
|
||||||
|
Recovery Keys (5 шт, тот же threshold 3) для emergency rekey/operator-init
|
||||||
|
операций.
|
||||||
|
4. Обновить этот runbook: основной случай — auto-unseal, ручной unseal
|
||||||
|
только при downtime master Vault / KMS.
|
||||||
Reference in New Issue
Block a user