Kubernetes v1.37 Turns Pod Identity From a Bearer Token Into a Certificate
Kubernetes v1.37 graduates Pod Certificates and ClusterTrustBundles to General Availability, replacing copyable bearer tokens with built-in, auto-rotated X.509 identity for pods.
Every pod in a Kubernetes cluster already gets an identity token: a service account JWT, minted by the kubelet, mounted into the container before the workload even starts. It works well enough that most clusters never think about how it works, or about its central weakness. In Kubernetes v1.37, codenamed Garhwal and released August 26, two related features that address that weakness both graduated to General Availability: Pod Certificates and ClusterTrustBundles. Together they let a pod hold an X.509 certificate instead of a bearer token, issued and automatically rotated by the kubelet, without an operator having to run a service mesh or an external certificate controller just to get workload identity.
Table Of Content
- The Problem With a Token Anyone Can Copy
- How a Pod Gets Its Own Certificate
- What identifies the request
- What the signer has to do
- Where the Trust Anchors Live: ClusterTrustBundle
- What Actually Graduated in v1.37
- Pod Certificates: three releases from alpha to stable
- ClusterTrustBundle: a much longer road
- Why This Will Not Replace Your Service Mesh
- Who Should Actually Reach for This
The graduation is explained in a Kubernetes Blog post published August 28 by Taahir Ahmed (GitHub handle ahmedtd), who wrote both enhancement proposals alongside SIG Auth contributor stlaz. Ahmed’s own summary of what shipped is direct: “Pod Certificates (and the closely-associated Cluster Trust Bundles) build X.509 certificate issuance for TLS and mTLS directly into core Kubernetes.” His assessment of the result: “The goal of Pod Certificates is to make using X.509 certificates from your Kubernetes workload just as easy as using service account JWTs, while maintaining Kubernetes’ high security bar. I think we’ve hit this target.”
The Problem With a Token Anyone Can Copy
The case for building this in starts with what a bearer token actually is: proof that you are currently holding a piece of text, not proof of anything about you. As Ahmed frames it, service account JWTs have one big downside: they are bearer tokens, and whoever holds a copy is treated as the identity it names. Because a workload has to hand that same token to every peer it authenticates to, each of those peers could, in principle, replay it elsewhere too. Kubernetes already binds service account tokens to a time window, a specific object, and an audience to blunt that risk, but by Ahmed’s own account none of those bindings are “complete defences.”
Proof-of-possession credentials solve a different problem: instead of handing over the whole secret, a workload proves it holds a private key without ever transmitting that key. X.509 certificates, the same mechanism behind every HTTPS connection, already do exactly this. The certificate is the public half, safe to pass around freely; the private key stays put and is used only to sign a proof during a TLS handshake.
How a Pod Gets Its Own Certificate
Pod Certificates work through a new certificates.k8s.io resource, PodCertificateRequest, and the delivery mechanism deliberately mirrors how service account tokens already reach a pod. The kubelet, not the application container, does the work: it generates a key pair, builds a PKCS#10 certificate signing request from it (the request’s stubPKCS10Request field), and creates a PodCertificateRequest naming a signer along with the pod, service account, and node it belongs to.
What identifies the request
Per the KEP-4317 design, the fields the kubelet fills in include:
signerName: which signer controller should handle the requestpodName/podUID,serviceAccountName/serviceAccountUID,nodeName/nodeUID: the identity being asserted, all values the kubelet already knows about the pod it is runningmaxExpirationSeconds: the longest lifetime the caller will accept for the issued certificateunverifiedUserAnnotations: free-form data a pod author can pass through to the signer implementation
The same node-restriction admission control that already stops a kubelet from vouching for pods it is not running applies here too, so a compromised node cannot request a certificate for a pod scheduled somewhere else.
What the signer has to do
A signer is just a controller watching for PodCertificateRequest objects addressed to the name it registers. Kubernetes ships no default signer; a cluster operator or a vendor has to deploy one. When a signer matches a request, it either issues a certificate by writing certificateChain, notBefore, notAfter, and beginRefreshAt to the request’s status subresource, or it rejects the request with a Denied or Failed condition. The kubelet watches for that status update, and once the time in beginRefreshAt arrives, it starts the whole request over again, so a workload’s certificate keeps rotating automatically without the pod ever restarting.
Once a certificate is issued, the private key and certificate chain land on the pod’s filesystem through a projected volume, the same delivery model service account tokens already use. In a v1.37 pod spec, that looks like:
volumes:
- name: workload-credentials
projected:
sources:
- podCertificate:
signerName: "mysigner.example/spiffe"
keyType: ED25519
credentialBundlePath: credentialbundle.pem
That example signer name is taken directly from the KEP’s own documentation, and it is not incidental. SPIFFE-shaped workload identity is clearly one of the use cases its authors had in mind, even though Pod Certificates itself has no built-in opinion on SPIFFE ID formatting; that is left entirely to whichever signer a cluster chooses to run.
Where the Trust Anchors Live: ClusterTrustBundle
Issuing a certificate only solves half the problem. Something also has to tell every other workload which certificate authorities to trust, and until now that usually meant baking a CA bundle into a container image or hand-rolling a ConfigMap. ClusterTrustBundle, the second feature that reached GA in v1.37, gives that a real API: a cluster-scoped resource whose spec.trustBundle field holds a PEM bundle of X.509 trust anchors, optionally tied to a specific spec.signerName.
Pods consume trust bundles through the same projected-volume mechanism as Pod Certificates, either by naming one bundle directly:
- clusterTrustBundle:
name: example-bundle
path: ca.pem
or by asking for every bundle that matches a signer name and a label selector, merged into a single file:
- clusterTrustBundle:
signerName: example.com/server-tls
labelSelector:
example.com/version: live
path: ca_certificates.pem
The second form matters more than it looks. It lets an operator publish a new trust anchor under a new label, wait for it to propagate to every pod that references it, and only then retire the old one, all without editing a single pod spec.
What Actually Graduated in v1.37
Neither feature is new in this release. What changed is that both feature gates were removed from Kubernetes entirely and their behavior locked on by default, according to the v1.37 changelog.
Pod Certificates: three releases from alpha to stable
Pod Certificates shipped as alpha in v1.34, reached beta in v1.35, and went stable in v1.37. The changelog entry for the graduation, credited to contributor yt2985, flags a breaking change riding along with it: the PodCertificateRequest API moved from certificates.k8s.io/v1beta1 to v1, and two fields already deprecated in the beta API, PKIXPublicKey and ProofOfPossession, are removed entirely from v1. Anything still setting those fields needs to be updated before upgrading past v1.36. As of this writing, the public API reference on kubernetes.io still documents the v1beta1 shape; the v1 reference page had not yet gone live.
ClusterTrustBundle: a much longer road
ClusterTrustBundle took far longer to reach the same point. The API itself shipped as alpha in v1.27, kubelet support for mounting it as a volume followed in v1.28, and it did not reach beta until v1.33, when a dedicated kube-apiserver-serving signer was added alongside it. Both its feature gates were then graduated to GA and enabled by default in v1.37. Getting from alpha to GA took ten Kubernetes releases, a reminder that “alpha” in Kubernetes can mean years of production hardening before a feature is considered stable enough to enable by default.
Why This Will Not Replace Your Service Mesh
The most detailed technical pushback on Pod Certificates predates the GA graduation but still lands on ground the KEP has not addressed. Writing in December 2025, while the feature was still in beta, engineer Howard John argued that Pod Certificates offers little to teams already running a service mesh like Istio. His core objection matches the mechanism described above: because the kubelet generates the key pair and writes it to the pod’s filesystem, rather than a workload process or a hardware security module ever generating or holding it directly, the security model is closer to a service account token with an asymmetric key than to a true hardware-backed credential.
John also points to a gap the KEP’s own published goals do not dispute: a PodCertificateRequest can only assert the identity of the pod that the kubelet is actually running, with no mechanism for one pod to hold certificates on behalf of other pods. That breaks the model Istio’s ambient mode depends on, where a single per-node ztunnel proxy needs a certificate for every other pod scheduled on that node, not just for itself. Teams already invested in Istio’s own certificate authority, cert-manager’s istio-csr project, or a SPIRE deployment using the SPIFFE Workload API have little reason to rip any of that out in favor of a beta-turned-stable Kubernetes primitive that cannot cover the same case.
Where Pod Certificates does help is upstream of the mesh decision entirely. It removes the excuse for skipping workload-to-workload mTLS because standing up an external certificate authority felt like too much machinery. A signer controller is still required, and Kubernetes ships none by default, but the pod-facing half, requesting a certificate and getting it rotated automatically, is now core API surface instead of a CRD, a sidecar, or a Secret an operator has to babysit by hand.
Who Should Actually Reach for This
The realistic audience is platform teams that want mTLS, or simply a credential stronger than a bearer token, between services, without adopting a full service mesh or an external certificate operator just to get it. That was already possible with tools like cert-manager’s CSI driver, which behaves similarly to Pod Certificates in day-to-day use. The difference is that a signer speaking directly to certificates.k8s.io is one less CRD-based system to install, watch for drift, and keep patched. Whether that argument actually wins depends entirely on signer implementations that, for most clusters, do not exist yet: v1.37 ships the request-and-rotation machinery on the pod side, not the certificate authority that has to sit behind it.








No Comment! Be the first one.