HSM / KMS integration¶
The ICryptoProvider abstraction lets Ampora delegate every signing operation to an external key store. The CA signing key is generated inside the HSM/KMS, never extracted, and every issuance and CRL signing is a delegated operation.
Five adapters ship in opt-in NuGet packages:
| Adapter | Backend | Algorithms |
|---|---|---|
Ampora.Pki.Aws | AWS KMS | RSA 2048/3072/4096, ECDSA P-256/P-384 |
Ampora.Pki.Azure | Azure Key Vault (HSM-backed) | RSA 2048/3072/4096, ECDSA P-256 |
Ampora.Pki.Gcp | GCP KMS | RSA 2048/3072/4096, ECDSA P-256/P-384 |
Ampora.Pki.Pkcs11 | Any PKCS#11 device (Thales, SoftHSM, YubiHSM) | RSA / ECDSA per device support |
Ampora.Pki.VaultTransit | HashiCorp Vault Transit | RSA / ECDSA / Ed25519 per Vault config |
The default Software provider keeps wrapped keys in PostgreSQL, suitable when you do not have an HSM or KMS at hand.
When to use HSM / KMS¶
- You operate under a compliance regime that mandates non-extractable signing keys (FIPS 140-2 Level ⅔, Common Criteria EAL4+, eIDAS).
- Your existing PKI is already HSM-backed and Ampora's sub-CA needs to match.
- You want a clear audit trail in your KMS service (CloudTrail, Azure Activity Log, Cloud Audit Logs) for every signing operation.
Configuration¶
CryptoProvider:
Kind: AwsKms # or AzureKeyVault, GcpKms, Pkcs11, VaultTransit, Software
KeyId: arn:aws:kms:eu-central-1:1234:key/abcd-... # provider-specific
Region: eu-central-1 # AWS only
Endpoint: "" # override for VPC endpoints / dev kms
Each provider has provider-specific keys; see the adapter's README on the repository.
AWS KMS¶
CryptoProvider:
Kind: AwsKms
KeyId: arn:aws:kms:eu-central-1:111111111111:key/abcd-1234-5678
Region: eu-central-1
Required IAM:
kms:Signkms:Verifykms:GetPublicKeykms:DescribeKey
The pod's service account must have these via IRSA (recommended) or via a long-lived access key in the Secret.
Azure Key Vault¶
CryptoProvider:
Kind: AzureKeyVault
KeyId: https://amporaprodvault.vault.azure.net/keys/ampora-ca/abcdef1234
Required RBAC on the key:
Key Vault Crypto User(sign + verify + get).
Workload Identity is the recommended auth path on AKS.
GCP KMS¶
CryptoProvider:
Kind: GcpKms
KeyId: projects/acme/locations/europe-west3/keyRings/ampora/cryptoKeys/ca/cryptoKeyVersions/1
Required IAM:
cloudkms.signer(sign).cloudkms.viewer(read public key + metadata).
Workload Identity Federation is the recommended auth path on GKE.
PKCS#11¶
CryptoProvider:
Kind: Pkcs11
ModulePath: /usr/local/lib/libCryptoki2_64.so
TokenLabel: ampora-prod
ObjectLabel: ampora-ca-rsa3072
PinEnvVar: HSM_PIN # name of env var that holds the PIN
Bring your own PKCS#11 module (Luna, nFast, YubiHSM, SoftHSM). The adapter loads the .so at startup; container deployments mount the module from a sidecar or init-container.
HashiCorp Vault Transit¶
CryptoProvider:
Kind: VaultTransit
Address: https://vault.acme.io:8200
Mount: transit
KeyName: ampora-ca
Auth:
Method: Kubernetes # AppRole | Token | Kubernetes
Role: ampora-prod
Required Vault policy:
path "transit/sign/ampora-ca/*" { capabilities = ["update"] }
path "transit/keys/ampora-ca" { capabilities = ["read"] }
Bootstrap from an HSM-backed CA¶
If the HSM key already exists (e.g. provisioned out-of-band as part of your corporate PKI):
- Configure the provider as above.
- Start Ampora.
- Settings → PKI → Signing keys → Import HSM key. Provide the provider's key reference and the cert chain.
- The new row lands in
Draftwith the public key derived from the HSM and no private material in the database. - Activate as usual.
If the HSM key does not yet exist:
- Configure the provider.
- Start Ampora.
- Settings → PKI → Signing keys → Create. Ampora calls the provider to generate a new key inside the HSM/KMS.
- The row lands in
DraftwithKeyHandle = <provider-specific>. - Have the cert signed by your offline root, paste the chain, activate.
Either way, the private key never lives on disk and never lives in PostgreSQL.
Performance considerations¶
Signing through KMS / HSM adds network latency to every issuance and every CRL refresh. Ampora batches CRL signing (one signing per refresh, not per revocation) and caches OCSP responses for 4 hours by default. Bulk leaf issuance during a fleet rebootstrap fans out via a small worker pool — provider-specific concurrency limits apply.
Typical numbers per signing operation:
| Provider | Local-region latency |
|---|---|
| AWS KMS | 8 – 15 ms |
| Azure Key Vault | 30 – 80 ms |
| GCP KMS | 15 – 30 ms |
| Vault Transit (mTLS, k8s auth) | 5 – 15 ms |
| PKCS#11 (local USB / network HSM) | 1 – 50 ms depending on device |
For a 1000-agent rebootstrap, plan on a few minutes; the operation is async and shows progress in the UI.
Failure mode handling¶
If the provider becomes unavailable:
- New issuance fails immediately with a
ServiceUnavailableaudit event. - Existing certs keep validating from the in-memory trust bundle, unaffected.
- CRL refresh on the existing CRL keeps serving (
nextUpdatewindow extension up to 1 hour) but does not record new revocations. - Health probe flips from green to amber (degraded) — the cluster stays up, the dashboard shows the provider as unhealthy.
Recovery is automatic — once the provider responds again, queued issuances drain.