PKCS#11 vendors

Per-vendor notes for supported (and unsupported) HSMs. CertAutoPilot's requirements are CKM_AES_GCM + CKM_AES_KEY_GEN — any FIPS-approved HSM from the last decade qualifies. We validate via the capability probe before committing. See the setup flow for the generic procedure.

01Support matrix

HSMStatusNotes
SoftHSM2 ≥ 2.4✅ Test-onlyReference implementation for CI/dev. Not for production (software-only). CKM_AES_GCM added in SoftHSM v2.4.
AWS CloudHSM✅ ProductionSet encryption.pkcs11.use_gcm_iv_from_hsm: true — CloudHSM mandates HSM-generated IVs. Requires the CloudHSM client daemon + libcloudhsm_pkcs11.so.
Thales Luna Network HSM 7.x✅ ProductionStandard v2.40 behaviour. Works with host-supplied IVs. Default config.
Fortanix DSM✅ Community-validated (free SaaS tier ideal for dev/test)Standard PKCS#11 client. Free Developer tier ships 10 000 transactions / 30-day trial — enough for a full rotation cycle without touching a credit card. See the walkthrough below.
Nitrokey HSM 2⚠️ Likely limitedMechanism list varies by firmware; verify CKM_AES_GCM via pkcs11-tool -M before committing.
YubiHSM 2❌ NOT SUPPORTEDVendor PKCS#11 module supports only CKM_AES_CBC[_PAD], CKM_AES_ECB, and the proprietary CKM_YUBICO_AES_CCM_WRAP. No CKM_AES_GCM.
IBM CEX 5/6/7 via opencryptoki⚠️ Vendor docs checkTheoretically compatible; not validated by us yet.

02SoftHSM2 (dev / CI only)

# Install
sudo apt install -y softhsm2 opensc      # Debian/Ubuntu
brew install softhsm opensc              # macOS

# Initialise a token
softhsm2-util --init-token --free \
  --label certautopilot-prod \
  --so-pin sopassword --pin password

# One-command install via the bootstrap. Pass the PIN inline or from a
# mode-0600 file — see the standalone install docs for both variants.
curl -fsSL https://raw.githubusercontent.com/CloudNativeWorks/certautopilot-archive/main/get.sh \
  | sudo bash -s -- --version=1.4.0 --mongo=local \
    --kek-provider=pkcs11 \
    --pkcs11-module=/usr/lib/softhsm/libsofthsm2.so \
    --pkcs11-token-label=certautopilot-prod \
    --pkcs11-pin=password

SoftHSM2 holds the "HSM" in a plain file. It is a legitimate development/testing backend, not a production cryptographic boundary.

03AWS CloudHSM

Prerequisites:

  1. Provision a CloudHSM cluster in your AWS account (or attach to an existing one).
  2. Create a crypto user on the cluster (separate from the crypto officer used for admin).
  3. Install the CloudHSM client daemon on every CertAutoPilot host (Amazon publishes packages for Amazon Linux, RHEL, Ubuntu). The package lands the library at /opt/cloudhsm/lib/libcloudhsm_pkcs11.so and the daemon's config at /opt/cloudhsm/etc/cloudhsm_client.cfg.
  4. Point the daemon at your cluster — one of the ENI IPs is enough; the daemon discovers peers via the cluster membership API:
    sudo /opt/cloudhsm/bin/configure -a <cluster-eni-ip>
    sudo systemctl enable --now cloudhsm-client
    This command writes the cluster endpoint into cloudhsm_client.cfg. The library reads it on dlopen; CertAutoPilot never sees the IP.
  5. Confirm the daemon is running and the cluster is reachable: sudo /opt/cloudhsm/bin/cloudhsm_mgmt_util should list nodes.

Then:

secrets:
  encryption:
    provider: pkcs11
    pkcs11:
      modulePath: /opt/cloudhsm/lib/libcloudhsm_pkcs11.so
      tokenLabel: <your-cluster-label>
      useGcmIvFromHsm: true        # CloudHSM mandates HSM-supplied IVs
      pinValue: <CU-user:password>  # crypto-user creds in user:pass form

The PIN format for CloudHSM is <username>:<password> (crypto-user credentials), not a simple password.

Multi-VM: the same cluster serves every VM. Run configure -a on each host. Cluster scaling (adding/removing HSMs) is handled by the daemon automatically — no CertAutoPilot restart needed for that.

04Thales Luna Network HSM

Prerequisites (must complete before running the bootstrap):

  1. Download the Luna Client SDK from your Thales customer portal. Install on every CertAutoPilot host — ships libCryptoki2_64.so under /usr/safenet/lunaclient/lib/.
  2. Register the client certificate with your HSM partition using vtl or the LunaSH console per Thales docs:
    # Add each HSM appliance you want this host to talk to. In an HA
    # group, add every member; the client library handles failover.
    sudo /usr/safenet/lunaclient/bin/vtl addServer \
      -n hsm01.internal.example.com \
      -c /etc/lunaclient/cert/server/CAFile.pem
    sudo /usr/safenet/lunaclient/bin/vtl addServer \
      -n hsm02.internal.example.com \
      -c /etc/lunaclient/cert/server/CAFile.pem
    
    # Create / assign the HA group the service will bind to.
    sudo /usr/safenet/lunaclient/bin/vtl haAdmin -group -add \
      -label cap-prod -slot 0
    These commands edit /etc/Chrystoki.conf. A minimal post-setup snippet of that file looks like:
    LunaSA Client = {
        ReceiveTimeout = 20000;
        NetClient = 1;
        ServerName00 = hsm01.internal.example.com;
        ServerPort00 = 1792;
        ServerName01 = hsm02.internal.example.com;
        ServerPort01 = 1792;
        ClientPrivKeyFile = /etc/lunaclient/cert/client/cap-vm-a.pem;
        ClientCertFile   = /etc/lunaclient/cert/client/cap-vm-a.cert;
        ServerCAFile     = /etc/lunaclient/cert/server/CAFile.pem;
    }
    VirtualToken = {
        VirtualToken00Label = cap-prod;
        ...
    }
    You never paste IPs into CertAutoPilot's config.yaml. The Luna library reads Chrystoki.conf on dlopen and handles connection pooling, HA failover, and TLS to the appliances.
  3. Verify partition access: /usr/safenet/lunaclient/bin/vtl verify must succeed for the CertAutoPilot host before the bootstrap runs — the installer doesn't perform partition bootstrap.
# PIN as a mode-0600 file (recommended); inline via --pkcs11-pin also works.
umask 077 && printf '%s' "$PARTITION_PASSWORD" > /tmp/cap-pin
curl -fsSL https://raw.githubusercontent.com/CloudNativeWorks/certautopilot-archive/main/get.sh \
  | sudo bash -s -- --version=1.4.0 --mongo=local \
    --kek-provider=pkcs11 \
    --pkcs11-module=/usr/safenet/lunaclient/lib/libCryptoki2_64.so \
    --pkcs11-token-label=cap-prod \
    --pkcs11-pin-file=/tmp/cap-pin
shred -u /tmp/cap-pin

Luna accepts both host-supplied and HSM-supplied IVs; the default (use_gcm_iv_from_hsm: false) is fine. Consult vendor docs for firmware + FIPS-mode requirements.

Multi-VM: run the Luna client install + vtl addServer + vtl verify sequence on every VM before the bootstrap. The Chrystoki.conf file has to be byte-identical across VMs (same ServerName list, same HA group label) — most operators push it via their config-management tool. Each VM gets its own client cert (different ClientPrivKeyFile / ClientCertFile paths are fine), but all certs must be registered with the same HSM partition.

05Fortanix DSM

Fortanix Data Security Manager (DSM) is the easiest way to try a real cloud HSM against CertAutoPilot without procurement. Their SaaS offers a free Developer tier with ~10 000 transactions / 30-day trial — enough to run a full rotation cycle (add V2 → verify → rotate → remove V1) end-to-end. FIPS 140-2 Level 3 backing, standard PKCS#11 v2.40 client, no per-host key distribution needed because the HSM is SaaS.

1. Sign up + create a Group

Go to fortanix.com → "Start Free" → pick a region close to where CertAutoPilot will run (EU / Americas / APAC — the region determines the api_endpoint you'll need in the config below).

Once logged in to the DSM console:

  1. Groups → ADD GROUP. Name it certautopilot-kek. A Group is the logical container that owns both your client App and your KEK Security Object.

2. Create an App (the PKCS#11 client identity)

  1. Apps → ADD APP.
  2. Name: certautopilot.
  3. Assigned groups: certautopilot-kek.
  4. Authentication method: API Key (simplest; DSM also supports PKCS#11 client certificate auth, but API Key is the shortest path to a first rotation).
  5. Minimum permissions for CertAutoPilot: ENCRYPT, DECRYPT, GENERATE. Add WRAPKEY / UNWRAPKEY if you plan to use the same App for non-envelope operations later.

After Save, the App detail page shows an API Key and an App UUID. Copy the API Key — you'll feed it to CertAutoPilot as the PKCS#11 "PIN". Treat it like any other HSM PIN: mode 0600 on disk, never in argv or shell history.

3. Download the PKCS#11 client library

Fortanix Support → PKCS#11 library downloads. Pick the latest release (as of April 2026, PKCS#11 5.6.2919). Cross-check the OS Compatibility Matrix linked from the same page against your CertAutoPilot host (typically Ubuntu 22.04+, Debian 12+, RHEL/Rocky/Alma 9+).

Preferred: the distro package. It puts the library in a standard path and pulls in any required shared libraries.

# Debian / Ubuntu
sudo dpkg -i fortanix-pkcs11-*.deb

# RHEL / Rocky / AlmaLinux
sudo rpm -i fortanix-pkcs11-*.rpm

# If distro package doesn't fit, tarball works too
sudo mkdir -p /opt/fortanix/pkcs11
sudo tar -xzf fortanix-pkcs11-*.tar.gz -C /opt/fortanix/pkcs11/
The library filename is fortanix_pkcs11.so (v5.x)

Fortanix renamed the library in the 5.x series. Older guides and vendor-agnostic snippets still reference libsdkms-pkcs11.so — if you see that path anywhere, translate it to fortanix_pkcs11.so. The default install puts it at /opt/fortanix/pkcs11/fortanix_pkcs11.so.

Find where the .so landed — path depends on how you installed:

dpkg -L fortanix-pkcs11 | grep '\.so$'    # Debian/Ubuntu
rpm -ql  fortanix-pkcs11 | grep '\.so$'    # RHEL/Rocky/Alma
find / -name 'fortanix_pkcs11.so' 2>/dev/null   # fallback

4. Write the client config file

Fortanix's 5.x client auto-detects /etc/fortanix/pkcs11.conf when no explicit path is given, but CertAutoPilot runs as the non-root certautopilot service user — which can't read a root-only file under /etc/fortanix/. Pick any path the service user can read at runtime; the examples below use /etc/fortanix/pkcs11.conf (Fortanix default) and fix permissions post-install. If you prefer /etc/certautopilot/fortanix-pkcs11.conf (all CertAutoPilot secrets in one directory), that directory only exists AFTER this installer's first run — so either pre-create it yourself or use the Fortanix default path for now and move the file after install.

The installer creates the certautopilot user+group during user::ensure, which runs before the PKCS#11 preflight check. If you're laying down the config before the very first install, create the group yourself once so the chown below succeeds:

getent group certautopilot >/dev/null || sudo groupadd --system certautopilot

Now write the config (INI-like, not YAML):

sudo mkdir -p /etc/fortanix
sudo tee /etc/fortanix/pkcs11.conf >/dev/null <<EOF
# One of: https://eu.smartkey.io, https://amer.smartkey.io, https://apac.smartkey.io
# Match the region you picked at signup (DSM console's top bar shows it).
api_endpoint = "https://eu.smartkey.io"

# Raw API Key from DSM console → Apps → certautopilot → API Keys tab.
# Fortanix API keys are 164 characters; a short value means a truncated copy-paste.
api_key = "<PASTE APP API KEY>"
EOF

# The service user must be able to read the config at runtime — mode 0640
# + group=certautopilot keeps it invisible to everyone else while the
# service process (group member) can open it. Parent dir needs group +x
# so path traversal works.
sudo chown root:certautopilot /etc/fortanix/pkcs11.conf
sudo chmod 0640 /etc/fortanix/pkcs11.conf
sudo chgrp certautopilot /etc/fortanix
sudo chmod 0750 /etc/fortanix
Common trap: root:root 0600

If the config stays at the default root:root 0600 that a bare tee or text-editor save leaves behind, the service user hits could not open file /etc/fortanix/pkcs11.conf: PermissionDenied at every startup. The Fortanix library falls back to its built-in defaults (no endpoint, no API key) and C_Login returns CKR_ARGUMENTS_BAD — the error is obscure, the root cause is purely file permissions. The chown/chmod lines at the end of the block above are not optional: the parent dir needs group=certautopilot 0750 and the file needs root:certautopilot 0640. The installer's pkcs11 preflight will fail fast with an exact remediation if you skip them, but fixing it up front saves a round trip.

The Fortanix library reads the config path from the file:// URI that CertAutoPilot stores as its PKCS#11 PIN (see the install step below). Because the URI is explicit, the library never consults its built-in default path or FORTANIX_PKCS11_CONFIG_PATH — so if you already have a Fortanix client consuming the default path you can put CertAutoPilot's config elsewhere and leave the existing one alone. Any path the certautopilot service user can read works.

5. Probe with pkcs11-tool before installing CertAutoPilot

Confirm auth + library work before committing to an install:

# Install the pkcs11-tool if missing
sudo apt install -y opensc    # Debian/Ubuntu
# or:
sudo dnf install -y opensc    # RHEL/Rocky/Alma

# Info / token list — prints 32 slots, all exposing the same token
# (label: "Fortanix Token"). The slot count is a client-library quirk;
# one token is what actually exists.
pkcs11-tool --module /opt/fortanix/pkcs11/fortanix_pkcs11.so -I
pkcs11-tool --module /opt/fortanix/pkcs11/fortanix_pkcs11.so -L

# Login + list objects.
# The --pin value is a URI telling the Fortanix library to read the real
# API key from the config file (handled by the library, not pkcs11-tool).
# An empty object list is expected on a fresh group — what matters is
# that login succeeds with no CKR_PIN_INCORRECT error.
pkcs11-tool --module /opt/fortanix/pkcs11/fortanix_pkcs11.so \
  --login --pin 'file:///etc/fortanix/pkcs11.conf' -O
Why file:// instead of the raw API key?

Fortanix's 5.x library officially supports four PIN formats in its C_Login handler: raw 164-character key, env:VAR, file:///path, and password:... (vendor docs). Fortanix itself recommends the config-file approach "for applications with character limits on the PIN parameter" — relevant because the 164-character raw key routinely trips shell PATH limits, CI secret-UI truncation, and copy-paste-with-trailing-newline bugs. The file:// URI sidesteps all of that: the key lives in one mode-0600 file, and the URI you pass around (as CertAutoPilot's PKCS#11 PIN) is itself non-secret.

Troubleshooting:

  • CKR_PIN_INCORRECT with a raw API key → almost always a copy-paste whitespace or truncation. Verify echo -n "$KEY" | wc -c prints 164. Switch to the file:// URI above to sidestep the issue entirely.
  • 0 slots with tokens available → config file not found or not readable. Make sure the path your file:// PIN URI points at (e.g., /etc/fortanix/pkcs11.conf) exists and is readable by the user running pkcs11-tool / the CertAutoPilot service.
  • could not open file … PermissionDenied at C_Login, followed by CKR_ARGUMENTS_BAD → the service user (certautopilot) can't read the Fortanix config. Expected fix: file mode 0640, ownership root:certautopilot; parent dir mode 0750 with group certautopilot. The Fortanix library's fallback "using default configuration" line in the same log confirms this is the permission case — the library couldn't parse your real config and defaulted to empty values, so the API key was never sent.
  • ECONNREFUSED / DNS error → wrong api_endpoint region. EU account hitting the amer endpoint (or vice versa) fails here before auth is even attempted.
  • Authentication failed (401 in trace logs) → API Key was generated in a different region, or the App's auth method isn't "API Key" (check DSM → Apps → your app → Authentication tab), or the App is disabled.
  • cannot dlopen / module not found.so path wrong. Run the find command above and use the exact path.
  • Want verbose logs? Set FORTANIX_PKCS11_LOG_FILE=/tmp/fortanix_pkcs11.log and FORTANIX_PKCS11_LOG_LEVEL=trace in the environment that runs CertAutoPilot (for systemd: drop them into /etc/certautopilot/secrets.env; for ad-hoc certautopilot kek commands, export them before invoking). The 5.x client does not honour an [log] section or top-level log_file/log_level keys inside the client config — only these two env vars. The trace file records every HTTP request the library sends to DSM, which is the most direct signal when the DSM console audit log is empty.
  • DSM Audit Log (console → Audit Log) → most authoritative signal. Every failed auth attempt that reaches DSM is logged with a reason. If it's empty, the problem is client-side (wrong endpoint, config not loaded); if it's populated, the problem is credential-side.

6. Install CertAutoPilot with the Fortanix PKCS#11 provider

Pass the file:// URI directly as the PKCS#11 PIN: it isn't itself a secret (it just points at the file that holds the real API key, which you already protected with 0640 root:certautopilot in step 4), so argv visibility of the URI during install is fine. The installer stamps the URI into /etc/certautopilot/secrets.env as CERTAUTOPILOT_ENCRYPTION_PKCS11_PIN; systemd loads that into the service process at every start, and the Fortanix library resolves the URI back to the real API key inside C_Login.

# Bootstrap. Two Fortanix-specific flags to note:
#   --pkcs11-token-label — default label is 'Fortanix Token' (with a
#     space); the quotes are required.
#   --pkcs11-pin         — file:// URI pointing at your Fortanix
#     client config. Use --pkcs11-pin-file only when the PIN itself
#     is the 164-char raw API key (see alternative below).
curl -fsSL https://raw.githubusercontent.com/CloudNativeWorks/certautopilot-archive/main/get.sh \
  | sudo bash -s -- --version=1.4.4 --mongo=local \
      --kek-provider=pkcs11 \
      --pkcs11-module=/opt/fortanix/pkcs11/fortanix_pkcs11.so \
      --pkcs11-token-label="Fortanix Token" \
      --pkcs11-pin='file:///etc/fortanix/pkcs11.conf'

Alternative: raw API key (no Fortanix config file indirection). Here the 164-character key IS the secret, so it must never appear in argv — use --pkcs11-pin-file with a mode-0600 file:

umask 077
printf '%s' '<164-char API key from DSM>' > /tmp/cap-pin
chmod 0600 /tmp/cap-pin

curl -fsSL https://raw.githubusercontent.com/CloudNativeWorks/certautopilot-archive/main/get.sh \
  | sudo bash -s -- --version=1.4.4 --mongo=local \
      --kek-provider=pkcs11 \
      --pkcs11-module=/opt/fortanix/pkcs11/fortanix_pkcs11.so \
      --pkcs11-token-label="Fortanix Token" \
      --pkcs11-pin-file=/tmp/cap-pin

shred -u /tmp/cap-pin

The raw-key path puts the 164-char secret in /etc/certautopilot/secrets.env (mode 0600); the URI path keeps it in /etc/fortanix/pkcs11.conf so rotating the API key is a one-file edit rather than a secrets.env edit plus service restart. Either path works; pick whichever matches your secret-rotation story.

During the install, kek pkcs11-init --version=1 issues a CKM_AES_KEY_GEN against Fortanix — you'll see a new AES Security Object appear in the DSM console under Groups → certautopilot-kek → Security Objects, labelled certautopilot-kek-v1. That is your KEK.

7. Rotation cycle on Fortanix

Same shape as any other PKCS#11 provider (the runbook applies unchanged):

# Create V2 inside the HSM + kek_versions metadata
sudo certautopilot kek pkcs11-init --version=2

# Restart so the provider loads V2 alongside V1
sudo systemctl restart certautopilot

# Verify — every live node must have V2 loaded (current need not match)
sudo certautopilot kek verify --target=2

# Rotate — rewrap every envelope with V2 explicitly
sudo certautopilot kek rotate --from-version=1 --to-version=2
sudo certautopilot kek status   # poll to completion

# Wait ~30s for heartbeat auto-reload to flip fleet current → V2
# (optional forced restart: systemctl restart certautopilot)

# Retire V1 — refuses if any live node still has V1 as current
sudo certautopilot kek remove --version=1

Fortanix-specific gotchas

  • Token label is literally "Fortanix Token" (with a space). The DSM client exposes 32 PKCS#11 slots and every one of them carries the same fixed token label Fortanix Token. Pass it quoted on the install command: --pkcs11-token-label="Fortanix Token". Dropping the space (Fortanix) is the most common bootstrap failure and produces could not find PKCS#11 token from kek pkcs11-init. Always cross-check with pkcs11-tool -L.
  • Client config file must be readable by the certautopilot service user. A bare tee leaves the file root:root 0600; kek pkcs11-init runs as root and masks this, but the systemd-hardened service fails at every start with could not open file … PermissionDenied followed by CKR_ARGUMENTS_BAD at C_Login. The file needs root:certautopilot 0640 and its parent dir needs root:certautopilot 0750 — see step 4. The installer's pkcs11 preflight fails fast with the exact chown/chmod if this trips.
  • API Key = PKCS#11 PIN. DSM doesn't have a separate "User PIN" concept for API-Key-authed Apps. If the key leaks, rotate it via DSM console → Apps → your app → "Rotate API Key", then update /etc/certautopilot/secrets.env and restart.
  • Transaction budget. Free tier caps total operations (wrap + unwrap + generate). A full rotation of a lab cluster is 2–3 ops per envelope-encrypted record (unwrap old + wrap new + occasional key ops). For 500 records budget ~2 000 transactions — well within the free tier.
  • Audit log. DSM console → Audit Log shows every PKCS#11 call CertAutoPilot makes. Useful for confirming rotation activity and for the sort of compliance evidence a real HSM deployment would need.
  • Fortanix accepts host-supplied GCM IVs — but only at 12 bytes (NIST 96-bit). Any other length fails with CKR_ARGUMENTS_BAD at C_Encrypt (reproducible against eu.smartkey.io). CertAutoPilot pins GCMIVLength=12 at every crypto11.Config construction site for exactly this reason — you do not need to configure anything, but do not override the pin.
  • Leave use_gcm_iv_from_hsm at its default (false). The true path is broken on Fortanix: crypto11 asks miekg/pkcs11 to build a CK_GCM_PARAMS with pIv=NULL, but miekg leaves ulIvBits unset in that path, and Fortanix responds with CKR_MECHANISM_PARAM_INVALID at C_EncryptInit. Only AWS CloudHSM requires true; every other HSM (including Fortanix) wants host-supplied IVs.
  • Fortanix advertises CKM_AES_KEY_WRAP_KWP (0x2107) and CKM_AES_KEY_WRAP (0x2104) but both reject every parameter combination we tried. Raw miekg/pkcs11 probes with NULL mechanism params and the 8-byte default ICV all returned CKR_MECHANISM_PARAM_INVALID. Algorithm migration from AES-GCM to AES-KWP (tempting as a way to eliminate IV-length concerns) is a dead end on Fortanix; the KEK wrap stays on AES-GCM.
  • Trial → production. Moving from the Developer tier to a paid Fortanix subscription doesn't change anything CertAutoPilot cares about — same client library, same endpoint pattern, same PKCS#11 semantics. The keys you created during trial persist into the upgraded account.

06Nitrokey HSM 2

Nitrokey's PKCS#11 mechanism list depends on firmware version. Probe first:

pkcs11-tool --module /usr/lib/opensc-pkcs11.so -M | grep -i gcm

If CKM_AES_GCM is absent, upgrade firmware. Some older versions only expose CKM_AES_CBC — unsupported by CertAutoPilot.

07YubiHSM 2 — NOT SUPPORTED

YubiHSM's PKCS#11 module supports only CKM_AES_CBC[_PAD], CKM_AES_ECB, and the vendor-proprietary CKM_YUBICO_AES_CCM_WRAP. No CKM_AES_GCM, so envelope wrap/unwrap cannot be implemented without using the CCM wrap path — which we don't do today. A Phase 3 effort may add YubiHSM-specific CCM wrap on request.

08IBM CEX via opencryptoki

IBM's Crypto Express cards expose PKCS#11 through the opencryptoki layer. Theoretically they support CKM_AES_GCM, but we haven't validated end-to-end. Run --probe-only first; report success/failure so we can update this matrix.

09What to watch for in any HSM

  • Session exhaustion. Many HSMs cap at ~1024 concurrent sessions. CertAutoPilot's default session pool is 1024; tune encryption.pkcs11.max_sessions if yours is tighter.
  • Sensitive + non-extractable attributes. The probe checks that generated keys come back with CKA_SENSITIVE=true and CKA_EXTRACTABLE=false. Some HSMs default differently — ensure your key policy enforces these.
  • IV handling. Set use_gcm_iv_from_hsm: true for CloudHSM. Leave false for SoftHSM2, Luna, Fortanix, and everything else.
  • Firmware upgrades. Before applying a firmware update, run --probe-only in a non-production cluster to check for mechanism regressions.