Skip to content

mTLS & PKI

Ampora is its own internal Certificate Authority for agent client certificates. There is no need to provision agent certs with cert-manager, Vault PKI, or your corporate CA — Ampora bootstraps the CA on first start, issues leaves on demand, and persists every key under the configured key protector.

If you would rather plug an external CA in, see Security → HSM/KMS integration — the same abstraction (ICryptoProvider) lets the CA delegate signing to AWS KMS, Azure Key Vault, GCP KMS, PKCS#11, or HashiCorp Vault Transit.

What Ampora signs

Object Issued by Lifetime (default)
Agent client certs Persisted CA 365 days
OCSP responder cert Persisted CA 90 days
Federation client certs Operator-issued from the same CA 90 days

The Ampora server's server TLS — the cert your operators see in the browser address bar — is not signed by Ampora. That is your job (cert-manager, your corporate CA, ACME, etc.) and lives on the reverse proxy.

Bootstrapping the CA

On first start with no CaSigningKey rows present, Ampora:

  1. Generates a new RSA-3072 key pair (configurable; ECDSA-P-256 supported too).
  2. Wraps the private key with IKeyProtector (AES-GCM-256 by default; HSM/KMS if configured) and persists it as a Draft CaSigningKey.
  3. Promotes that key to Active immediately so the server can issue.
  4. Issues the OCSP responder certificate.

You can pre-bake a CA from outside (import a PFX, paste a key from your HSM) before first start to avoid the auto-bootstrap. See Certificate rotation.

Issuing agent certs

Agent certs are issued during the bootstrap-token redemption flow:

sequenceDiagram
    Agent->>Ampora: WS upgrade with Authorization: Bearer <bootstrap-token>
    Ampora->>Ampora: validate token (single-use, TTL, tenant-scope)
    Ampora->>Ampora: generate key pair, sign cert via active CA
    Ampora-->>Agent: ConnectionSettings { cert, key, ca-bundle }
    Agent->>Agent: re-connect with mTLS
    Agent->>Ampora: WS upgrade with mTLS client cert

The cert subject CN is the agent's instance_uid, the SAN includes a DNS and URI form (urn:ampora:agent:<id>), and the EKU is clientAuth. The CRL Distribution Point and OCSP Responder URL embedded in every cert come from the corresponding settings:

  • CertificateAuthority:CrlDistributionPointhttps://AMPORA_HOST/pki/crl.der (Ampora's own endpoint).
  • CertificateAuthority:OcspResponderUrlhttps://AMPORA_HOST/pki/ocsp (Ampora's own endpoint, also signed by the active CA).

Trust bundle

GET /pki/trust-bundle.pem returns the active + trusted CA leaves as a PEM chain. Trusted-but-not-active means previously active — kept in the bundle for one configurable window (CertificateAuthority:DefaultTrustedWindowDays) so agents that already have a cert signed by the previous active key still validate after a rotation.

Agents pull the trust bundle once during bootstrap and cache it locally. If you rotate the CA, agents pick up the new bundle on their next bootstrap (e.g. on first connect after a cert renewal). For zero-touch agent-side rotation, ship the trust bundle via your config-management tool too.

Signing-key rotation

Driven through the Settings → PKI → Signing keys UI or the equivalent admin API:

Endpoint Purpose
GET /pki/signing-keys List keys with status
POST /pki/signing-keys Create a new Draft key
POST /pki/signing-keys/{id}/activate Promote DraftActive; the previous active becomes Trusted
POST /pki/signing-keys/{id}/retire TrustedRetired after the trusted window expires

Lifecycle states:

Draft → Active → Trusted → Retired
  • Draft: created but not yet issuing.
  • Active: the single key currently issuing new certs.
  • Trusted: previously active, no longer issuing, but its leaves still validate. Kept in the trust bundle until the configured window expires.
  • Retired: deactivated, removed from the trust bundle. Existing leaves signed by it stop validating.

The activate operation is atomic: there is exactly one Active row at a time, and the previous Active is moved to Trusted with a TrustedUntilUtc = now + DefaultTrustedWindow.

Walkthroughs and operational guidance:

Revocation

Two mechanisms ship out of the box and complement each other:

  • CRLGET /pki/crl.{der,pem}, refreshed every 60 seconds, with nextUpdate 15 minutes in the future. Cached at the HTTP layer with a matching Cache-Control header.
  • OCSPPOST /pki/ocsp (RFC 6960). Stapled responses are 4 hours fresh; clients that do not cache will hit the responder per validation.

Mutual exclusion is not required — clients (including the OpenTelemetry Collector) typically prefer OCSP and fall back to CRL.

Inspecting an agent's certificate

From the agent side, the cert lives wherever your collector stores it (the opamp_extension writes it under its data directory). From the server side:

  • The Ampora Identities page lists every issued cert with subject CN, fingerprint, issuance time, expiry, status and the bound agent.
  • The audit log records every issuance, renewal and revocation with the signing key that produced it.
  • Leaf lifetime: 365 days. Long enough to avoid rotation churn, short enough that a stolen cert has a hard expiry.
  • Active window: indefinite. Rotate when a key is compromised, when your compliance window says so, or when you switch from software to HSM-backed.
  • Trusted window: 30 days. Long enough to tolerate stragglers, short enough that a previous active key cannot validate new agents for a quarter.
  • CRL nextUpdate: 15 minutes. Short enough that a revocation propagates fast, long enough that scrapers do not flood the endpoint.
  • OCSP staple lifetime: 4 hours. Balances freshness and load.