diff --git a/infrastructure/vps-standby/vault/manifests/restore-cronjob.yaml b/infrastructure/vps-standby/vault/manifests/restore-cronjob.yaml index 872a664..cca4e91 100644 --- a/infrastructure/vps-standby/vault/manifests/restore-cronjob.yaml +++ b/infrastructure/vps-standby/vault/manifests/restore-cronjob.yaml @@ -71,11 +71,25 @@ data: # the chart's default "vault-0". VAULT_POD="vps-vault-0" UNSEAL_KEY="$(kubectl -n vault get secret vault-unseal-key -o jsonpath='{.data.key}' | base64 -d)" + # Home's real root token - after the first successful restore, this + # Vault's auth data is byte-for-byte home's (as of that snapshot), so + # home's root token is valid here too. Needed to authenticate + # `raft snapshot restore`, which is a privileged operation - unseal + # alone isn't enough. Stored the same way as the unseal key (kubectl, + # not git): + # kubectl -n vault create secret generic vault-root-token \ + # --from-literal=token= + HOME_ROOT_TOKEN="$(kubectl -n vault get secret vault-root-token -o jsonpath='{.data.token}' | base64 -d)" + RESTORE_TOKEN="" vault_exec() { kubectl -n vault exec -i "$VAULT_POD" -- env VAULT_ADDR=http://127.0.0.1:8200 vault "$@" } + vault_exec_auth() { + kubectl -n vault exec -i "$VAULT_POD" -- env VAULT_ADDR=http://127.0.0.1:8200 VAULT_TOKEN="$RESTORE_TOKEN" vault "$@" + } + echo "==> Checking Vault status..." STATUS_JSON="$(vault_exec status -format=json 2>&1 || true)" INITIALIZED="$(echo "$STATUS_JSON" | jq -r '.initialized // empty' 2>/dev/null || echo "")" @@ -85,14 +99,20 @@ data: echo "==> First run: initializing with a throwaway single-key seal..." INIT_JSON="$(vault_exec operator init -key-shares=1 -key-threshold=1 -format=json)" THROWAWAY_KEY="$(echo "$INIT_JSON" | jq -r '.unseal_keys_b64[0]')" + RESTORE_TOKEN="$(echo "$INIT_JSON" | jq -r '.root_token')" echo "==> Unsealing with throwaway key for first restore..." vault_exec operator unseal "$THROWAWAY_KEY" >/dev/null unset THROWAWAY_KEY INIT_JSON - elif [ "$SEALED" = "true" ]; then - echo "==> Sealed - unsealing with the stored home unseal key..." - vault_exec operator unseal "$UNSEAL_KEY" >/dev/null else - echo "==> Already unsealed." + # Already restored at least once before - home's root token is valid + # here regardless of seal state, since it's restored FROM home. + RESTORE_TOKEN="$HOME_ROOT_TOKEN" + if [ "$SEALED" = "true" ]; then + echo "==> Sealed - unsealing with the stored home unseal key..." + vault_exec operator unseal "$UNSEAL_KEY" >/dev/null + else + echo "==> Already unsealed." + fi fi echo "==> Installing mc (MinIO client)..." @@ -117,8 +137,7 @@ data: kubectl -n vault cp "/tmp/${LATEST}" "${VAULT_POD}:/tmp/${LATEST}" echo "==> Restoring raft snapshot (this replaces all data + the keyring)..." - kubectl -n vault exec -i "$VAULT_POD" -- env VAULT_ADDR=http://127.0.0.1:8200 \ - vault operator raft snapshot restore -force "/tmp/${LATEST}" + vault_exec_auth operator raft snapshot restore -force "/tmp/${LATEST}" kubectl -n vault exec "$VAULT_POD" -- rm -f "/tmp/${LATEST}" echo "==> Restarting Vault to fully reload post-restore state..."