Add Vault auto-unseal service and 1Password bootstrap script
Add vault-tpm2-unseal.sh/.service to unseal Vault once after boot using the TPM-sealed key, and tpm-bootstrap-1password.sh to (re)seal that key from a 1Password secret reference. Document PCR policy selection, the Vault service, and the host-specific tpm2.env (gitignored, example in README) in README.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Executable
+117
@@ -0,0 +1,117 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Bootstrap the TPM 2.0 seal used by vault-tpm2-unseal.service: reads the
|
||||
# Vault unseal key from 1Password via the op CLI, using the secret
|
||||
# reference configured in the environment file, and seals it with the same
|
||||
# PCR-policy binding as tpm-seal-password.sh.
|
||||
#
|
||||
# This replaces interactive password entry with an op read, but op read
|
||||
# itself still requires an operator present to approve the request (device
|
||||
# biometric unlock or an active `op signin` session) - this script does not
|
||||
# run unattended.
|
||||
#
|
||||
# Requires: tpm2-tools, the 1Password CLI (op), access to /dev/tpmrm0.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
CONFIG="/etc/vault.d/tpm2.env"
|
||||
HANDLE=""
|
||||
PCR_LIST=""
|
||||
FORCE=0
|
||||
|
||||
usage() {
|
||||
cat <<-EOF
|
||||
Usage: $(basename "$0") [-c config] [-H handle] [-l pcr-list] [-f]
|
||||
|
||||
-c config Environment file providing OP_SECRET_REFERENCE and,
|
||||
optionally, TPM_HANDLE/TPM_PCR_LIST (default: ${CONFIG})
|
||||
-H handle Persistent TPM handle to store the sealed password at,
|
||||
overrides TPM_HANDLE from the config file
|
||||
-l pcr-list PCR bank and indices to bind release to, overrides
|
||||
TPM_PCR_LIST from the config file
|
||||
-f Evict an existing object at that handle before sealing
|
||||
EOF
|
||||
}
|
||||
|
||||
while getopts "c:H:l:fh" opt; do
|
||||
case "$opt" in
|
||||
c) CONFIG="$OPTARG" ;;
|
||||
H) HANDLE="$OPTARG" ;;
|
||||
l) PCR_LIST="$OPTARG" ;;
|
||||
f) FORCE=1 ;;
|
||||
h) usage; exit 0 ;;
|
||||
*) usage; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
[ -r "$CONFIG" ] || {
|
||||
echo "Cannot read configuration file: ${CONFIG}" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# shellcheck disable=SC1090
|
||||
source "$CONFIG"
|
||||
|
||||
: "${OP_SECRET_REFERENCE:?OP_SECRET_REFERENCE must be set in ${CONFIG}}"
|
||||
HANDLE="${HANDLE:-${TPM_HANDLE:-0x81010001}}"
|
||||
PCR_LIST="${PCR_LIST:-${TPM_PCR_LIST:-sha256:7}}"
|
||||
|
||||
command -v tpm2_createprimary >/dev/null || {
|
||||
echo "tpm2-tools is required (apt install tpm2-tools)" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
command -v op >/dev/null || {
|
||||
echo "1Password CLI (op) is required" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
if tpm2_readpublic -c "$HANDLE" >/dev/null 2>&1; then
|
||||
if [ "$FORCE" -eq 1 ]; then
|
||||
tpm2_evictcontrol -C o -c "$HANDLE" >/dev/null
|
||||
else
|
||||
echo "A sealed object already exists at ${HANDLE}; rerun with -f to replace it" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
WORKDIR="$(mktemp -d)"
|
||||
trap 'rm -rf "$WORKDIR"' EXIT
|
||||
umask 077
|
||||
|
||||
echo "Reading ${OP_SECRET_REFERENCE} from 1Password; approve the request if prompted." >&2
|
||||
|
||||
PASSWORD="$(op read "$OP_SECRET_REFERENCE")"
|
||||
|
||||
[ -n "$PASSWORD" ] || {
|
||||
echo "op read returned an empty value for ${OP_SECRET_REFERENCE}" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
tpm2_createprimary -C o -c "$WORKDIR/primary.ctx" -Q
|
||||
|
||||
tpm2_createpolicy -Q \
|
||||
--policy-pcr \
|
||||
-l "$PCR_LIST" \
|
||||
-L "$WORKDIR/policy.digest"
|
||||
|
||||
printf '%s' "$PASSWORD" | tpm2_create \
|
||||
-C "$WORKDIR/primary.ctx" \
|
||||
-L "$WORKDIR/policy.digest" \
|
||||
-i - \
|
||||
-u "$WORKDIR/seal.pub" \
|
||||
-r "$WORKDIR/seal.priv" \
|
||||
-Q
|
||||
|
||||
unset PASSWORD
|
||||
|
||||
tpm2_load \
|
||||
-C "$WORKDIR/primary.ctx" \
|
||||
-u "$WORKDIR/seal.pub" \
|
||||
-r "$WORKDIR/seal.priv" \
|
||||
-c "$WORKDIR/seal.ctx" \
|
||||
-Q
|
||||
|
||||
tpm2_evictcontrol -C o -c "$WORKDIR/seal.ctx" "$HANDLE" >/dev/null
|
||||
|
||||
echo "Password from ${OP_SECRET_REFERENCE} sealed and persisted at handle ${HANDLE}, bound to PCRs ${PCR_LIST}"
|
||||
Reference in New Issue
Block a user