Files
hermes 05d44d2e51
Flate / Flate (pull_request) Blocked by required conditions
Flate / Flate - Success (pull_request) Blocked by required conditions
Flate / Flate - Filter (pull_request) Successful in 5s
fix(vault): kubectl без -i и с < /dev/null — exec съедал stdin цикла
2026-09-17 17:45:33 +00:00

105 lines
4.7 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
set no-exit-message
set quiet
set shell := ['bash', '-euo', 'pipefail', '-c']
set script-interpreter := ['bash', '-euo', 'pipefail']
set default-list
set default-script
# Unseal-ключами Vault владеем вручную: файл вне git (см. .gitignore), по одному
# ключу на строку, строки, начинающиеся с '#', игнорируются.
#
# Почему не sops: age-ключ sops лежит в самом кластере (секрет sops-age), поэтому
# любой sops-файл из этого репозитория расшифрует тот, у кого есть доступ к
# кластеру, и смысл ручного unseal (PVC без ключей бесполезен) пропадёт.
# Копии ключей держи в менеджере паролей и на бумаге: они показываются один раз
# при `vault operator init`.
#
# kubectl зовём БЕЗ -i и всегда с < /dev/null: exec с -i подключает stdin
# контейнера к нашему stdin, а это stdin файла ключей в цикле ниже — после первого
# ключа цикл получал EOF и распечатывал Vault одной долей.
keys_file := env('VAULT_UNSEAL_KEYS', clean(justfile_directory() + '/vault-unseal-keys'))
vault_namespace := env('VAULT_NAMESPACE', 'security')
vault_pod := env('VAULT_POD', 'vault-0')
# Показать состояние Vault.
[doc('Показать состояние Vault (sealed/unsealed и прогресс распечатывания)')]
[group('vault')]
status:
#!/usr/bin/env bash
set -uo pipefail
for cmd in kubectl jq; do
command -v "$cmd" > /dev/null || { echo "vault: не найден $cmd (активируй mise в каталоге репозитория)" >&2; exit 1; }
done
kubectl -n "{{ vault_namespace }}" exec "{{ vault_pod }}" -- vault status < /dev/null || true
# Распечатать Vault ключами из файла.
[doc('Распечатать Vault ключами из файла vault-unseal-keys')]
[group('vault')]
unseal:
#!/usr/bin/env bash
set -euo pipefail
keys_file="{{ keys_file }}"
ns="{{ vault_namespace }}"
pod="{{ vault_pod }}"
for cmd in kubectl jq; do
command -v "$cmd" > /dev/null || { echo "vault: не найден $cmd (активируй mise в каталоге репозитория)" >&2; exit 1; }
done
if ! kubectl -n "$ns" get pod "$pod" > /dev/null 2>&1 < /dev/null; then
echo "vault: под $ns/$pod недоступен — Vault не запущен или kubeconfig не тот" >&2
exit 1
fi
if [[ ! -f "$keys_file" ]]; then
echo "vault: нет файла с unseal-ключами: $keys_file" >&2
echo "" >&2
echo "Создай его в корне репозитория (в git он не попадёт, см. .gitignore)" >&2
echo "и положи по одному ключу на строку, например:" >&2
echo "" >&2
echo " <ключ 1 из vault operator init>" >&2
echo " <ключ 2 из vault operator init>" >&2
echo " <ключ 3 из vault operator init>" >&2
echo "" >&2
echo "Vault инициализируется с 5 долями и порогом 3, ключи показываются один раз." >&2
exit 1
fi
if find "$keys_file" -perm /077 -print -quit | grep -q .; then
echo "vault: у файла ключей слишком широкие права — сделай chmod 600 $keys_file" >&2
fi
sealed() {
kubectl -n "$ns" exec "$pod" -- vault status -format=json < /dev/null 2> /dev/null | jq -r '.sealed | tostring' || true
}
if [[ "$(sealed)" == "false" ]]; then
echo "vault: уже распечатан, ничего не делаю"
exit 0
fi
used=0
while IFS= read -r key || [[ -n "$key" ]]; do
key="$(printf '%s' "$key" | tr -d '[:space:]')"
[[ -z "$key" || "$key" == \#* ]] && continue
used=$((used + 1))
echo "vault: отправляю долю $used"
kubectl -n "$ns" exec "$pod" -- vault operator unseal "$key" < /dev/null || true
if [[ "$(sealed)" == "false" ]]; then
echo "vault: распечатан, использовано долей: $used"
break
fi
done < "$keys_file"
if [[ "$(sealed)" != "false" ]]; then
echo "vault: всё ещё запечатан — проверь, что в файле есть порог (3) верных долей" >&2
exit 1
fi
kubectl -n "$ns" exec "$pod" -- vault status < /dev/null || true