Two questions settle where a VPN private key belongs: whether the key material can be copied off the host, and whether a process can use it with nobody at the keyboard. A store's marketing label answers neither one. A tunnel daemon that has to come back after a reboot needs unattended use, which rules out anything gated on a PIN typed by a human.

Decide Between Copying and Using

Copying and using fail differently, so treat them as two requirements rather than one. An attacker who can read the key bytes carries the identity to another host, and the original machine never notices. An attacker who cannot read the bytes but can reach the signing process still authenticates for as long as that access lasts.

A file key is trivially copyable, which is also why it is the easiest to back up and restore. A software key store changes the API rather than the boundary: the provider refuses its own export calls, yet the same administrator context that installed the key usually has other routes to the material. Non-exportable in a software provider is a statement about supported operations, not proof of a hardware wall. Treat it as a speed bump for casual copying, not as protection against somebody who already holds your session.

A TPM or a smart card runs the signing operation inside hardware and returns only the result. That closes the copy path while leaving the use path open to anything able to request a signature.

Match the Store to the Tunnel Daemon

The daemon constrains this more than the security policy does. WireGuard takes a base64 private key from a file or from wg set input and has no route into a certificate store, so a TPM-backed interface key is not on the table. OpenVPN built against OpenSSL 3 can load a key through a provider URI, and strongSwan ships a TPM plugin alongside PKCS#11 support, but both depend on how your package was compiled.

A daemon that cannot reach the chosen store turns the hardware boundary into decoration. Somebody exports the key once, leaves it in a file, and the rest of the design quietly runs on that copy.

Renewal is the other half of the match, and it is where most designs fall apart. A store that works for the first enrollment but demands a console login for every reissue gets bypassed the first time a certificate expires at an awkward hour. Test the reissue path while the current key still has months left.

Inventory the Key Before You Move It

Record what the key is before changing where it lives, because a migration that drops the subject alternative names breaks the tunnel in a way that reads like a routing fault. Dump the certificate, confirm the private key is readable where the daemon expects it, and check that the pair actually matches.

openssl x509 -in vpn.crt -noout -subject -ext subjectAltName
openssl pkey -in vpn.key -check -noout
openssl x509 -in vpn.crt -noout -pubkey | openssl sha256
openssl pkey -in vpn.key -pubout | openssl sha256

The last two digests must be identical. When they are not, the daemon finishes its setup and then fails every attempt with a certificate or signature error that points nowhere near the real cause. The WireGuard equivalent is shorter, since the public key derives directly from the private one: wg pubkey < /etc/wireguard/wg0.key has to print the peer key your server already has on file.

Permissions belong in the same inventory. stat -c '%a %U:%G' /etc/wireguard/wg0.key should return 600 root:root, and anything group- or world-readable means the key has already been available to processes you never intended.

Check the Store and the Use Path

Verification has three parts, and the third is the one that gets skipped. Confirm the key exists in the store you picked, confirm the daemon loaded that key rather than a leftover copy, then confirm it still starts once the export artifact is gone.

certutil -store -user My
certutil -csp "Microsoft Platform Crypto Provider" -key -user
certutil -verifykeys -user My
ipsec listcerts

On Windows the first command lists the personal store and prints the key provider beside each entry, which is where a certificate that looks hardware-backed but sits in the software provider shows up. The second lists keys held by the platform crypto provider, so a VPN identity missing there while its certificate is present means the private half lives somewhere else. On a Linux gateway, ipsec listcerts reports what strongSwan loaded, including keys that came from the TPM plugin. Compare thumbprints or public-key hashes against the inventory rather than trusting the entry count.

The negative test is the one that proves the design. Move the exported key out of the daemon's configuration directory, restart the service, and read the log for the identity it presents. A tunnel that still comes up is using the store; a failed start means the design was really running on a copy.

Write Down Renewal and Rollback

Rollback differs sharply between the two families, and that difference belongs in the design note rather than in an incident call. A file key can be backed up encrypted and restored, so a failed migration reverses. A non-exportable key cannot be backed up at all, which makes reissue and re-enrollment the only recovery path when the device dies.

Check expiry before it turns into an outage: openssl x509 -in vpn.crt -noout -checkend 2592000 exits non-zero once the certificate expires inside thirty days, so it drops straight into a monitoring check. A weekly run of that line catches the renewal nobody scheduled.

Removal happens on the server: delete the peer or revoke the serial, then confirm the tunnel fails, since a client holding a cached session can hide a half-finished revocation for a while. Revocation also has to reach the concentrator's CRL or OCSP path, not merely the CA database. A certificate is a public document, and the RFC 5280 profile covers how it is validated; none of that validation protects a private key copied before the rotation.

Write the decision in one place: which store holds the key, which process may use it, who can reissue it, and what the rollback is. That paragraph is what auditors ask for, and it is what survives a staff change.

Artaigilean co-cheangailte