checkId: check.crypto.hsm plugin: stellaops.doctor.crypto severity: warn tags: [crypto, hsm, pkcs11, security]

HSM/PKCS#11 Availability

Doctor check check.crypto.hsm — for operators who back Stella Ops signing keys with a hardware security module, confirming that the PKCS#11 module loads, a slot is reachable, and a token is present before signing operations depend on it.

What It Checks

Verifies HSM (Hardware Security Module) availability via PKCS#11 interface. The check validates three layers:

  1. Module configuration: whether a PKCS#11 module path is configured via Crypto:Hsm:ModulePath or Cryptography:Pkcs11:ModulePath.
  2. Module file existence: whether the configured .so (Linux) or .dll (Windows) file exists on disk.
  3. Slot access: whether the PKCS#11 module can enumerate slots and access the configured slot.
  4. Token presence: whether a token is initialized in the slot and accessible (login test).
ConditionResult
Module path not configuredFail
Module file not found at configured pathFail
Slot access failed (init error, no slots, permission denied)Fail
Token not accessible (not initialized, login failure)Warn
Module loaded, slot accessible, token presentPass

Evidence collected: ModulePath, ModuleExists, SlotId, SlotLabel, SlotAccess, TokenPresent, TokenLabel.

The check only runs when Crypto:Hsm:Enabled or Cryptography:Pkcs11:Enabled is set to “true”.

Why It Matters

HSMs provide tamper-resistant hardware protection for cryptographic keys. When HSM is enabled, all signing operations (attestations, evidence seals, certificate signing) depend on the HSM being accessible. An unavailable HSM means no signing can occur, which blocks evidence generation, attestation creation, and release approvals. HSM connectivity issues can silently degrade to software-based signing if fallback is enabled, which may violate compliance requirements for FIPS 140-2 Level 3 or eIDAS qualified signatures.

Common Causes

How to Fix

Docker Compose

# Verify HSM module is accessible
docker compose exec gateway ls -la /usr/lib/softhsm/libsofthsm2.so

# Initialize a token if needed (SoftHSM2 for development)
docker compose exec gateway softhsm2-util --init-token --slot 0 --label "stellaops" --pin 1234 --so-pin 0000

# List available slots
docker compose exec gateway softhsm2-util --show-slots

# Set environment variables
# Crypto__Hsm__Enabled=true
# Crypto__Hsm__ModulePath=/usr/lib/softhsm/libsofthsm2.so
# Crypto__Hsm__Pin=1234

docker compose restart gateway

Bare Metal / systemd

# Install SoftHSM2 (for development/testing)
sudo apt install softhsm2

# Initialize token
softhsm2-util --init-token --slot 0 --label "stellaops" --pin 1234 --so-pin 0000

# List slots
softhsm2-util --show-slots

# Verify module permissions
ls -la /usr/lib/softhsm/libsofthsm2.so

# Configure the PKCS#11 module path and PIN via YAML, then restart the service.
# Edit appsettings.crypto.yaml (or your appsettings override) and set:
#   crypto:
#     hsm:
#       enabled: true
#       modulePath: /usr/lib/softhsm/libsofthsm2.so   # Linux
#       # modulePath: C:\SoftHSM2\lib\softhsm2.dll    # Windows variant
#
# Provide the PIN via environment variable (do NOT commit it to YAML):
#   export Crypto__Hsm__Pin=<your-pin>
# or via your secret store (Kubernetes Secret, systemd EnvironmentFile, etc.).
#
# Save the YAML, export the PIN, then restart. Changes take effect on the next start.

sudo systemctl restart stellaops-platform

Kubernetes / Helm

# values.yaml
crypto:
  hsm:
    enabled: true
    modulePath: /usr/lib/softhsm/libsofthsm2.so
    pinSecret: stellaops-hsm-pin
    slotId: 0
# Create HSM PIN secret
kubectl create secret generic stellaops-hsm-pin \
  --from-literal=pin=<your-pin>

# For hardware HSMs, mount the device into the pod
# Add to pod spec: devices: ["/dev/pkcs11"]

# Initialize token
kubectl exec deploy/stellaops-gateway -- softhsm2-util --init-token --slot 0 --label stellaops --pin 1234 --so-pin 0000

helm upgrade stellaops ./charts/stellaops -f values.yaml

Verification

stella doctor run --check check.crypto.hsm

See the Doctor reference for the full check catalog, CLI usage, and export bundles.