cert-manager: The X.509 Controller That Made TLS a Kubernetes Resource
Jetstack built cert-manager in 2017 to fix what kube-lego could not: certificates, issuers, and challenges as real Kubernetes resources. The v0.11 API rename then made every upgrading cluster uninstall and reinstall to get there.
Sources
- cert-manager/cert-manager repository (GitHub ID 92313258, created 2017-05-24; 14.1k stars, 2,487 forks as of 2026-11-07)
- Root commit 36308ae8 — 'initial commit', James Munnelly (2017-07-19)
- docs/certificate.yaml at the root commit — the first Certificate manifest ever written for cert-manager
- pkg/apis/certmanager/v1alpha1/types.go at the root commit — Certificate with embedded ACME, no Issuer type
- cert-manager v0.1.0 release notes — 'the first release of cert-manager... still not in a production ready state' (2017-10-13)
- v0.3.0 release notes — ingress-shim merged into cert-manager (#502), ACMEv1 dropped, experimental Vault issuer (2018-05-24)
- v0.6.0 release notes — ACME Order and Challenge resource types, ACME re-implemented 'completely driven by CRDs' (#788) (2019-01-22)
- v0.9.0 release notes — the CertificateRequest resource type, the issuer contract for 1.0 (2019-07-23)
- v0.11.0 release notes — API group rename to cert-manager.io; uninstall-and-reinstall upgrade path (2019-10-10)
- v1.0.0 release notes — 'a seal of trust on 3 years of development', 253 contributors, the v1 API compatibility promise (2020-09-02)
- v1.21.0 release notes — ACME Renewal Information (RFC 9773), renewal policies, three breaking Helm changes (2026-07-08)
- v1.21.3 release notes — current patch release of the v1.21 series (2026-10-23)
- jetstack/kube-lego — the annotation-driven predecessor, archived; 'no longer maintained' since PR #346 (repo created 2016-03-06)
- pkg.go.dev module docs for github.com/jetstack/cert-manager — 'loosely based upon the work of kube-lego'
- TechCrunch: Venafi acquires Jetstack, the startup behind cert-manager (2020-05-14)
- Business Wire: Jetstack donates cert-manager to CNCF Sandbox, 'a community of over 250 contributors' (2020-11-17)
- Issue #3451: Move repo to cert-manager/cert-manager — opened 2020-11-10, closed 2022-01-05
- CNCF project page: cert-manager — Sandbox 2020-11-10, Incubating 2022-09-19, Graduated 2024-09-29
- CNCF: Cloud Native Computing Foundation Announces cert-manager Graduation (KubeCon Salt Lake City, 2024-11-12)
- cert-manager.io: 'cert-manager is now a CNCF Graduated Project!' (2024-11-12)
- cert-manager.io: cert-manager completes CNCF-sponsored security audit (2024-03-18)
- Ada Logics security audit report — Adam Korczynski, David Korczynski, facilitated by OSTIF, funded by the CNCF (2024-02-17)
- CNCF TAG Security: cert-manager self-assessment (June 2024)
- CNCF TOC graduation issue #1306
- GitHub Advisory GHSA-8rvj-mm4h-c258 — high: direct ACME Challenge resources can bypass Issuer DNS01 solver policy (2026-06-25)
- GitHub Advisory GHSA-gx3x-vq4p-mhhv — medium: controller DoS via specially crafted DNS response (2026-02-02)
- trust-manager v0.26.0 — removes the compromised eMudhra roots from the default CA bundle (2026-10-27)
- Thoma Bravo press release: CyberArk completes acquisition of Venafi (2024-10-01)
- CyberArk community: the CyberArk to Palo Alto Networks transition (Palo Alto completed its CyberArk acquisition 2026-02-11)
- jetstack/jetstack-secure — open-source components of CyberArk Certificate Manager for Kubernetes (the commercial layer's repo)
- Business Wire: Jetstack launches Jetstack Secure, built on cert-manager (2021-02-08)
- cert-manager docs: the Certificate resource (v1 API, secretTemplate, renewal policies)
- cert-manager docs: ACME — the Let's Encrypt issuer with http01 and dns01 solvers
- cert-manager docs: the annotated Ingress resource (ingress-shim)
- cert-manager/webhook-example — the sample repo for building external ACME DNS01 solver webhooks (534 forks, 2026-11-07)
The default answer to "how do you get TLS certificates into Kubernetes" started as a London
consultancy's second attempt at the problem. The first attempt, kube-lego, watched Ingress
annotations and asked Let's Encrypt for certificates — and kept its state where nobody could
inspect it. The second attempt, cert-manager, made the opposite bet: certificates, issuers,
orders, and challenges would all be first-class Kubernetes resources, watchable with
kubectl describe and automatable with the same machinery that runs the
rest of the cluster. The bet required breaking the project's own API so badly in 2019 that the
official upgrade path was "back up, uninstall, reinstall" — and it still ended in a CNCF
graduation, three corporate acquisitions of the founding company, and a tool that most
clusters now install without thinking about any of this history.
The Origin: kube-lego's Limits, a Consultancy's Pain, and a CRD Bet (2016–2017)
kube-lego: the annotation-driven predecessor (2016)
The thing cert-manager replaced was also a Jetstack-era project. kube-lego, whose repository was created on and is archived today, automated the obvious 2016 problem: you annotated a Kubernetes Ingress with the domains you wanted, and kube-lego asked Let's Encrypt for a certificate and wrote it into a Secret. For a year this was the state of the art. Its ceiling was architectural: the process held issuance state in memory, exposed nothing as an API object, and offered one issuer type — Let's Encrypt, one challenge at a time. cert-manager's own README is the primary source on the lineage: the project "is loosely based upon the work of kube-lego and has borrowed some wisdom from other similar projects e.g. kube-cert" — a sentence preserved today on the Go module docs page. kube-lego was formally closed on August 26, 2021, when PR #346 updated its README "to say that the project is no longer maintained" — four years after cert-manager had taken over its user base.
The gap between the two designs is the whole story of this project, so it is worth stating plainly: kube-lego was a client of the Kubernetes API that happened to run in a cluster; cert-manager was designed as a native extension of the Kubernetes API. That difference — state in a process versus state in etcd, annotations versus resources — is what everything else in this tale follows from.
The first commit, and an apiVersion that never shipped (July 2017)
Jetstack, a London Kubernetes consultancy founded in 2015, created the repository on
under the path
jetstack-experimental/cert-manager — the name survives in the v0.1.0
release notes, which link their own quick-start guide at that old URL. The root commit landed
on , authored by James Munnelly with the
message initial commit:
36308ae8.
The scaffold is a time capsule: a single controller at
cmd/controller/main.go, API types at
pkg/apis/certmanager/v1alpha1/types.go, and — most revealing of all —
a design document posing as an example manifest at
docs/certificate.yaml.
# Example ACME certificate using DNS
apiVersion: certmanager.kubernetes.io/v1
kind: Certificate
metadata:
name: my-certificate
spec:
domains:
- www.google.com
acme:
challenge: dns-01
url: https://...
email: test@example.com
dns:
clouddns: {}
status:
state: Pending
---
# Example ACME certificate using Ingress
apiVersion: certmanager.kubernetes.io/v1
kind: Certificate
metadata:
name: my-certificate
spec:
domains:
- www.google.com
acme:
challenge: http-01
url: https://...
email: test@example.com
ingressRef:
name: something
status:
state: Pending
Two things about that file deserve a slow read. First, the
apiVersion is certmanager.kubernetes.io/v1 —
a group under kubernetes.io, and a v1 that never shipped: the public
releases opened at v1alpha1, in a
certmanager.k8s.io group. Ambition outran both the API plan and the
namespace in the first week. Second, the design is monolithic: the Certificate type
embeds its ACME configuration — the release-era
types.go
defines CertificateSpec as Domains []string
plus a ProviderConfig wrapper whose only inhabitant is
ACME *ACME. There is no Issuer kind anywhere in the root tree. The
separation of what you want (a Certificate) from how it gets signed (an
Issuer) — the idea the entire project would eventually be built on — did not exist on day
one. It arrived by v0.1.0, alongside the ClusterIssuer, in October 2017.
cert-manager/cert-manager (GitHub repo ID 92313258, created 2017-05-24)
├── root 36308ae8 "initial commit" (James Munnelly, 2017-07-19)
│ — scaffold: cmd/controller/main.go,
│ pkg/apis/certmanager/v1alpha1/types.go, docs/certificate.yaml
└── path jetstack-experimental/cert-manager (2017, per the v0.1.0 release notes)
→ jetstack/cert-manager (same repo object, renamed)
→ cert-manager/cert-manager (org move completed 2022-01-05, issue #3451)
jetstack/kube-lego (repo created 2016-03-06; 2.1k stars; archived)
└── last act PR #346 "Update README to say that the project is no
longer maintained" (merged 2021-08-26) — the predecessor
cert-manager says it was "loosely based upon"
v0.1.0: the release that admitted everything (October 2017)
The first release, published , opens with a sentence vendors do not usually ship: "It is currently still not in a production ready state, and features are subject to change." What v0.1.0 did contain was already the project's core differentiator set: ACME DNS-01 challenges with Google Cloud DNS, AWS Route53, and Cloudflare providers; HTTP-01 challenges "compatible with all ingress controllers following ingress spec (GCE & nginx tested)"; simple CA-based issuance from a Secret-held keypair; cluster-wide issuers ("aka ClusterIssuer"); and the line that separated it from kube-lego forever — "Backed by CRDs," with events written to the Kubernetes API and a status block used for state. The release notes end with a community pitch, not a roadmap: "open some issues, comment or pick something up and get started." The 38 contributors credited by v0.3.0 six months later suggest that pitch worked.
The Timeline: From a Niche CRD Controller to the Default TLS Layer
- 2016-03-06 — jetstack/kube-lego is created: Ingress annotations in, Let's Encrypt certificates out. The dominant Kubernetes TLS automation of 2016 — and state in a process, not in the API.
- 2017-05-24 — The repository object that hosts today's cert-manager/cert-manager is created as jetstack-experimental/cert-manager (GitHub ID 92313258).
- 2017-07-19 — James Munnelly's
initial commit(36308ae8): one controller, one API package, a Certificate type with ACME embedded — and an example manifest whose apiVersion (certmanager.kubernetes.io/v1) never shipped. - 2017-10-13 — v0.1.0: "still not in a production ready state." ACME DNS-01 (CloudDNS, Route53, Cloudflare), HTTP-01, CA issuers, ClusterIssuer, "Backed by CRDs."
- 2018-05-24 — v0.3.0: ingress-shim — a separate tool that turned Ingress annotations into Certificates — is merged into cert-manager itself (#502, @munnerz). ACMEv1 support is dropped outright; experimental HashiCorp Vault issuer lands (#292). Thirty-eight code contributors credited.
- 2018-09-12 — v0.5.0: the validating webhook ships (disabled by default), plus keyAlgorithm, keySize, isCA, organization fields on Certificate.
- 2019-01-22 — v0.6.0: ACME is re-implemented to be "completely driven by CRDs" (#788, @munnerz) — the Order and Challenge resource types are introduced, and every ACME authorization step becomes an inspectable Kubernetes object.
- 2019-04-14 — cert-manager/webhook-example is created — the sample repo for third-party ACME DNS01 solver webhooks. It counts 534 forks as of 2026-11-07: a whole vendor ecosystem grew out of one interface.
- 2019-07-23 — v0.9.0: the CertificateRequest resource type is introduced — "defining an API specification for Certificates and allowing anyone to implement their own issuers and CAs as first class citizens."
- 2019-10-10 — v0.11.0: the API group rename —
certmanager.k8s.io→cert-manager.io, v1alpha1 → v1alpha2, annotation prefixes renamed. The official upgrade path: back up, uninstall, rewrite every manifest, reinstall. The most violent breaking change in the project's history, paid deliberately on the road to v1. - 2020-05-14 — Venafi announces it is acquiring Jetstack, cert-manager's founding company, from the machine-identity market's incumbent side. Co-founders Matt Bates and Josh Barker join Venafi's executive team; TechCrunch notes cert-manager at "hundreds of contributors and millions of downloads."
- 2020-09-02 — v1.0.0: "a seal of trust on 3 years of development" — 1,500 issues closed by 253 contributors across 16 breaking releases ("things that needed to be broken were broken"), and a compatibility promise for the v1 API that still holds six years later.
- 2020-11-10 — cert-manager is accepted into the CNCF Sandbox — the independence move, five months after the Venafi acquisition. The same day, issue #3451 opens: move the repo out of the Jetstack org, because "operating in both the Jetstack GitHub org and the cert-manager org... has been causing certain limitations for a while now."
- 2020-11-17 — The donation is announced publicly: a community of over 250 contributors, "a foundational add-on to many Kubernetes and OpenShift clusters."
- 2021-02-08 — Jetstack Secure launches — the commercial SaaS layer over cert-manager (multi-cluster visibility, single-cluster tier free). It later becomes TLS Protect for Kubernetes, then CyberArk Certificate Manager for Kubernetes.
- 2021-08-26 — kube-lego's closure is formalized: PR #346 updates the README "to say that the project is no longer maintained." The predecessor outlived its replacement by four years, in maintenance mode.
- 2022-01-05 — Issue #3451 closes: the repository completes its move to the cert-manager GitHub org — Go import paths, Prow, Helm chart hosting, and Quay.io images all relocated as part of the foundation-run infrastructure.
- 2022-09-19 — cert-manager moves to CNCF Incubating.
- 2024-02-17 — The Ada Logics security audit report (funded by the CNCF, facilitated by OSTIF) is published: a formal threat model, eight issues raised (5 low, 2 moderate, 1 informational — all fixed by v1.12.8/v1.13.4/v1.14.3), OSS-Fuzz integration, and three low-scoring dependencies removed outright.
- 2024-09-29 — The CNCF TOC votes cert-manager Graduated — the same maturity tier as Kubernetes, Istio, Cilium, Linkerd, and SPIFFE.
- 2024-10-01 — CyberArk completes its ~$1.54B acquisition of Venafi from Thoma Bravo. Jetstack — and the commercial layer around cert-manager — are now a CyberArk business unit, days after the graduation vote.
- 2024-11-12 — Graduation announced at KubeCon Salt Lake City: "created in 2017 at Jetstack, which is now a part of Venafi, a CyberArk company," with "more than 450 contributors and issued more than 200 releases." The announcement thanks "Venafi for sponsoring the bulk of the maintainer time."
- 2026-02-02 — GHSA-gx3x-vq4p-mhhv (medium): cert-manager-controller denial of service via specially crafted DNS response — the second published advisory of the graduated era.
- 2026-06-25 — GHSA-8rvj-mm4h-c258 (high): directly created ACME Challenge resources could bypass an Issuer's DNS01 solver policy and use ClusterIssuer DNS credentials. The fix tightened the
cert-manager-editaggregate ClusterRole and shipped across three branches (v1.19.6, v1.20.3, v1.21.0). - 2026-07-08 — v1.21.0: ACME Renewal Information support (RFC 9773, behind the
ACMEUseARIfeature gate), certificate renewal policies, AWS IAM authentication for the Vault issuer, a FIPS-oriented "Modern2026" PKCS#12 profile — and three breaking Helm chart changes in one release. - 2026-10-23 / 2026-10-27 — The current normal: v1.21.3 and v1.20.5 patch releases land days apart, and trust-manager v0.26.0 ships removing the compromised eMudhra CA roots from the default trust bundle — the ecosystem's first live test of coordinated trust-bundle incident response.
Crisis Points & Architectural Pivots
Pivot one: annotations in, resources underneath (2018)
cert-manager's most-used interface today is still the one it inherited from kube-lego:
annotate an Ingress, get a certificate. The difference is what the annotation now means. In
May 2018, v0.3.0 merged ingress-shim — until then a separate tool — into
the main controller (#502, @munnerz), and renamed its flags into the process
(--ingressShim.defaultIssuerName and friends; today the Helm chart
values ingressShim.defaultIssuerName,
ingressShim.defaultIssuerKind,
ingressShim.defaultIssuerGroup). The annotation is now a thin
front-end for the resource model: ingress-shim reads it, creates or updates a
Certificate resource, and the normal issuance machinery does the rest. The
kube-lego interaction was kept alive deliberately — as a shim over a real API — which is why
the migration off kube-lego never required anyone to change a single Ingress manifest.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
# add an annotation indicating the issuer to use.
cert-manager.io/cluster-issuer: nameOfClusterIssuer
name: myIngress
namespace: myIngress
spec:
rules:
- host: example.com
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: myservice
port:
number: 80
tls: # placing a host in the TLS config determines what ends up in the cert's subjectAltNames
- hosts:
- example.com
secretName: myingress-cert # cert-manager will store the created certificate in this secret.
Pivot two: ACME state becomes API objects (2019)
The second pivot is the one that made cert-manager debuggable. In January 2019, v0.6.0
introduced the Order and Challenge resource types and, in the
release's own words, "re-implemented ACME Issuer to be completely driven by CRDs" (#788,
@munnerz). Before this, an in-flight ACME authorization was controller state; after it, every
step — the order taken against the ACME server, the challenge it demanded, the solver pod or
DNS TXT record standing behind it — became an object with events and a status you could read
with kubectl describe. The operational significance is hard to
overstate: a failed HTTP-01 challenge now fails in the same place you debug everything else,
instead of inside a controller log you have to know to fetch. It also created the surface that
2026's high-severity advisory would later land on (see the security arc below): state in the
API is inspectable by everyone, including actors you did not intend.
Pivot three: CertificateRequest — the issuer contract (2019)
In July 2019, v0.9.0 introduced the CertificateRequest resource type, described in the release notes as "a step towards where we want to be for 1.0, defining an API specification for Certificates and allowing anyone to implement their own issuers and CAs as first class citizens." The architecture that resulted — Certificate describes what you want, CertificateRequest carries the X.509 CSR to whichever issuer can sign it — did two things at once. It let new issuer types (the v0.11 notes name the Smallstep step-issuer, an experimental CSI driver for mounting certs into pods, an Istio node-agent integration, and "retrieving certificates without giving cert-manager access to your private keys") slot in without touching the core controller. And it produced a vendor ecosystem: the org's webhook-example repo — the sample for building third-party ACME DNS01 solver webhooks — counts 534 forks as of 2026-11-07. Issuers for Vault, Venafi, Google CA Service, AWS Private CA, and every regional DNS provider on earth exist because this contract exists.
2017 — v0.1: one resource, one controller, ACME embedded in the Certificate
Ingress ──► cert-manager controller ──► Let's Encrypt (ACME)
(in-memory state) └──► Secret (kubernetes.io/tls)
2019+ — the five-resource model (Order/Challenge v0.6, CertificateRequest v0.9)
Certificate (cert-manager.io/v1) created by: ingress-shim | Gateway API shim
│ spec.issuerRef | CSI driver | your manifests
▼
Issuer / ClusterIssuer type: acme | ca | selfsigned | vault | venafi | external
│ controller reconciles the Certificate into...
▼
CertificateRequest (the CSR — the issuer contract any CA can implement)
│ [acme path] │ [external issuer path]
▼ ▼
Order (acme.cert-manager.io) any controller watching
▼ CertificateRequests
Challenge
├─ http01: solver pod + service, or edit-in-place Ingress
└─ dns01: TXT record via in-tree provider or a DNS01 webhook
▼
Secret (kubernetes.io/tls) ──► Ingress / Gateway / pod mounts (CSI) /
CA injection targets (cainjector)
The v0.11 migration: the breaking change that cleared the road to v1
October 2019 is the crisis this project is built on. v0.11.0 renamed the API group from
certmanager.k8s.io to
cert-manager.io, bumped the version from v1alpha1 to v1alpha2,
removed fields deprecated in v0.8, renamed every annotation prefix, and switched the status
subresource on — all "in preparation for moving into v1beta1 and eventually v1," as the
release put it. The cost was stated without apology: "It's recommended that you backup and
completely uninstall cert-manager before re-installing the v0.11 release," followed
by a manual rewrite of every manifest's apiVersion:
Kind | Old apiVersion | New apiVersion
-------------------|-------------------------------|--------------------------------------
Certificate | certmanager.k8s.io/v1alpha1 | cert-manager.io/v1alpha2
Issuer | certmanager.k8s.io/v1alpha1 | cert-manager.io/v1alpha2
ClusterIssuer | certmanager.k8s.io/v1alpha1 | cert-manager.io/v1alpha2
CertificateRequest | certmanager.k8s.io/v1alpha1 | cert-manager.io/v1alpha2
Order | certmanager.k8s.io/v1alpha1 | acme.cert-manager.io/v1alpha2
Challenge | certmanager.k8s.io/v1alpha1 | acme.cert-manager.io/v1alpha2
The retrospective framing came a year later, in the v1.0.0 release notes: "In the past 16
releases many bugs got fixed, and things that needed to be broken were broken." That is the
honest summary of the v0.x era — eight minor lines in two years, at least four of them
carrying action-required migrations. The cure was architectural, not procedural: the
conversion webhook. v0.15.0 (May 2020) made the webhook a required component
and introduced v1alpha3 — "This change is required in order to support the upcoming changes
to our API versions, as we introduce v1alpha3, v1beta1 and v1 over the coming months!" — with
a feedback plea for firewall-rule configurations that break API-server-to-webhook traffic.
From that point, API versions changed through conversion rather than uninstall rituals:
v1beta1 arrived in v0.16.0 (#3038), and v1.0.0 (September 2020) shipped
cert-manager.io/v1 — the apiVersion still in every manifest today,
six years and ten minor versions later, exactly as the release's "compatibility promise with
our v1 API" committed.
| apiVersion | First shipped | What it cost you |
|---|---|---|
| certmanager.k8s.io/v1alpha1 | v0.1.0 (Oct 2017) | Certificate carried ACME config inline; 16 releases of action-required upgrades followed |
| cert-manager.io/v1alpha2 | v0.11.0 (Oct 2019) | Back up, uninstall, rewrite every manifest, reinstall |
| cert-manager.io/v1alpha3 | v0.15.0 (May 2020) | Webhook becomes a required component — clusters that block webhook traffic now need firewall work |
| cert-manager.io/v1beta1 | v0.16.0 (Jul 2020) | Nothing — the conversion webhook absorbs it |
| cert-manager.io/v1 | v1.0.0 (Sep 2020) | Nothing — the compatibility promise; still current as of v1.21.3 (2026) |
What you write today: the v1 API in practice
Two resources still cover the common case — a Certificate and a Let's Encrypt issuer. What changed since 2017 is the expressiveness: renewal windows on a cron schedule, key algorithm and encoding, PKCS#12/JKS keystores with named profiles, subject and name constraints. The samples below are the current documented forms.
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: example-com
namespace: sandbox
spec:
secretName: example-com-tls
dnsNames:
- example.com
issuerRef:
name: ca-issuer
kind: Issuer
duration: 2160h # 90d
renewBefore: 360h # 15d
renewal: # v1.21: renewal policies — cron-scheduled renewal windows
policy: RenewBefore
windows:
- cron: "0 2 * * 1-5"
timezone: America/Denver
windowDuration: 2h
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
email: user@example.com
server: https://acme-staging-v02.api.letsencrypt.org/directory
privateKeySecretRef:
# Secret that will store the ACME account key — "your identity with
# your ACME provider"; lose it and you cannot revoke prior certificates
name: example-issuer-account-key
solvers:
- http01:
ingress:
ingressClassName: nginx
# for split-horizon DNS / NAT hairpin environments, v1.21 added:
# waitInsteadOfSelfCheck: 30s # skip cert-manager's self-check and wait instead
# full issuance state: Certificate + CertificateRequest + events in one view
cmctl status certificate example-com
# force an immediate renewal (e.g. after a CA compromise or mis-issuance)
cmctl renew example-com
The security arc: from "no CVEs" to a graduated-era high
The project's TAG Security self-assessment (June 2024) contains a sentence that reads oddly today: "There haven't been any CVEs or notable security reports made about cert-manager." It was true — the audit-era findings were the Ada Logics report's eight issues (the most interesting: an out-of-memory denial of service from a crafted certificate subject in an alpha feature, and servers missing timeouts), all fixed across v1.12.8, v1.13.4, and v1.14.3, with the audit also folding cert-manager into Google's OSS-Fuzz and deleting three low-scoring dependencies outright (pkg/errors #6793, go-ldap/ldap #6761, gomodules/jsonpatch #6455). The audit announcement called it "the last major blocker for cert-manager's journey to graduation."
The graduated era has been more eventful. GHSA-r4pg-vg54-wxx4 (November 2024, low) flagged
a parsing DoS on crafted PEM input. GHSA-gx3x-vq4p-mhhv (February 2026, medium) was a
controller DoS via specially crafted DNS responses. And
GHSA-8rvj-mm4h-c258
(June 2026, high) is the instructive one: directly created ACME Challenge
resources could bypass an Issuer's DNS01 solver policy and use ClusterIssuer DNS credentials
— a privilege-boundary flaw enabled by the very design pivot (challenge state as API
objects) that made the project debuggable in 2019. The fix was not a revert but a tightening
of the cert-manager-edit aggregate ClusterRole, shipped
simultaneously to v1.19.6, v1.20.3, and v1.21.0 — a three-branch coordinated patch of a kind
the project had never needed before. The design lesson generalizes: every resource you add
to the API is a capability you grant to everyone with create permissions.
Worth crediting: v1.21.0's own release notes carry a known-issues section naming a
controller crash-loop triggered by renewal.policy: Disabled
(#9031 — "do not set renewal.policy: Disabled on any Certificate until this is fixed"),
cosmetic log spam from non-cert-manager Secret events (#8994), and an Issuer that can stick
at Ready: False, Reason: InvalidSolver until a 10-hour informer
resync or a spec edit (#9036). Shipping your own toil list in the release notes is the
anti-hype pattern this site wishes every project copied.
Community Engine & Corporate Influence: Who Actually Built It
The cast is smaller than Helm's merged-two-projects origin, and the corporate story is stranger. cert-manager was built at Jetstack, the London Kubernetes consultancy founded in 2015 by Matt Bates (CTO) and Josh Barker. James Munnelly — the root commit's author — carried the project architecturally from the 2017 scaffold through the v0.6 ACME rewrite, the v0.9 CertificateRequest contract, and the v0.11 migration, and the release notes' @munnerz attribution recurs on exactly those pivot PRs. The generation after him — Maël Valais and Ashley Davis authored the 2024 TAG Security self-assessment — carried the project through graduation.
The ownership chain cert-manager's maintainers rode through is four companies deep: Jetstack → Venafi (announced May 14, 2020; TechCrunch reported the deal expected to close that June, with both co-founders joining Venafi's executive team) → CyberArk (completed its ~$1.54B acquisition of Venafi from Thoma Bravo on October 1, 2024 — while the graduation process was mid-flight) → Palo Alto Networks (completed its acquisition of CyberArk on February 11, 2026). The CNCF's own graduation press release had to compress this into one clause: "created in 2017 at Jetstack, which is now a part of Venafi, a CyberArk company."
What kept a four-acquisition chain from destabilizing the project is the same move Helm
made, executed faster: foundation ownership, timed deliberately. The
Sandbox donation landed in November 2020 — six months after the Venafi acquisition, and the
org-move issue (#3451) opened the same day the donation was accepted. The graduation
announcement's thank-you list is candid about the funding asymmetry: "Venafi for sponsoring
the bulk of the maintainer time required to see this process through," and the audit
announcement repeats it — "Venafi who sponsored maintainer time to respond to and fix the
findings." The maintainer you can see doing that work today signs his trust-manager commits
as wallrj-cyberark. One company funds most of the engineering; the
foundation owns the project. That arrangement — not neutrality — is what cert-manager,
Helm (see our Helm tale), and most of the graduated
portfolio actually run on.
Scale, for the record: 601 contributors (GitHub contributors endpoint including anonymous, 2026-11-07), 14,151 stars, 2,487 forks, roughly 11,600 commits, and more than 200 releases since October 2017 — against a maintainer group small enough to fit in one Slack channel, which is the graduation blog's honest subtext when it asks readers to "reach out on Slack or join one of our regular meetings."
The sub-project family
cert-manager's architecture review increasingly happens in its satellite repos, each created to keep a concern out of the core: istio-csr (2020) signs Istio workload identities using any cert-manager issuer; approver-policy (2021) gates CertificateRequests behind approvable policy — the answer to "who may request a certificate for that name"; trust-manager (2021) distributes CA trust bundles cluster-wide — issuance and trust were split because they are different problems; cmctl (2024) became the standalone CLI at the v1.14 boundary; and the webhook-example template (2019) is where five hundred-plus DNS-provider integrations were born. The commercial layer — Jetstack Secure, launched February 2021, renamed TLS Protect for Kubernetes, now CyberArk Certificate Manager for Kubernetes — sells multi-cluster visibility and enterprise support on top of exactly this open-source core, the classic open-core split with the foundation owning the core.
Current Trajectory: The Verdict
Late 2026 cert-manager shows the metabolism of a mature graduated project: minors land
roughly every four months (v1.12 May 2023 through v1.21 July 2026, with a drift to ~5-month
spacing in 2026), patches flow on at least two lines simultaneously (v1.21.3 on October 23 and
v1.20.5 on October 28), and the June 2026 security fix shipped across three. The feature
direction is issuer-protocol maturity, not new surface: ACME Renewal Information support
(RFC 9773, behind the ACMEUseARI gate) means a Let's Encrypt
mass-revocation or CA key rollover can push renewals instead of waiting for
clients' clocks; renewal policies add cron-scheduled windows; the Modern2026 PKCS#12
profile replaces 3DES/RC2 legacy encodings for FIPS 140-3 environments; and a webhook fix
now recovers missed renewals within a minute of system suspend — a detail only a project
with laptop-cluster users would think to ship.
The most current evidence that this ecosystem earns its keep is an incident: the eMudhra CA compromise of late 2026. When the compromised roots hit the news, trust-manager v0.26.0 (October 27) shipped within days removing the eMudhra roots from the default CA bundle, rebuilt its trust-package images, and moved to a Go toolchain that distrusts the compromised intermediates (CVE-2026-111943) — while documenting bluntly that the v0.25.0 chart's default bundle still trusted them. Issuance automation (cert-manager) plus trust automation (trust-manager) is what made that response days instead of a quarter-long certificate audit. The graduation blog's forward commitments — post-quantum adoption "when standards are ready," trust-manager growth, machine-identity scale — map cleanly onto what the project actually shipped next.
Who should skip it? Teams whose TLS terminates before the cluster: if your certificates live on a managed load balancer (AWS ACM, Google-managed certificates, Cloudflare edge TLS), in-cluster issuance has nothing to issue for. Teams with locked-down platforms that prohibit admission webhooks or third-party CRDs — the conversion webhook has been required since v0.15, so this is not optional software; that firewall exception to the apiserver is part of the deployment. Teams who need workload identity rather than ingress TLS: SPIFFE/SPIRE is the right primitive, and istio-csr is the bridge if you run Istio. And teams that need trust distribution rather than issuance — pushing CA bundles to every namespace is trust-manager's job, a distinction people learn the hard way.
Verdict: cert-manager is the rare tool whose founding architectural bet — everything as
a Kubernetes resource — survived contact with reality so completely that the bet is now
invisible. The 2019 breaking migration is the reason the API you write today is
cert-manager.io/v1 and has not changed in six years; the 2020
foundation donation is the reason four corporate acquisitions never became a governance
event; the 2024 audit is the reason the 2026 high-severity fix rolled out in days across
three branches instead of becoming a community fight. For platform teams the operational
toil is real — debugging failed orders is an events-and-status ceremony, the webhook is a
hard dependency, and the RBAC surface needs review (don't let anyone create Challenge
resources) — but the alternative is the world cert-manager replaced: certificates as
untracked state, expiring on Friday nights. Install it with the Helm chart (see our
Helm tale for the packaging history), pair it with
trust-manager for bundles, monitor the Ready condition rather than expiry dates, and let
the ingress-shim annotations keep doing what kube-lego started in 2016 — now with a real
API underneath. (For the ingress machinery the HTTP-01 solver leans on, see our
Ingress NGINX tale.)