Runbook: Attestor - HSM Connection Issues
Sprint: SPRINT_20260117_029_DOCS_runbook_coverage Task: RUN-005 - Attestor Runbooks
Source-reconciled (2026-05-30; re-verified 2026-05-31): This runbook was rewritten against
src/Cryptography/StellaOps.Cryptography.Plugin.Hsm/HsmPlugin.cs, the Doctor checksrc/Doctor/__Plugins/StellaOps.Doctor.Plugin.Crypto/Checks/HsmPkcs11AvailabilityCheck.cs, the CLI surface insrc/Cli/StellaOps.Cli/Commands/CryptoCommandGroup.cs(plus thekeygroup inCommands/Proof/KeyRotationCommandGroup.csandCommandFactory.cs), and the scope catalogsrc/Authority/.../StellaOpsScopes.cs. A previous revision documented astella crypto hsm ...command family, a software-signing fallback, and HSM failover that do not exist in the code; those were removed. The 2026-05-31 re-verification additionally corrected thestella key verifyusage (two positional args, and the verb is a stub today), flagged that the Doctor check’s slot/token stages are stubbed to always pass, and noted the--hsm-pinremediation hint is also a non-existent verb. SeeDecisions & Risksat the end.
Audience: platform and security on-call engineers diagnosing failed HSM-backed signing in a Stella Ops deployment. Use this runbook when attestations stop signing, the Attestor/Signer host fails to start, or the check.crypto.hsm Doctor check reports Fail/Warn. The HSM provider is fail-closed by design — recovery means fixing configuration or connectivity and restarting, never downgrading to software keys.
Metadata
| Field | Value |
|---|---|
| Component | Attestor / Cryptography |
| Severity | Critical |
| On-call scope | Platform team, Security team |
| Last updated | 2026-05-30 |
| Doctor check | check.crypto.hsm |
Symptoms
- [ ] Signing operations failing with “HSM is not connected” / “HSM not connected”
- [ ] Attestor / signer service fails to start (initialization throws before the PKCS#11 library loads)
- [ ] Health probe reports the HSM provider
Unhealthy(“HSM not connected”) orDegraded(“HSM responding slowly”) - [ ] Error:
HSM key id '<id>' is not declared in configured key identifiers(key not in the allow-list) - [ ] Attestations cannot be created; releases blocked
- [ ]
stella doctor --check check.crypto.hsmreports Fail/Warn
Note on alerts: No
AttestorHsmConnectionFailedPrometheus/alert rule is defined in the repository today. If your deployment ships such an alert, wire it to the HSM pluginHealthCheckAsyncresult (Unhealthy/Degraded) and record the rule definition alongside this runbook. Treat the alert name here as illustrative, not authoritative.
Impact
| Impact Type | Description |
|---|---|
| User-facing | No attestations can be signed; releases blocked |
| Data integrity | Keys remain in the HSM; operations resume when the connection is restored |
| SLA impact | All HSM-backed signing operations blocked; compliance posture at risk |
Fail-closed by design. The HSM provider does not fall back to local / software keys when the HSM is unreachable or misconfigured. Outside explicit simulation mode (Development/Testing only), initialization throws before the PKCS#11 library is loaded if any required selector is missing. Treat a missing or failed HSM as a deployment defect to fix, not a condition to work around by switching signing modes. See
docs/modules/cryptography/hsm-pkcs11-deployment-health.md(“Fail-Closed Startup Contract” and “Operational Notes”).
Diagnosis
Crypto/HSM diagnostics and configuration changes require an operator token with the appropriate scope (see
src/Authority/.../StellaOpsScopes.cs):crypto:readfor read-only status,crypto:admin/crypto:profile:adminfor provider/profile changes, andcrypto:kek:read/crypto:kek:rotatefor KEK lifecycle operations.
Quick checks
Run the Doctor HSM check (this is the canonical health gate; the check ID is
check.crypto.hsm):stella doctor --check check.crypto.hsmThe check only runs when HSM is enabled (
Crypto:Hsm:Enabled=trueorCryptography:Pkcs11:Enabled=true). It reports four stages — module path configured, module file exists, slot access, token presence — but only the first two are real validations today:HsmPkcs11AvailabilityCheckreadsCrypto:Hsm:ModulePath(orCryptography:Pkcs11:ModulePath) and callsFile.Existson it. The slot-enumeration and token-presence stages (CheckSlotsAsync/CheckTokenAsync) are stubbed to always succeed in the current code — they do not open the PKCS#11 module or contact the token. So aPassfrom this check confirms only that the module path is set and the file is present, not that the slot/token are actually reachable. Use the HSM plugin’sHealthCheckAsyncresult (below) for true connectivity. (Flagged for follow-up; seeDecisions & Risks.)Show crypto plugin status (lists the PKCS#11/HSM provider and its health):
stella crypto plugins statusShow the active crypto provider / FIPS / compliance settings:
stella crypto status
Deep diagnosis
Inspect the active profile and run provider diagnostics:
stella crypto profiles show --details --test--testruns provider connectivity/diagnostics;--detailsprints provider capabilities.Re-run the Doctor check with verbose progress and JSON output to capture the evidence block:
stella doctor --check check.crypto.hsm --format json --verboseOn the real failure paths (module path unset / file missing) the evidence carries
ModulePath,ConfiguredPath, andExists. On thePasspath the evidence reportsSlotId,SlotLabel,TokenPresent, andTokenLabel— but note these slot/token values come from the stubbedCheckSlotsAsync/CheckTokenAsync(constantSlotId=0,SlotLabel="SoftHSM slot 0",TokenLabel="stellaops"), so they are placeholders, not live HSM readings. TheSlotAccess=failed/Errorevidence fields only render if the (stubbed) slot check is ever made to fail; today it cannot. Treat the plugin’sHealthCheckAsyncoutput as the authoritative connectivity signal.Check the service logs for the Attestor / Signer host. The HSM plugin logs on initialization and per-operation, e.g.:
HSM provider connected in {ProviderMode} mode to slot {SlotId}(success)HSM not connected(health probe failed)HSM key id '<id>' is not declared in configured key identifiers(allow-list rejection) Use your standard log access path for the service (there is nostella crypto hsm logscommand).
Interpret the health metadata emitted by
HealthCheckAsync. Real PKCS#11 mode reports:Detail Meaning providerMode=pkcs11Provider backed by a real PKCS#11 library pkcs11=trueHealth probe used the real PKCS#11 client simulation=false/testOnly=falseNot the local test harness slotConfigured slot ID tokenLabelExpected token label configuredKeyCountNumber of declared key identifiers If you instead see
providerMode=simulation,simulation=true,testOnly=true, orlibrary=in-process-simulator, the service is running the local simulation harness, which is test-only and must never back release evidence.
Resolution
There is no runtime “switch to software signing”, “reconnect”, or “failover to backup HSM” command in Stella Ops today. The provider fails closed and recovers only by fixing the underlying configuration / connectivity and restarting the affected service so the plugin re-initializes.
Immediate mitigation
Confirm the failure class with
stella doctor --check check.crypto.hsm(module not configured vs. module missing vs. slot/token failure). This tells you which root-cause section below applies.Do not bypass the HSM. Switching to local/software keys is not a supported mitigation and contradicts the fail-closed contract — it would invalidate the signing route as release evidence. If signing must continue, restore the HSM route, do not downgrade it.
After fixing the configuration or connectivity, restart the affected service (Attestor / Signer host) so
InitializeCryptoServiceAsyncre-runs and re-opens the slot/session. The plugin connects on startup; there is no live reconnect verb.
Root cause fix
If the PKCS#11 module path is not configured or the file is missing (Doctor check Fail):
Configure the module / library path in the service configuration. The Doctor check reads
Crypto:Hsm:ModulePath(orCryptography:Pkcs11:ModulePath), while the HSM plugin itself bindsCryptography:Hsm:LibraryPath:Cryptography: Hsm: LibraryPath: "/usr/lib/softhsm/libsofthsm2.so" # Windows: C:\SoftHSM2\lib\softhsm2.dllThe Doctor check output prints a
stella crypto config set --hsm-module …remediation hint, but that CLI verb is not implemented today — there is noconfigsubcommand understella crypto. Apply the path through the service configuration (env var / config file / Platform environment settings) instead, and restart the service. (Flagged for follow-up; seeDecisions & Risks.)Verify the library architecture matches the service image (an x64-only
.socannot load in an ARM64 .NET process). See the “ARM64 Runtime Contract” indocs/modules/cryptography/hsm-pkcs11-deployment-health.md.
If startup fails closed with a “requires …” error: the plugin requires LibraryPath, SlotId, TokenLabel, Pin, and at least one key identifier (KeyIds or operation-specific IDs) outside simulation mode. Supply the missing selectors via the service configuration (PIN must come from a secret source, not source-controlled config):
Cryptography:
Hsm:
LibraryPath: "/usr/lib/softhsm/libsofthsm2.so"
SlotId: 0
TokenLabel: "StellaOps-Prod"
Pin: "${HSM_PIN}"
KeyIds: "stellaops-signing-2026,stellaops-encryption-2026"
If slot access fails (Doctor Fail, “PKCS#11 slot access failed”):
- Check module permissions:
ls -la <module-path>. - Initialize the slot/token if needed (SoftHSM example):
softhsm2-util --init-token --slot 0 --label "StellaOps-Prod"
If the token is not accessible (Doctor Warn, “PKCS#11 token not accessible”):
- Initialize the token and configure the PIN (the plugin validates the configured
TokenLabelagainst the slot — a mismatch fails startup):softhsm2-util --init-token --slot 0 --label StellaOps-Prod --pin <pin> --so-pin <so-pin> - Provide the user PIN through your secret source (
Cryptography:Hsm:Pin).
If signing fails with an allow-list error (HSM key id '<id>' is not declared in configured key identifiers): the runtime KeyId is not in the configured allow-list. Add it to KeyIds (or the relevant SigningKeyIds / VerificationKeyIds / EncryptionKeyIds / DecryptionKeyIds) and restart the service.
Verification
# Re-run the HSM Doctor check; expect Pass (confirms module path set + file
# present — slot/token stages are stubbed, so this is necessary, not sufficient)
stella doctor --check check.crypto.hsm --format json
# Confirm the crypto plugin reports the HSM/PKCS#11 provider healthy
stella crypto plugins status
# Confirm the active profile/provider and run provider diagnostics
stella crypto profiles show --details --test
Do not rely on
stella key verifyas an HSM verification step today. The top-levelstella key verifycommand (theKeyRotationCommandGrouptree:key list|add|revoke|rotate|status|history|verify) takes two positional arguments —<anchorId>(a GUID trust-anchor id) and<keyId>— plus an optional--signed-at <iso8601>, i.e.stella key verify <anchorId> <keyId>. More importantly, every verb in that group is currently a stub: it printsError: key rotation verify requires a configured key rotation service. No simulated trust-anchor change or validity result was produced.and returns a system-error exit code. It does not contact the HSM and cannot confirm a signing key’s validity in the current build. (Flagged; seeDecisions & Risks.)
Prevention
- [ ] Fail-closed posture: keep
AllowSimulationoff in production; never let a missing HSM downgrade to local keys. - [ ] Token-label validation: keep
TokenLabelaligned with the provisioned token so a slot swap / SoftHSM reinit fails closed instead of signing with the wrong token. - [ ] Key-ID hygiene: keep declared key IDs aligned with signer, attestor, and authority signing profiles so evidence traces the exact HSM key route.
- [ ] Monitoring: wire an alert to the HSM plugin health result (
Unhealthy/Degraded) and record the alert-rule definition next to this runbook (none ships today). - [ ] Testing: include
check.crypto.hsmin regular health checks; exercise the SoftHSM2 integration path perdocs/operations/softhsm2-test-environment.md.
Related Resources
- HSM deployment / health contract:
docs/modules/cryptography/hsm-pkcs11-deployment-health.md - SoftHSM2 test environment setup:
docs/operations/softhsm2-test-environment.md - Cryptography architecture:
docs/modules/cryptography/architecture.md - Related runbooks:
attestor-signing-failed.md,crypto-ops.md - Doctor check (code):
src/Doctor/__Plugins/StellaOps.Doctor.Plugin.Crypto/Checks/HsmPkcs11AvailabilityCheck.cs - Doctor check (article):
docs/doctor/articles/crypto/hsm.md - HSM plugin (code):
src/Cryptography/StellaOps.Cryptography.Plugin.Hsm/HsmPlugin.cs
Decisions & Risks
- Removed invented CLI surface. A prior revision documented
stella crypto hsm status|test|reconnect|ping|logs|slots|failover|config set| config get|auth verify|auth update|pkcs11-status|pkcs11-reload|pkcs11-info| connectivity. None of these exist. The realstella cryptosubcommands are:sign,verify,provider,algorithm,fips,status,profile,profiles,plugins,keys,encrypt,decrypt,hash,kek(src/Cli/StellaOps.Cli/Commands/CryptoCommandGroup.cs). - Doctor check ID corrected from
check.crypto.hsm-availabilitytocheck.crypto.hsm(HsmPkcs11AvailabilityCheck.CheckId). - Removed the “switch to software signing” mitigation — it contradicts the documented fail-closed startup contract; there is no
signing.mode/session.timeout/session.keepalive/pkcs11.library_pathruntime config in the code. Configuration keys are underCryptography:Hsm:*(LibraryPath/SlotId/TokenLabel/Pin/KeyIds), with the Doctor check also readingCrypto:Hsm:*/Cryptography:Pkcs11:*. - Removed backup-HSM failover — no failover feature exists in the plugin.
- Corrected key/attest commands: the prior
stella keys verify <id> --operation signwas wrong on every axis. The real verb lives in the top-levelkey(singular) group built byKeyRotationCommandGroup(src/Cli/StellaOps.Cli/Commands/Proof/KeyRotationCommandGroup.cs, registered atCommandFactory.cs:102):stella key verify <anchorId> <keyId> [--signed-at <iso8601>]— two positional args (a GUID trust-anchor id and the key id), not one, and no--operationflag. The former pluralstella keyssample-data group was unregistered and was deleted on 2026-07-29. Critically, the whole registeredstella keyrotation group is currently a stub — every verb returnsKeyRotationServiceUnavailable(...)(“requires a configured key rotation service”) with a system-error exit code — so it cannot be used to verify an HSM key today. Thestella attest config set/attest reload/attest test-signcommands do not exist (realattestsubcommands:build,attach,verify,verify-offline,list,fetch,predicates). - Related Resources fixed:
docs/modules/cryptography/hsm-integration.mdanddocs/operations/hsm-configuration.mddo not exist; replaced with the realhsm-pkcs11-deployment-health.md,softhsm2-test-environment.md, and the Doctor articledocs/doctor/articles/crypto/hsm.md. - Alert name flagged:
AttestorHsmConnectionFailedis not defined in source; annotated as illustrative. stella crypto config set --hsm-module/--hsm-pinis Doctor remediation text, not a real CLI verb.HsmPkcs11AvailabilityCheckemits bothstella crypto config set --hsm-module …(module-path failures) andstella crypto config set --hsm-pin <your-pin>(token-not-accessible path) as remediation hints, but thecryptocommand group has noconfigsubcommand at all. The runbook instead points operators at the service configuration. Follow-up: either implementstella crypto config setor correct both Doctor-check remediation hints.- Doctor slot/token stages are stubbed.
HsmPkcs11AvailabilityCheck’sCheckSlotsAsyncandCheckTokenAsyncare placeholders that always returnSuccess=truewith constant slot/token values; only the module-path-configured and module-file-exists stages are real. APasstherefore does not prove the slot/token are reachable. The runbook now states this and routes true connectivity diagnosis through the HSM pluginHealthCheckAsyncresult. Follow-up: wire the Doctor check to a real PKCS#11 probe (or the plugin health result) so itsPass/Warn/Failreflects live HSM state. - Open risk: there is no live HSM reconnect/health verb on the CLI today; recovery is “fix config/connectivity + restart the service”. If a runtime reconnect or health-probe verb is desired, file a sprint task against
StellaOps.Cli/ the HSM plugin.
