checkId: check.smremote.remote-hsm.connectivity plugin: stellaops.doctor.security severity: fail tags: [security, crypto, hsm, smremote]
SmRemote Remote HSM Connectivity
This Doctor check verifies that the SmRemote remote-HSM forwarder (cn.sm.remote.http) is reachable and reports a healthy SM vendor-adapter contract. All SM2/SM3/SM4 signing and encryption rides this forwarder, so a dead remote HSM silently fails every SM crypto operation — and SmRemote validates the forwarder only at its own startup, leaving no runtime signal until this check was added (gap-matrix SmRemote-Remote-HSM, P0/P1 for SM-compliance deployments).
What It Checks
Resolves the SmRemote service endpoint from the canonical manifest entry integration.hsm.smremote — config keys SmRemote:Endpoint / Crypto:SmRemote:Endpoint, with the compose env alias STELLAOPS_SMREMOTE_URL accepted as a legacy fallback. The probe then GETs the SmRemote service’s own /healthroute:
| Condition | Result |
|---|---|
| SmRemote not configured (SM regional crypto not deployed) | skip (honest — never a false pass) |
/health returns 200 with a healthy SM provider/adapter body | pass |
/health returns 503 (or any non-success) — forwarder/remote-HSM unhealthy | fail (remote-HSM-specific cause) |
| The SmRemote service is unreachable | fail |
The /health route is the deployment-correct aggregated signal: when the forwarder is configured (cn.sm.remote.http), that endpoint internally calls the remote HSM and returns its vendor-adapter contract (status / provider / adapterKind / contractVersion), answering 503 with a failureClass (adapter_http_error / adapter_timeout / a vendor-contract failure) when the remote HSM is unreachable, times out, or fails its contract. This is a state a bare “is the SmRemote service up?” probe would miss, because the SmRemote service itself is up while its remote HSM is dead.
Air-gap & non-destructive posture
The probe is reachability + capability/contract only. It never reaches the remote HSM directly — it asks the local SmRemote service for its already-computed health. It performs no signing operation, no key mint/delete, and no external network revocation (ADR-026 D5, air-gap invariant). On-prem / remote-provider only — never a cloud-managed KMS.
Secret safety
The SmRemote bearer API key (SM_REMOTE_HSM_API_KEY) is held by the SmRemote service, not by Doctor. This check never reads it, never sends it, and never places any secret in evidence — only the endpoint URL, the HTTP status, and public adapter/contract identifiers (provider, adapterKind, contractVersion) are recorded.
Why It Matters
When SM regional crypto is in use, every SM2 signature, SM3 hash, and SM4 encrypt/decrypt that the platform performs flows through this forwarder. A dead or contract-failing remote HSM means SM crypto operations fail closed platform-wide with no other Doctor signal. Catching it here turns a silent SM-compliance outage into a visible, actionable fail.
Common Causes
- The remote HSM is unreachable, timing out, or failing its vendor-adapter contract
SM_REMOTE_HSM_URL/SM_REMOTE_HSM_TIMEOUT/SM_REMOTE_HSM_API_KEYare misconfigured in the SmRemote service- The SmRemote service is down or its HSM session has expired
- The SmRemote endpoint host/port (
STELLAOPS_SMREMOTE_URL) is wrong on the consuming services
How to Fix
Docker Compose
# Inspect the SmRemote forwarder health (the aggregated remote-HSM signal):
curl -fsS http://smremote.stella-ops.local/health
# Verify the remote-HSM configuration (on-prem / remote provider only — never a cloud-managed KMS):
# SM_REMOTE_HSM_URL, SM_REMOTE_HSM_TIMEOUT, SM_REMOTE_HSM_API_KEY
# Then re-establish the forwarder / HSM session:
docker compose -f devops/compose/docker-compose.crypto-provider.smremote.yml restart smremote
Bare Metal / systemd
# Confirm the SmRemote endpoint and probe its health:
curl -fsS "$STELLAOPS_SMREMOTE_URL/health"
# Restart the SmRemote service to re-establish the HSM session:
systemctl restart stellaops-smremote
Kubernetes / Helm
# Check the SmRemote pod and the remote-HSM config (Secret/ConfigMap):
kubectl get pods -l app=stellaops-smremote -n stellaops
kubectl logs -l app=stellaops-smremote -n stellaops --tail=100
# Roll the deployment to re-establish the forwarder once the HSM is reachable:
kubectl rollout restart deployment/stellaops-smremote -n stellaops
Verification
stella doctor run --check check.smremote.remote-hsm.connectivity
Related Checks
check.crypto.pack.admission— the signed crypto-provider pack that supplies the in-processcn.sm.softprovider (a different SM crypto path / supply-chain boundary)check.security.authority-signing-key— the Authority token-signing key (a different signing dependency)check.core.integration-coverage— enumerates every declared integration; this check is the live owner ofintegration.hsm.smremote
