Articles

Kubernetes v1.37 Pod Certificates & Trust Bundles

Kubernetes 1.37 introduces built‑in Pod Certificates and Cluster Trust Bundles, bringing X.509 certificate issuance to core for secure TLS/mTLS. This outline covers why they matter, the architecture, issuance flow, a hands‑on Tinycert example, and how to get involved.

Written by:
APin

Senior Technology Analyst • Verified Expert

More from this author
Kubernetes v1.37 Pod Certificates & Trust Bundles

Kubernetes 1.37 introduces built‑in Pod Certificates and Cluster Trust Bundles, bringing X.509 certificate issuance to core for secure TLS/mTLS. This outline covers why they matter, the architecture, issuance flow, a hands‑on Tinycert example, and how to get involved.

Why Pod Certificates Matter

In a Kubernetes cluster the “production‑identity” problem is the need for a workload to prove who it is when it talks to external services (databases, APIs, other clusters). The control plane currently solves this with service‑account JSON Web Tokens (JWTs). A Kubelet writes a signed JWT into the pod’s filesystem, automatically rotates it, and the node‑restriction admission plugin limits token requests to the node that actually runs the pod. This mechanism is convenient and works with any system that understands JWTs.

However, service‑account JWTs are bearer tokens. Possession of the token is sufficient to act as the identity it represents. Because the token must be copied to every peer the pod contacts, any compromised peer can replay the token and impersonate the pod. The JWT format includes mitigations such as time‑binding, audience‑binding, and object‑binding, but these are not complete defenses against token theft or replay attacks.

Proof‑of‑possession (PoP) credentials eliminate this class of risk by requiring the holder to demonstrate control of a private key that never leaves the workload. X.509 certificates, the de‑facto standard for TLS and mutual TLS (mTLS), implement PoP through asymmetric cryptography: the workload keeps a private key locally (ideally generated inside the container or an HSM) and presents a signed certificate issued by a trusted Certificate Authority (CA). The verifier checks the signature against the public key in the certificate, ensuring that only the entity possessing the private key can complete the handshake.

Pod Certificates introduced in Kubernetes 1.37 embed this X.509 issuance flow directly into the platform, providing:

  • Automatic private‑key generation and rotation by Kubelet.
  • PodCertificateRequest objects that are processed by a signer controller, which returns a certificate chain and a refresh schedule.
  • ClusterTrustBundle projection so workloads can load the CA bundle without manual configuration.

By using PoP X.509 certificates, workloads gain:

  • Strong mutual authentication for both client and server roles.
  • Reduced attack surface compared to bearer tokens, because an attacker must compromise the private key, not just copy a token.
  • Compatibility with existing TLS‑based security controls required by standards such as NIST SP 800‑52 and OWASP ASVS.

Adopting Pod Certificates therefore closes the security gap left by bearer JWTs while preserving the automation and least‑privilege guarantees already provided by Kubernetes.

Architecture Overview

The Pod Certificate workflow introduces a set of tightly‑coupled components that replace the traditional service‑account JWT path with X.509‑based proof‑of‑possession credentials. Understanding each component and its responsibilities is essential before designing an application that relies on automatic TLS rotation.

Core components

  • Application pod – Declares podCertificate and clusterTrustBundle projected volumes in its spec. The workload reads the private key, certificate chain, and trust anchors from the mounted files to perform (m)TLS.
  • Kubelet – Runs on every node and acts on behalf of the pod. It generates a private key, creates a PodCertificateRequest, watches ClusterTrustBundle objects, and writes the resulting artifacts to the pod’s filesystem.
  • PodCertificateRequest – A Kubernetes API object that carries the CSR (certificate signing request) and the name of the desired signer. Kubelet populates this object; the signer controller updates its status.certificateChain and status.beginRefreshAt fields.
  • Signer controller – Implements the signing logic for a specific signer (e.g., a SPIFFE or DNS‑SAN signer). It validates the request, enforces policies such as node‑restriction, and returns a signed certificate chain.
  • ClusterTrustBundle – Holds one or more CA certificates associated with a signer. Kubelet aggregates bundles that match the signer name and label selectors, reorders them deterministically, and projects the combined trust anchors into the pod.

Interaction sequence

  1. Pod is scheduled; Kubelet discovers podCertificate and clusterTrustBundle volume sources.
  2. Kubelet generates a private key (type defined by keyType) and creates a PodCertificateRequest addressed to the configured signer.
  3. The signer controller processes the request, signs the CSR, and populates status.certificateChain and status.beginRefreshAt.
  4. Kubelet writes the private key and certificate chain to the pod’s projected volume. If the signer supports a single‑file “credential bundle,” the application can watch one path.
  5. Kubelet retrieves all matching ClusterTrustBundle objects, merges their CA certificates, and writes the unified bundle to the designated mount point.
  6. The application starts, reads the key, certificate, and trust bundle, and begins TLS handshakes. It must monitor the files (via inotify or polling) to handle rotation when beginRefreshAt is reached.

Practical example

apiVersion: v1
kind: Pod
metadata:
  name: demo
spec:
  containers:
  - name: app
    image: myapp:latest
    volumeMounts:
    - name: certs
      mountPath: /etc/tls
  volumes:
  - name: certs
    projected:
      sources:
      - podCertificate:
          signerName: ahmedtd.github.io/tinycert-spiffe
          keyType: RSA
      - clusterTrustBundle:
          signerName: ahmedtd.github.io/tinycert-spiffe
          labelSelector:
            matchLabels:
              purpose: spiffe

This manifest demonstrates how an application declares its identity requirements. Kubelet will handle key generation, request creation, bundle aggregation, and file updates without additional code in the workload.

Before adopting Pod Certificates, verify that your application can reload TLS credentials on‑the‑fly and that your security policy (e.g., NIST SP 800‑57 for key management) permits short‑lived certificates, as core signers enforce a maximum lifetime of 24 hours.

Certificate Issuance Flow

The Pod Certificates feature in Kubernetes extends the cluster’s identity model by issuing X.509 credentials instead of bearer JWTs. The flow is deliberately similar to the service‑account token pipeline, but it adds proof‑of‑possession through asymmetric keys.

  1. Key generation – When a pod is scheduled, Kubelet scans the pod spec for podCertificate volume sources. For each source it creates a private key locally, respecting the keyType field (e.g., RSA 2048 bits or ECDSA P‑256). NIST SP 800‑57 recommends these sizes for a balance of security and performance.
  2. Request creation – Kubelet builds a PodCertificateRequest object that references the signer name declared in the volume source. The request contains the public key and any requested extensions (DNS SANs, SPIFFE IDs, etc.).
  3. Signer decision – A signer controller watches the request. It validates the pod‑to‑node binding (the node‑restriction admission plugin enforces that only the node running the pod can request a certificate). If the request complies with policy, the signer populates two status fields:
    • status.certificateChain – the PEM‑encoded leaf certificate followed by intermediate CAs.
    • status.beginRefreshAt – a timestamp indicating when Kubelet should start a renewal attempt (typically a fraction of the certificate’s lifetime).
  4. Filesystem write – Kubelet retrieves the issued chain, then writes the private key and the chain to the pod’s projected volume. By default it creates a single “credential bundle” file so the application can read both artifacts atomically, avoiding race conditions during rotation.
  5. Automatic rotation – As the beginRefreshAt time passes, Kubelet repeats steps 1–4, overwriting the bundle file. Applications must watch the file (via inotify or periodic polling) and reload TLS contexts when the content changes.

Practical example: a Go microservice loads the bundle with tls.LoadX509KeyPair at startup, then registers an fsnotify.Watcher on the bundle path. On each modify event it calls tlsConfig.LoadX509KeyPair again, ensuring uninterrupted mTLS communication while the underlying certificate is refreshed automatically.

Because signers in core Kubernetes limit certificate lifetimes to 24 hours (up to 91 days for external signers), the built‑in rotation logic satisfies compliance frameworks such as SOC 2 and ISO 27001, which require periodic credential renewal and minimal exposure of long‑lived secrets.

Practical Implementation with Tinycert

Before using Tinycert, understand the two credential models it supports. A DNS‑SAN certificate contains Subject Alternative Names that match the Kubernetes Service DNS entries, enabling traditional TLS verification. A SPIFFE certificate encodes the workload’s namespace and service‑account as a spiffe:// URI, allowing workload‑level identity checks that are independent of DNS.

Installation of the Tinycert signer controller is performed with a single manifest. The controller runs as a Deployment and registers two signers with the API server:

kubectl apply -f https://github.com/ahmedtd/tinycert/releases/download/v0.1.0/tinycert.yaml

After the Deployment is ready, verify the signers:

kubectl get signers
NAME                                 TYPE
ahmedtd.github.io/tinycert-service    X509
ahmedtd.github.io/tinycert-spiffe    X509

To request a certificate, add a podCertificate volume to the pod spec and reference the desired signer. The example below requests a SPIFFE client certificate and mounts the resulting credential bundle at /certs:

apiVersion: v1
kind: Pod
metadata:
  name: spiffe-client
spec:
  containers:
  - name: app
    image: ghcr.io/ahmedtd/spiffe-demo:latest
    volumeMounts:
    - name: certs
      mountPath: /certs
  volumes:
  - name: certs
    projected:
      sources:
      - podCertificate:
          signerName: ahmedtd.github.io/tinycert-spiffe
          keyType: RSA
          path: /certs/credential.pem

The Go library github.com/ahmedtd/tinycert/lib/spiffefsd simplifies loading these files. A minimal server that enforces mutual TLS looks like:

package main

import (
    "crypto/tls"
    "log"
    "net/http"

    "github.com/ahmedtd/tinycert/lib/spiffefsd"
)

func main() {
    // Load SPIFFE cert + trust bundle from the filesystem delivery layout
    cred, err := spiffefsd.Load("/certs")
    if err != nil {
        log.Fatalf("load SPIFFE credentials: %v", err)
    }

    tlsConfig := &tls.Config{
        GetCertificate: cred.GetCertificate,
        GetClientCertificate: cred.GetClientCertificate,
        ClientAuth: tls.RequireAndVerifyClientCert,
        ClientCAs: cred.TrustPool,
    }

    srv := &http.Server{
        Addr:      ":8443",
        TLSConfig: tlsConfig,
        Handler:   http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            w.Write([]byte("mutual TLS success"))
        }),
    }

    log.Println("starting server on :8443")
    log.Fatal(srv.ListenAndServeTLS("", ""))
}

Run the companion client by mounting the same podCertificate volume with the tinycert-service signer (which provides a DNS‑SAN cert) and using the same library to configure tls.Config. The client will present its certificate, the server will verify it against the ClusterTrustBundle that Kubelet writes to /certs, and the TLS handshake will succeed.

  • Install Tinycert signer controller with kubectl apply.
  • Declare podCertificate volumes for DNS‑SAN or SPIFFE signers.
  • Use the Go spiffefsd library to load credentials and configure tls.Config.
  • Run server and client pods; Kubelet automatically rotates certificates (max 24 h for built‑in signers, up to 91 days for Tinycert).

By following these steps, engineers can integrate Kubernetes‑native X.509 identity with existing mTLS pipelines while keeping private keys inside the workload, satisfying principles of least privilege and proof‑of‑possession required by standards such as NIST SP 800‑63‑3 and OWASP ASVS.

Next Steps and Community Involvement

The introduction of Pod Certificates and Cluster Trust Bundles in Kubernetes v1.37 marks a significant evolution in production identity, moving from bearer-token reliance to X.509-based proof-of-possession credentials. For engineers looking to implement these features or extend their capabilities, the following resources provide the necessary technical foundation.

To begin integrating these identity mechanisms, consult the official Kubernetes documentation regarding Pod Certificates and Cluster Trust Bundles. Understanding the interplay between Kubelet, the PodCertificateRequest object, and the signer controller is essential for managing certificate lifecycle and rotation without manual intervention.

Active development and standardization efforts are ongoing within the community. Engineers are encouraged to contribute to the following areas:

  • SPIFFE Filesystem Delivery (Draft Standard): Review and provide technical feedback on the draft, which aims to standardize how SPIFFE certificates and trust bundles are consumed directly from the filesystem. This is critical for ensuring interoperability across different container platforms and signer implementations.
  • SIG Auth Participation: Engage with the Kubernetes Special Interest Group for Authentication (SIG Auth). This group is the primary forum for shaping the design of future built-in certificate signers, ensuring they meet the security and flexibility requirements of diverse production environments.
  • Custom Signer Development: While Kubernetes provides the machinery for issuance, the ecosystem currently relies on third-party signers. Developers should utilize Tinycert as a baseline for building custom controllers. Specifically, the lib/spiffefsd Go library serves as a reference implementation for loading SPIFFE certificates and configuring TLS libraries to support mutual authentication.

By building custom signers—such as those that provide specific DNS SANs or SPIFFE-compatible identities—you can tailor your cluster’s identity issuance to match your organization’s unique security policies while maintaining strict compatibility with the Kubelet’s projected volume integration.

Editorial Policy & Research Methodology

Our findings are based on rigorous internal research, verified industry benchmarks, and direct technical implementation experience from our enterprise client projects. All statistics and technical claims are reviewed by senior engineers before publication to ensure accuracy, transparency, and helpfulness for our readers.

Have an Idea?

Let's Build Something Amazing Together.