#!/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"