Software
AutoHSM
A small daemon that keeps a self-hosted HashiCorp Vault unsealed across restarts, using unseal shares wrapped by a unique, non-extractable HSM key on each node.
What it is
Vault's built-in PKCS#11 auto-unseal is an Enterprise feature. A Community Edition server that reboots stays sealed until people enter enough unseal keys. AutoHSM closes that gap for teams running their own Vault, and it treats visibility as the more important half:
- Availability: the server comes back unsealed after a reboot without a person at the keyboard.
- Visibility: every poll that finds the server sealed raises an alarm, even when the unseal then succeeds, so you learn that it restarted at all.
Who it is for
- Operators of a self-hosted Vault using Shamir unseal keys who want unattended recovery after reboots.
- Teams that already run, or can run, an HSM or SoftHSM token on each node.
- Anyone who wants a sealed server to be loud rather than silently unavailable.
How it works
Each node holds one or more unseal shares, each stored as an AES-256-GCM envelope encrypted by a key that never leaves the node's HSM:
autohsm-v1.<base64(nonce)>.<base64(ciphertext||tag)> AAD: autohsm-v1|node=<node_id>|idx=<n>
| Situation | Result |
|---|---|
| Share used with a different node label | Fails: AAD mismatch |
| Share replayed under another index | Fails: AAD index mismatch |
| Ciphertext tampered with | Fails: GCM tag |
| Disk, backup or snapshot stolen | Inert: the key never leaves the HSM |
| Wrong CA presented by the server | Fails: pinned CA, no system-root fallback |
| Plaintext http:// server address | Refused at config load |
The daemon polls seal status, and when the server is sealed it unwraps this node's shares inside the HSM and submits them. Accepted share indexes are recorded per unseal attempt so a crash does not resubmit.
Install
The repository is public under the MIT license. PKCS#11 needs cgo, so build on the target platform (a Linux host or Linux container for Linux servers). With Go 1.24 or newer and a C compiler:
go install github.com/afterdarksys/secretserver-autohsm/cmd/autohsm@latest
Or build from a checkout:
git clone https://github.com/afterdarksys/secretserver-autohsm.git cd secretserver-autohsm make build # CGO_ENABLED=1 go build -trimpath -o bin/autohsm ./cmd/autohsm # make build-linux # GOOS=linux GOARCH=amd64 build, writes bin/autohsm-linux-amd64
Install files and the service user
sudo install -m 0755 bin/autohsm /usr/local/bin/autohsm # after make build-linux: sudo install -m 0755 bin/autohsm-linux-amd64 /usr/local/bin/autohsm sudo useradd --system --no-create-home --shell /usr/sbin/nologin autohsm sudo install -d -o root -g autohsm -m 0750 /etc/autohsm sudo install -o root -g autohsm -m 0640 examples/autohsm.yaml /etc/autohsm/autohsm.yaml sudo install -o root -g autohsm -m 0640 /path/to/vault-ca.pem /etc/autohsm/vault-ca.pem sudo install -o root -g autohsm -m 0640 /secure/path/hsm-pin /etc/autohsm/pin sudo cp deploy/autohsm.service /etc/systemd/system/
Create the wrapping key (SoftHSM shown)
sudo usermod -aG softhsm autohsm sudo -u autohsm softhsm2-util --init-token --slot 0 --label autohsm --so-pin <SO_PIN> --pin <PIN> sudo -u autohsm AUTOHSM_PIN=<PIN> pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so \ --login --pin env:AUTOHSM_PIN \ --keygen --key-type aes:32 --label autohsm-wrap --private --sensitive \ --usage-decrypt
Create the token as the autohsm user; a token created as root is unreadable to the service, and every later step then fails with pkcs11 initialize: CKR_GENERAL_ERROR.
Wrap this node's share, verify, enable
sudo -u autohsm autohsm wrap --index 1 < /path/to/share-1.txt \ | sudo tee /etc/autohsm/share-1.wrapped sudo chown root:autohsm /etc/autohsm/share-1.wrapped sudo chmod 0640 /etc/autohsm/share-1.wrapped sudo -u autohsm autohsm selftest sudo systemctl daemon-reload sudo systemctl enable --now autohsm
autohsm status exits 2 when the server is sealed and never touches the HSM, which makes it a cheap external monitor from cron.
Platform support
| Component | Status |
|---|---|
| Linux with systemd | Supported target; README install and the shipped unit tested on Debian 12 |
| SoftHSM 2.6 / 2.7 | Integration and end-to-end tested |
| Vault 1.20, Shamir seal, 3 nodes | End-to-end tested, including negative cases |
| Hardware HSMs (vendor PKCS#11) | Written against PKCS#11 v2.40 AES-GCM but not yet exercised on production hardware. Run selftest against your token first. |
| Go toolchain | Go 1.24 or newer, cgo enabled |