foundation/bootstrap/vault-unseal.sh

35 lines
1.8 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
# Passphrase-gated Vault unseal helper (ADR-004). After a VM reboot foundation-vault
# re-seals; this reads the unseal keys from the passphrase-encrypted Pulumi config
# and unseals over SSH via docker exec (ADR-007). No external KMS, no SaaS — reboots
# require the master passphrase to be available (the ratified Layer-0 trade-off).
#
# `pulumi up` unseals as part of a deploy (the foundation-vault-init command); this
# helper is the break-glass for a reboot WITHOUT a deploy.
set -euo pipefail
DIR="$(cd "$(dirname "$0")" && pwd)"
export PULUMI_BACKEND_URL="file://${DIR}/state"
export PULUMI_CONFIG_PASSPHRASE="$(pass olsitec-foundation/PULUMI_CONFIG_PASSPHRASE)"
cd "$DIR"
pulumi stack select foundation >/dev/null
KEYS_JSON=$(pulumi config get vaultCredentials:unsealKeys 2>/dev/null || true)
[ -n "$KEYS_JSON" ] || { echo "no vaultCredentials:unsealKeys in config — is Vault initialized?" >&2; exit 1; }
HOST=$(pulumi config get foundation:vm.host)
PORT=$(pulumi config get foundation:vm.sshPort 2>/dev/null || echo 22)
SSHUSER=$(pulumi config get foundation:vm.user)
KEY="${SSH_PRIVATE_KEY_PATH:-${HOME}/.ssh/foundation-test_ed25519}"
# Keys travel over the SSH stdin pipe, NEVER on the command line. The remote shell
# unseals foundation-vault with each one via docker exec.
printf '%s' "$KEYS_JSON" | jq -r '.[]' | \
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i "$KEY" -p "$PORT" "$SSHUSER@$HOST" '
n=0
while IFS= read -r k; do
docker exec -e VAULT_ADDR=http://127.0.0.1:8200 foundation-vault vault operator unseal "$k" >/dev/null && n=$((n+1))
done
echo "applied $n unseal key(s)"
docker exec -e VAULT_ADDR=http://127.0.0.1:8200 foundation-vault vault status -format=json | jq -r "\"sealed: \" + (.sealed|tostring)"
'
echo "vault-unseal.sh: done"