Build Daily

Tinley Park · October 29, 2026
toolThe cert-manager project (CNCF; originally Jetstack)applied

cert-manager

The standard Kubernetes controller for X.509 certificates. Certificate and Issuer custom resources describe what is wanted; the controller generates keys, gets them signed by a CA, ACME server, Vault or a self-signed issuer, writes them to Secrets and renews them before expiry. Apache 2.0, a CNCF graduated project, free. It fits any cluster that needs internal TLS for databases and webhooks, or automated public certificates from Let's Encrypt.

Updated October 17, 2026

cert-manager issues and renews TLS certificates inside a Kubernetes cluster. A Certificate object names the DNS names, the issuer and the Secret to fill; cert-manager does the rest and keeps the Secret valid for as long as the object exists. It removes the manual step that makes certificates expire: nobody has to remember to renew. The official docs at cert-manager.io/docs own the full API reference.

What it is

Three Deployments in the cert-manager namespace, a set of CRDs in the cert-manager.io and acme.cert-manager.io API groups, and an optional cmctl CLI:

  • controller — runs the certificate, issuer, ACME and approval controllers, plus ingress-shim, which makes Certificates from annotated Ingress and Gateway objects.
  • webhook — validates and mutates cert-manager resources and serves CRD conversion.
  • cainjector — copies CA bundles into webhook configurations, CRDs and APIServices.

Licence is Apache 2.0. The project joined the CNCF Sandbox in 2020, moved to Incubating in 2022 and was announced as Graduated in November 2024. Related projects in the same organization: trust-manager (distributes CA bundles to namespaces), approver-policy (policy-based approval of certificate requests) and csi-driver (mounts certificates into pods without Secrets).

The current line is v1.21 (v1.21.2 shipped 2026-09-11; v1.20.4 is the other supported line). Releases come about every four months, each is supported until the second release after it, and only the last patch of each branch is supported. v1.22 is expected around November 2026. v1.21 supports Kubernetes 1.33 to 1.36.

v1.21 has three breaking changes, all in the Helm chart. The chart no longer creates the serviceaccounts/token Role for the controller's own ServiceAccount. The cert-manager-edit ClusterRole no longer grants create on Challenges or write access to Orders (already shipped in v1.20.3 and v1.19.6). The values prometheus.servicemonitor.targetPort, prometheus.servicemonitor.path and prometheus.podmonitor.path are removed, and the metrics port is renamed http-metrics. v1.21 also added experimental ACME Renewal Information (RFC 9773) behind the ACMEUseARI feature gate.

How it works

Everything is a custom resource. An Issuer (namespaced) or ClusterIssuer (cluster-wide) describes a signer: selfSigned, ca (a CA key pair in a Secret), acme, vault or an external issuer plugin. A Certificate describes the wanted certificate and the Secret to store it in. For each issuance the controller creates a CertificateRequest that carries the CSR. The internal approver approves requests for the built-in issuer types automatically. ACME issuers add Order and Challenge objects for the HTTP-01 or DNS-01 validation.

By default a certificate lasts 90 days and renews 2/3 of the way through its life. Since v1.18 the default privateKey.rotationPolicy is Always, so every renewal also generates a new key.

How cert-manager issues, renews and injects a certificate

Step 1 of 4. A new Certificate has no valid Secret, so the trigger controller sets the Issuing condition. The key manager generates a private key and holds it in a temporary Secret.

CA issuer path. An ACME issuer adds Order and Challenge objects between the request and the signed certificate.

cert-manager bootstraps its own webhook the same way. At startup the webhook generates a self-signed key pair, stores it in a Secret, and cainjector injects that CA from the Secret. That path does not need cert-manager's own CRDs or webhook to work first.

When to use it

Reach for it when:

  • Services inside the cluster need TLS from a private CA: databases, message brokers, admission webhooks, mTLS between services.
  • Public names need Let's Encrypt or another ACME CA, renewed with no manual step.
  • A Helm chart for another tool (Rancher, operators with webhooks) lists cert-manager as a prerequisite.
  • Certificates must come from Vault, a cloud private CA or an internal PKI through one Kubernetes API.

Skip it when:

  • All TLS terminates outside the cluster (a CDN or a cloud load balancer) and nothing inside needs a certificate.
  • The ingress controller's built-in ACME client covers the only need, and only one instance requests certificates.
  • An operator already manages its own certificates well, and a second source of truth would only add moving parts.

At a glance

Core concepts

  • Issuer / ClusterIssuer — a signer configuration. A ClusterIssuer reads its Secrets from the cluster resource namespace (cert-manager by default).
  • Certificate — the desired state: names, duration, renewBefore or renewBeforePercentage, key algorithm, secretTemplate.
  • CertificateRequest — one signing request. Its Approved, Denied and Ready conditions show where issuance stopped.
  • Order / Challenge — the ACME objects for one issuance and one domain validation.
  • ingress-shim — the cert-manager.io/cluster-issuer annotation on an Ingress or Gateway creates a Certificate for its TLS hosts.
  • cainjector annotations — cert-manager.io/inject-ca-from (a Certificate), cert-manager.io/inject-ca-from-secret (a Secret with cert-manager.io/allow-direct-injection: "true"), cert-manager.io/inject-apiserver-ca.

Key facts (v1.21)

Item Value
Licence Apache 2.0
Latest release v1.21.2 (2026-09-11)
Kubernetes 1.33 to 1.36
Support window Until the second following minor; last patch only
Default duration 90 days
Default renewal 2/3 of the duration
Default key rotation Always (since v1.18)
Default container UID/GID 65532 (since v1.20)
Chart oci://quay.io/jetstack/charts/cert-manager

Where certificates come from

Aspect cert-manager Ingress controller ACME CDN edge TLS
Covers Any Secret in the cluster Hostnames on that ingress Public hostnames on the CDN
Private CA Yes (ca, vault, external) No No
Webhook and CRD CA bundles Yes (cainjector) No No
Certificates usable by other pods Yes, as Secrets Usually not No

How to integrate

Install

helm install cert-manager oci://quay.io/jetstack/charts/cert-manager \
  --version v1.21.2 \
  --namespace cert-manager --create-namespace \
  --set crds.enabled=true

kubectl -n cert-manager rollout status deploy/cert-manager-webhook
cmctl check api --wait=2m

The legacy repo https://charts.jetstack.io still works and is updated a few hours after the OCI chart. Before an upgrade to v1.21, remove any of the deleted prometheus.* keys from the values file; the chart's schema rejects them.

Bootstrap a private CA

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: selfsigned
spec:
  selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: internal-ca
  namespace: cert-manager          # ClusterIssuers read Secrets from here
spec:
  isCA: true
  commonName: internal-ca
  subject:
    organizations: [example]       # avoid an empty issuer DN
  secretName: internal-ca
  duration: 87600h                 # 10 years
  privateKey:
    algorithm: ECDSA
    size: 256
  issuerRef:
    name: selfsigned
    kind: ClusterIssuer
    group: cert-manager.io
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: internal-ca
spec:
  ca:
    secretName: internal-ca

A server certificate from that CA

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: db-server
  namespace: data
spec:
  secretName: db-server-tls
  dnsNames:
    - db-rw.data.svc
    - db-rw.data.svc.cluster.local
  duration: 2160h                  # 90 days
  renewBeforePercentage: 33
  usages: [server auth, digital signature, key encipherment]
  issuerRef:
    name: internal-ca
    kind: ClusterIssuer

Inject a CA into a webhook

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: my-webhook
  annotations:
    cert-manager.io/inject-ca-from: my-system/my-webhook-serving-cert
webhooks: []                       # caBundle on each entry is filled in by cainjector

Check status

kubectl get certificates,certificaterequests -A
kubectl describe certificate db-server -n data
cmctl status certificate db-server -n data
cmctl renew db-server -n data        # force a renewal now

In the GL stack

cert-manager v1.21.2 runs on every cluster in the stack. Its job is in-cluster trust. It issues the certificates behind Rancher's self-signed CA flow, the TLS certificates for CloudNativePG's Postgres clusters, and the serving certificates and CA bundles for admission webhooks.

Public TLS terminates at Cloudflare. Browsers that reach paiddaily.io, sagedaily.io and the other product domains see Cloudflare's edge certificates, so no ACME issuer and no public DNS-01 credentials have to live inside a cluster. That keeps cert-manager's scope to private certificates whose clients are other services in the same stack.

Gotchas

  • The webhook must be up before anything else works. Right after install, creating an Issuer can fail with an error that calls webhook.cert-manager.io. Wait for the webhook rollout, or run cmctl check api --wait. A namespace stuck in Terminating after an uninstall usually clears with kubectl delete apiservice v1beta1.webhook.cert-manager.io.
  • CRDs outlive the release. Since v1.15 Helm keeps the CRDs on helm uninstall. Deleting the CRDs deletes every Certificate, Issuer and Order in the cluster.
  • New key on every renewal. Since v1.18 rotationPolicy: Always is the default. Anything that pins a public key needs rotationPolicy: Never set explicitly.
  • Mounted Secrets update; processes do not. The kubelet refreshes Secret volumes (not subPath mounts), but a server that reads its certificate only at startup keeps the old one until restart. Use a reloader, or a server that watches its files.
  • Self-signed issuer DN. A selfSigned certificate with no subject has an empty issuer DN, which is technically invalid. cert-manager emits a BadConfig event; set spec.subject.
  • ClusterIssuer Secrets live in one namespace. A ca ClusterIssuer looks for its Secret in the cluster resource namespace, not in the Certificate's namespace.
  • Trust distribution is a separate problem. cert-manager puts ca.crt in each Secret, but clients in other namespaces need the CA too. trust-manager, or a copy managed in Git, solves that.
  • Run v1.21.1 or later. v1.21.0 crash-looped the controller when a Certificate set renewal.policy: Disabled, and could leave Issuers stuck at InvalidSolver. Both were fixed in v1.21.1.
  • Token RBAC removed in v1.21. Issuers that use serviceAccountRef.name pointing at the controller's own ServiceAccount need their own Role for serviceaccounts/token: create, or a dedicated ServiceAccount.

Risks

  • Licence and stewardship. Apache 2.0 and CNCF graduated, with a published governance model and completed security and fuzzing audits. There is no maintainer LTS; vendors sell longer support for older lines.
  • Upgrade cadence. Each line is supported for about eight months. Skipping releases means stepping through several minors and their Helm value changes.
  • The CA key is a Secret. Anyone who can read Secrets in the cluster resource namespace can sign certificates the whole stack trusts. Restrict that RBAC as tightly as cluster-admin.
  • A webhook in the critical path. If the cert-manager webhook is down, creates and updates of cert-manager resources fail. Renewals that are already scheduled still need the controller to be up before expiry; the certmanager_certificate_expiration_timestamp_seconds metric is the alert source.

Alternatives

  • Ingress controller ACME (Traefik, Caddy) — pick it when the only need is public certificates for one ingress.
  • CDN or cloud-managed certificates (Cloudflare, AWS ACM) — pick them when TLS ends at the edge and nothing in the cluster needs its own certificate.
  • Operator-managed certificates — CloudNativePG and many operators can generate their own CA; pick that for a single operator with no wider PKI.
  • Vault or step-ca as the CA — pick them for a PKI shared beyond Kubernetes; cert-manager can still sit in front of both as the in-cluster client.

Related