Self-hosted enterprise CLM · No telemetry · Runs where the internet does not

Know every certificate, who holds its key, and what breaks before it expires.

CertSafe is certificate lifecycle management that runs on your own hosts. One Go gateway is the only public surface. Private keys live in OpenBao, HashiCorp Vault or a cloud KMS, never in Postgres. Every reading on screen is computed from the record when you open it, so nothing on the screen is a stored verdict that stopped being true.

$docker compose up -d
keys ∉ postgresA key row holds a reference into the secrets backend, never bytes.
mTLS + HMAC hopThe backend refuses any request the gateway did not sign.
0 outbound callsUnless you configured one. No licence check leaves the host.
https://certsafe.cde.internal:8443/queue licence · enterprise · 2027-10-28

What needs a person today

One decision at a time, hardest deadline first. Keys work while this panel has focus.

The four questions

A certificate list answers "what expires when". That is the one question that never caused the outage.

Most tools email you thirty days out and leave you guessing which host, which key and which flow are involved. CertSafe is built around the four questions an operator actually asks at 3am.

Q · who actually holds the private key?

Custody without compromise

Postgres holds metadata and a reference. The key itself is sealed in the backend you already trust. Export is an audited workflow: a reason of at least ten characters, N distinct approvers who are never the requester, a one-time grant whose only persisted form is a SHA-256, redeemed once under a conditional update.

Postgres · metadata
certificates · parsed X.509, public PEMkeys · custody_mode, sensitivitykey_ref → "kv/certsafe/keys/4f1c…"key_export_requests · approvals
Secrets backend · key material
OpenBaoHashiCorp VaultAWS Secrets ManagerGCP Secret ManagerAzure Key Vault
on_host · edge agent, 0600customer_held · never receiveddiscard · returned once
  • Envelope sealing: every generated key can be sealed to a recipient public key whose private half CertSafe does not hold. There is no unseal function in the code, and a test fails if one appears.
  • Two refusals, kept apart: "no material" is absolute and no role overrides it; "restricted" accepts the request and raises the bar to an administrator.
  • Break-glass is a setting, on by default, never silent: its own audit action, its own confirmation, visible on the request afterwards.
Q · what is actually on the hosts?

Discovery v2 and an edge agent you can read in five minutes

certsafe-agent.py is one file of the Python 3 standard library, generated with your choices written into its configuration block, shipped with its SHA-256, a hardened systemd unit and an hourly timer. A walk opens no network connection. It never opens a file named as a key.

certsafe-agent.py · sha256 9c41…e7b2stdlib only · 0 deps
# enrol: one token, any number of hosts
$ CERTSAFE_AGENT_TOKEN=csa_… ./certsafe-agent.py --once
# key made on the host, 0600; the CSR alone leaves
$ ./certsafe-agent.py --request-csr --cn web-pay-03.internal \
    --key-out /etc/ssl/private/web-pay-03.key
# signed? pull it, check it matches the key, install
$ ./certsafe-agent.py --pull-csr 1f2e --key-out KEY_FILE
exit 3  still unsigned, nothing written
  • Three permission models: unprivileged, ssl_group or root. No SSH, no root shell handed to a vendor.
  • The unit runs with PrivateNetwork, IPAddressDeny=any and ProtectSystem=strict; only the CSR and pull paths may reach the gateway.
  • A body that says PRIVATE KEY is refused with 422 before anything is read. The server sends the agent no command, only certificate text and a path it compares.
  • Every walk records what it touched and skipped per path. A path the agent was refused is a gap in the evidence pack, not an empty result.
Q · what breaks if this goes wrong?

Blast radius first, then a two-person deployment

Before anything destructive, a certificate's record lists every mapped device bound to it, every documented data flow with a hop onto one of those devices, and every discovery place that found it on disk without a map binding. It also says, on every certificate, what the list cannot contain.

1 · AskOne certificate, one pinned SSH host, dev / staging / production, a playbook path on a saved git target. Asking runs nothing.
2 · Rehearseansible-playbook --check. Dry run · nothing changed. Output stored redacted.
3 · ApproveAnother operator, with a reason. The asker cannot answer their own ask. Holds 24 hours.
Refused inputsinclude, import, roles, local_action, delegate_to. Nothing typed at run time.
  • The run reads the playbook again, checks the host's pinned key, and passes two fixed extra variables: the PEM and the key path. The key is a 0600 temp file removed when the run ends.
  • Exit 0 writes one deployment record and says only that. Any other exit is a failed run. One run per host at a time.
  • Publishing a PEM to git is the same shape: ask, a second person approves, one commit through the forge's API writes the certificate alone.
Q · what is arriving from outside?

Shorter lifetimes, authority renewal windows, and crypto agility

Public TLS lifetimes are heading toward 47 days. CertSafe reads each ACME authority's suggested renewal window (RFC 9773, ARI) hourly and renews at the earlier of your setting and the authority's start, so an authority asking for early renewal after an incident gets it. Scheme mandates and root retirements are recorded as advisories and matched against the live estate on every read.

1,284RSA 2048
412ECDSA P-256
318RSA 4096
27unreadable key
  • /agility counts algorithms from the stored PEMs on read, keeps unreadable keys apart, and lists the migration blockers somebody recorded under their name. Nothing is inferred from a name.
  • /drills keeps every compromise drill with a stopwatch on each step, the step that overran, and the next due date.
  • /advisories: a notice with a source, a deadline and an issuer, algorithm or name pattern. A dismissal hides it for a day; it returns while anything still matches.
Architecture & custody

Built for teams that assume the container network is hostile.

One public listener. Every hop behind it authenticated twice. Click a component to read what it refuses.

No telemetry, no phone-home

The licence is verified offline with an Ed25519 public key baked into the gateway image. The only outbound calls are the ones an operator saved: an ACME directory, a DNS API, a discovery target, a git forge. A test fails if the Ask modules import an HTTP client.

Phishing-resistant sign-in first

WebAuthn security keys with AAGUID allow-listing and a signature counter that is checked and advanced; a counter that goes backwards is refused and recorded. TOTP, per-account and unknown-address lockout parity, Argon2id password history, an HttpOnly sliding session cookie, CSP and HSTS.

Evidence an assessor verifies offline

A print-first evidence pack: gaps counted at the front and detailed at the back, estate by recorded scope, documented flows, what endpoints were observed serving (protocol, cipher and signature hash read off the wire for PCI DSS v4.0 Req 4.2.1), custody, policy exceptions. The append-only audit trail exports signed with an Ed25519 key whose public half sits on Settings → Audit, and forwards over RFC 5424 syslog.

Never "compliant"

Whether the record adds up to compliance is an assessor's judgement, not a return value. The product does not use the word, and a test reads the source to keep it that way. What you get is the observation, the decision, and who made it.

How it compares

Four ways teams run certificates today.

An honest table. Where CertSafe does not do something, the cell says so.

Legacy enterprise PKI suiteCloud-hosted SaaS CLMScripts and a spreadsheetCertSafe Enterprise
Where it runsYour data centre, after a professional-services engagement measured in monthsTheir cloud. Your topology, hostnames and expiry dates leave the buildingWherever the author left itYour hosts, from one compose file. Air-gapped CDE included
Where private keys liveVendor HSM or vendor database, opaque agent on every hostOften uploaded for "convenience"Beside the certificate, mode 0644, in a repo somewhereNever in Postgres. OpenBao, Vault, AWS, GCP, Azure, or on the host via the agent
The agentClosed binary, root, vendor-signedClosed binary, outbound beaconcron and opensslOne readable Python file, stdlib only, SHA-256 published, unprivileged by default
Blast radius before a changeRarelyNoNoYes: devices bound, flows named, found on disk unmapped, and what it cannot see
Two-person controlSometimes, via ticketsRole-based, single approverNoneKey export, PEM publish, playbook apply, high-sensitivity reveal. The asker never approves
TelemetryLicence server call-homeEverythingNoneNone. Offline Ed25519 licence
Appliance install (F5, JKS, ACS)Adapters for mostSomeHand-writtenNot built. An approved Ansible run against one pinned host, or the edge agent's pull
HSM-backed CA signingYesVendor-heldNoNo PKCS#11 signer today. CA keys live in the secrets backend; envelope recipients may be HSM-held
Natural-language searchNoLLM over your data, in their cloudgrepFixed grammar, compiled on screen, zero outbound calls
Time to first valueQuartersDays, after procurement reviews the data flowAlready there, until the author leavesAn afternoon: compose up, enrol an agent, read the queue

Comparisons describe categories, not named products. Every cell in the last column is backed by a feature entry and a test in the repository, including the two that say "not built".

Licensing

One codebase. No community edition with the good parts removed.

Every deployment runs the full enterprise code. A licence is a signed file with an expiry and a certificate cap, verified offline by the gateway. A trial is that same licence with a short expiry, not missing features.

30-day evaluation

FreeFull feature set. Your hosts, your staging VPC, or a laptop.
  • Signed .lic with --days 30 and a certificate cap for your estate
  • Compose bundle, dev OpenBao included
  • Every issuer, every custody backend, the edge agent
  • Written answers from solutions engineering during the trial
Request a trial licence

Enterprise Standard

Per estate bandCertificate cap on the licence. Quoted in writing, renewed yearly.
  • OpenBao, Vault, AWS, GCP or Azure custody; envelope sealing
  • Private CA with CRLs, ACME with ARI over DNS-01 and HTTP-01, CSR templates
  • Discovery over directories, SSH, Kubernetes, git, AWS Certificate Manager, TLS endpoints and the edge agent
  • Approved Ansible apply with rehearsal; approved PEM publish to git
  • Policy, evidence pack, signed audit export, syslog forwarding
  • Standard support, next business day
Book an architecture review

Enterprise Regulated

Unlimited estateFor payment processors, banks and sovereign environments.
  • No certificate cap on the licence
  • Your own licence issuer key, generated on your workstation, never on the host
  • Restore rehearsal run with your unseal-share holders on a scratch host
  • Dedicated architect channel on your Slack or Teams
  • Custom SLA and a named assessor liaison for PCI DSS v4.0 evidence
  • Roadmap input on HSM signing and appliance adapters
Talk to procurement
Verify any licence yourself, offline, from the gateway container: docker compose exec gateway certsafe-gateway license show. It prints customer, tier, cap, expiry and instance id from the same function the API answers, and nothing of the signature or the key.
Offline licence verifier →
Talk to an engineer

Book an architecture review, or start a trial on your own hosts.

You will talk to the people who wrote the custody code. No SDR sequence, no discovery call before the technical call.

Architecture review · 30 minYour estate on a whiteboard: custody backend, gateway placement, which hosts get the agent, what the evidence pack would say today.
Trial licence · same business dayAn offline-signed .lic and a compose bundle. The licence names your instance id, so nothing phones home to check it.
Security and procurementArchitecture and security model documents, the threat model, the SBOM for every image, and a security contact at security@certsafe.com.
Prefer emailsales@certsafe.com
Enter a work email address.
Your name, so the engineer knows who to write to.
Needed for the licence's customer field.
The cap on the trial licence is set from this.
Pick the closest. "Evaluating" is fine.
Tells us whether the bundle needs to ship without a registry pull.
Your details go to solutions engineering only. No marketing automation, no third-party enrichment.