Skip to content

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:Sign
  • kms:Verify
  • kms:GetPublicKey
  • kms: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):

  1. Configure the provider as above.
  2. Start Ampora.
  3. Settings → PKI → Signing keys → Import HSM key. Provide the provider's key reference and the cert chain.
  4. The new row lands in Draft with the public key derived from the HSM and no private material in the database.
  5. Activate as usual.

If the HSM key does not yet exist:

  1. Configure the provider.
  2. Start Ampora.
  3. Settings → PKI → Signing keys → Create. Ampora calls the provider to generate a new key inside the HSM/KMS.
  4. The row lands in Draft with KeyHandle = <provider-specific>.
  5. 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 ServiceUnavailable audit event.
  • Existing certs keep validating from the in-memory trust bundle, unaffected.
  • CRL refresh on the existing CRL keeps serving (nextUpdate window 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.