Files
nixos-servers/docs/vault/auto-unseal.md
Torjus Håkestad c694b9889a
All checks were successful
Run nix flake check / flake-check (push) Successful in 2m16s
vault: add auto-unseal
2026-02-02 00:28:24 +01:00

5.3 KiB

OpenBao TPM2 Auto-Unseal Setup

This document describes the one-time setup process for enabling TPM2-based auto-unsealing on vault01.

Overview

The auto-unseal feature uses systemd's LoadCredentialEncrypted with TPM2 to securely store and retrieve an unseal key. On service start, systemd automatically decrypts the credential using the VM's TPM, and the service unseals OpenBao.

Prerequisites

  • OpenBao must be initialized (bao operator init completed)
  • You must have at least one unseal key from the initialization
  • vault01 must have a TPM2 device (virtual TPM for Proxmox VMs)

Initial Setup

Perform these steps on vault01 after deploying the service configuration:

1. Save Unseal Key

# Create temporary file with one of your unseal keys
echo "paste-your-unseal-key-here" > /tmp/unseal-key.txt

2. Encrypt with TPM2

# Encrypt the key using TPM2 binding
systemd-creds encrypt \
  --with-key=tpm2 \
  --name=unseal-key \
  /tmp/unseal-key.txt \
  /var/lib/openbao/unseal-key.cred

# Set proper ownership and permissions
chown openbao:openbao /var/lib/openbao/unseal-key.cred
chmod 600 /var/lib/openbao/unseal-key.cred

3. Cleanup

# Securely delete the plaintext key
shred -u /tmp/unseal-key.txt

4. Test Auto-Unseal

# Restart the service - it should auto-unseal
systemctl restart openbao

# Verify it's unsealed
bao status
# Should show: Sealed = false

TPM PCR Binding

The default --with-key=tpm2 binds the credential to PCR 7 (Secure Boot state). For stricter binding that includes firmware and boot state:

systemd-creds encrypt \
  --with-key=tpm2 \
  --tpm2-pcrs=0+7+14 \
  --name=unseal-key \
  /tmp/unseal-key.txt \
  /var/lib/openbao/unseal-key.cred

PCR meanings:

  • PCR 0: BIOS/UEFI firmware measurements
  • PCR 7: Secure Boot state (UEFI variables)
  • PCR 14: MOK (Machine Owner Key) state

Trade-off: Stricter PCR binding improves security but may require re-encrypting the credential after firmware updates or kernel changes.

Re-provisioning

If you need to reprovision vault01 from scratch:

  1. Before destroying: Back up your root token and all unseal keys (stored securely offline)
  2. After recreating the VM:
    • Initialize OpenBao: bao operator init
    • Follow the setup steps above to encrypt a new unseal key with TPM2
  3. Restore data (if migrating): Copy /var/lib/openbao from backup

Handling System Changes

After firmware updates, kernel updates, or boot configuration changes, PCR values may change, causing TPM decryption to fail.

Symptoms

  • Service fails to start
  • Logs show: Failed to decrypt credentials
  • OpenBao remains sealed after reboot

Fix

  1. Unseal manually with one of your offline unseal keys:

    bao operator unseal
    
  2. Re-encrypt the credential with updated PCR values:

    echo "your-unseal-key" > /tmp/unseal-key.txt
    systemd-creds encrypt \
      --with-key=tpm2 \
      --name=unseal-key \
      /tmp/unseal-key.txt \
      /var/lib/openbao/unseal-key.cred
    chown openbao:openbao /var/lib/openbao/unseal-key.cred
    chmod 600 /var/lib/openbao/unseal-key.cred
    shred -u /tmp/unseal-key.txt
    
  3. Restart the service:

    systemctl restart openbao
    

Security Considerations

What This Protects Against

  • Data at rest: Vault data is encrypted and cannot be accessed without unsealing
  • VM snapshot theft: An attacker with a VM snapshot cannot decrypt the unseal key without the TPM state
  • TPM binding: The key can only be decrypted by the same VM with matching PCR values

What This Does NOT Protect Against

  • Compromised host: If an attacker gains root access to vault01 while running, they can access unsealed data
  • Boot-time attacks: If an attacker can modify the boot process to match PCR values, they may retrieve the key
  • VM console access: An attacker with VM console access during boot could potentially access the unsealed vault

Recommendations

  • Keep offline backups of root token and all unseal keys in a secure location (password manager, encrypted USB, etc.)
  • Use Shamir secret sharing: The default 5-key threshold means even if the TPM key is compromised, an attacker needs the other keys
  • Monitor access: Use OpenBao's audit logging to detect unauthorized access
  • Consider stricter PCR binding (PCR 0+7+14) for production, accepting the maintenance overhead

Troubleshooting

Check if credential exists

ls -la /var/lib/openbao/unseal-key.cred

Test credential decryption manually

# Should output your unseal key if TPM decryption works
systemd-creds decrypt /var/lib/openbao/unseal-key.cred -

View service logs

journalctl -u openbao -n 50

Manual unseal

bao operator unseal
# Enter one of your offline unseal keys when prompted

Check TPM status

# Check if TPM2 is available
ls /dev/tpm*

# View TPM PCR values
tpm2_pcrread

References