Microservices often communicate over internal networks, and many production systems need more than simple network connectivity. A service may need to prove its identity to another service before the connection is trusted.
Mutual TLS (mTLS) is one common way to achieve this. Instead of relying only on a bearer token or network location, both sides can authenticate using X.509 certificates.
Kubernetes 1.37 makes this easier by graduating Pod certificates and ClusterTrustBundles to Stable. Pods can receive private keys and X.509 certificate chains through projected volumes, while ClusterTrustBundles provide a Kubernetes-native mechanism for distributing trust anchors.
For .NET developers, this creates a useful foundation for certificate-based workload identity without requiring application code to generate or manually manage certificates.
What Are Kubernetes Pod Certificates?
A Pod certificate allows a workload to receive a private key and certificate chain through a projected volume.
The high-level flow is:
.NET Pod
|
| Requests workload certificate
v
Kubernetes API / Kubelet
|
v
Configured Signer
|
v
X.509 Certificate
|
v
Projected Volume
|
v
.NET Application
The application reads the certificate from the filesystem and uses it for TLS authentication.
Kubernetes handles certificate provisioning and refresh. The application is responsible for noticing certificate changes and reloading its credentials appropriately.
This is an important distinction: Kubernetes manages the lifecycle of the credential, while the application needs to consume that credential correctly.
Why Workload Identity Matters
Traditional applications often use one of several authentication approaches:
Service A
|
+-- API Key
+-- Shared Secret
+-- Bearer Token
+-- Client Certificate
Shared secrets can be difficult to rotate safely. Long-lived credentials can also create unnecessary risk if they are copied between environments.
With certificate-based workload identity:
Pod A
|
| Client Certificate
v
Pod B
|
| Validate certificate
v
Trusted Identity
The certificate becomes part of the workload's cryptographic identity.
Kubernetes introduced Pod certificates specifically to provide workloads with a mechanism for obtaining certificates through the kubelet, including automated refresh.
Pod Certificates vs ServiceAccount Tokens
ServiceAccount tokens and Pod certificates solve different problems.
| Feature | ServiceAccount Token | Pod Certificate |
|---|---|---|
| Credential type | Token | X.509 certificate |
| Primary use | Kubernetes API authentication | Certificate-based workload identity |
| mTLS support | Not directly | Yes |
| Private key | No | Yes |
| Certificate rotation | Not applicable | Kubelet-managed |
| Useful for TLS clients | Limited | Strong fit |
| Requires signer | No | Yes |
A ServiceAccount token remains useful for applications that need to authenticate to the Kubernetes API.
A Pod certificate is more appropriate when the application needs certificate-based identity for TLS or mTLS.
These mechanisms can therefore coexist.
How Pod Certificate Projection Works
A Pod requests a certificate by using a projected volume.
A simplified configuration looks like this:
apiVersion: v1
kind: Pod
metadata:
name: orders-api
spec:
serviceAccountName: orders-api
containers:
- name: orders-api
image: example/orders-api:latest
volumeMounts:
- name: workload-identity
mountPath: /var/run/workload-identity
readOnly: true
volumes:
- name: workload-identity
projected:
sources:
- podCertificate:
signerName: example.com/workload
keyType: ED25519
credentialBundlePath: credentialbundle.pem
The important configuration is:
podCertificate:
signerName: example.com/workload
The signerName identifies the signer that is expected to issue the certificate.
Kubernetes does not automatically make every arbitrary signer available. A signer controller must be deployed and configured to issue certificates for eligible Pods.
Why credentialBundlePath Is Useful
Kubernetes supports writing the private key and certificate chain separately, but it also supports a credential bundle.
For example:
credentialBundlePath: credentialbundle.pem
This is useful because the private key and certificate can rotate independently.
If an application reads:
private-key.pem
certificate.pem
as separate files, there is a possibility of reading the files during rotation and obtaining a mismatched key and certificate.
Kubernetes recommends using credentialBundlePath for applications that want to read the credentials as one consistent bundle.
Reading the Certificate in a .NET Application
A .NET application can load the certificate from the mounted filesystem.
For example:
using System.Security.Cryptography.X509Certificates;
var certificatePath =
"/var/run/workload-identity/credentialbundle.pem";
var certificate =
X509Certificate2.CreateFromPemFile(certificatePath);
However, a projected credential bundle contains both the private key and certificate chain, so the exact loading approach should match the PEM structure and certificate usage required by the application.
A more explicit approach for a PEM certificate and private key is:
using System.Security.Cryptography.X509Certificates;
var certificate =
X509Certificate2.CreateFromPemFile(
"/var/run/workload-identity/certificate.pem",
"/var/run/workload-identity/private-key.pem");
The application should also ensure that the certificate and private key belong together.
For production systems, certificate loading should be encapsulated rather than scattered throughout controllers and service classes.
Using a Client Certificate With HttpClient
Suppose a .NET service needs to call another internal service using mTLS.
The application can configure an HttpClientHandler with a client certificate:
using System.Net.Http;
using System.Security.Cryptography.X509Certificates;
var certificate =
X509Certificate2.CreateFromPemFile(
"/var/run/workload-identity/certificate.pem",
"/var/run/workload-identity/private-key.pem");
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(certificate);
using var client = new HttpClient(handler);
var response =
await client.GetAsync(
"https://payments.internal/api/orders");
The receiving service must trust the certificate's issuer and validate the client certificate according to its own authentication policy.
The certificate alone does not automatically establish trust.
What Is a ClusterTrustBundle?
A certificate is useful only when the receiving system can determine whether it trusts the certificate issuer.
This is where ClusterTrustBundle fits.
A ClusterTrustBundle is a cluster-scoped object that distributes X.509 trust anchors to workloads. Kubernetes provides a projected volume mechanism so Pods can consume those trust anchors.
The architecture becomes:
Certificate
|
| Issued by
v
Workload CA
|
| Trusted through
v
ClusterTrustBundle
|
v
.NET Service
This separates two concepts:
Identity → Pod certificate
Trust → ClusterTrustBundle
That separation is useful when designing a larger internal PKI architecture.
Configuring a Trust Bundle
A Pod can project a ClusterTrustBundle alongside its certificate.
Conceptually:
volumes:
- name: workload-identity
projected:
sources:
- podCertificate:
signerName: example.com/workload
keyType: ED25519
credentialBundlePath: credentialbundle.pem
- clusterTrustBundle:
signerName: example.com/workload
path: ca-bundle.pem
The exact trust-bundle selection depends on how the signer and trust bundle are configured.
Kubernetes supports signer-linked and signer-unlinked trust bundles, with access controlled through Kubernetes authorization mechanisms.
Certificate Rotation in .NET
One of the most important production considerations is rotation.
The kubelet refreshes projected Pod certificate credentials as they approach expiration. The application must reload the updated credentials when the mounted files change.
A common mistake is loading the certificate once when the application starts:
var certificate =
LoadCertificate();
var handler =
CreateHandler(certificate);
and then keeping that certificate indefinitely.
That can cause problems after certificate rotation.
A better architecture is to place certificate loading behind a component that can detect credential changes and refresh the HTTP/TLS client configuration when necessary.
The exact implementation depends on whether the application uses HttpClient, ASP.NET Core Kestrel, gRPC, or another networking stack.
A Simple Certificate Provider
For example:
public interface IWorkloadCertificateProvider
{
X509Certificate2 GetCertificate();
}
An implementation can encapsulate certificate loading:
public sealed class WorkloadCertificateProvider
: IWorkloadCertificateProvider
{
private readonly string _certificatePath;
private readonly string _privateKeyPath;
public WorkloadCertificateProvider(
string certificatePath,
string privateKeyPath)
{
_certificatePath = certificatePath;
_privateKeyPath = privateKeyPath;
}
public X509Certificate2 GetCertificate()
{
return X509Certificate2.CreateFromPemFile(
_certificatePath,
_privateKeyPath);
}
}
In a production implementation, this provider would also need a strategy for detecting file changes, replacing the certificate safely, and disposing of credentials that are no longer used.
Common Mistakes
Assuming a Certificate Is Automatically Trusted
Receiving a certificate does not mean another service trusts it.
The receiving application must trust the certificate's issuing CA or configured trust anchor.
Loading the Certificate Only Once
Certificates can rotate. An application that never reloads them can eventually attempt to use an expired credential.
Reading Key and Certificate Separately During Rotation
This can create a temporary mismatch between the private key and certificate.
Using credentialBundlePath provides a consistent bundle for atomic reads.
Using a Generic Signer Without Reviewing Its Policy
The signer controls which certificates it issues and under what conditions.
The Kubernetes documentation explicitly notes that signers can impose their own access requirements and may refuse certificate requests.
Treating Workload Identity as Authorization
A certificate establishes cryptographic identity. It does not automatically define what the identity is allowed to do.
Authorization still needs to be designed separately.
Troubleshooting Pod Certificates
Check the Pod
kubectl describe pod orders-api
Look for volume and mount errors.
Check the Projected Files
Inside the container:
ls -la /var/run/workload-identity
You should see the projected credential files.
Check the Certificate
openssl x509 \
-in /var/run/workload-identity/certificate.pem \
-text \
-noout
Check:
Expiration
Issuer
Subject
Subject Alternative Name
Key usage
Check the Signer
If a certificate is not being issued, verify that the configured signer controller is running and that it is authorized to issue certificates for the workload.
Check Rotation
If authentication works initially but fails later, inspect whether the application reloads the updated certificate after the projected files change.
Best Practices
Use short-lived workload certificates where appropriate.
Keep private keys inside the projected credential volume and avoid copying them elsewhere.
Use a dedicated signer for workload identity.
Define clear certificate issuance policies.
Distribute trust anchors through ClusterTrustBundles where appropriate.
Use
credentialBundlePathwhen the application needs a consistent certificate/key pair.Make .NET applications capable of reloading rotated credentials.
Separate authentication from authorization.
Monitor certificate expiration and issuance failures.
Test certificate rotation and signer failure before production deployment.
Advantages and Disadvantages
Advantages
Provides native Kubernetes support for Pod-level X.509 credentials.
Supports certificate-based workload identity.
Useful for mTLS communication.
Kubelet manages certificate refresh.
ClusterTrustBundles provide a native trust-distribution mechanism.
Reduces the need for applications to manually provision certificates.
Disadvantages
Requires a properly configured signer.
Applications still need certificate reload logic.
Certificate-based authentication adds operational complexity.
Trust configuration must be designed carefully.
Existing applications may require changes to their TLS configuration.
A certificate provides identity but does not replace authorization policies.
Conclusion
Kubernetes 1.37's graduation of Pod certificates and ClusterTrustBundles to Stable provides a stronger foundation for certificate-based workload identity. Pods can receive private keys and X.509 certificate chains through projected volumes, while trust bundles can distribute the CA information required to validate those identities.
For .NET services, the practical architecture is straightforward:
.NET Pod
|
+--> Pod Certificate
| |
| +--> Client identity
|
+--> ClusterTrustBundle
|
+--> Trusted CA
The most important production consideration is lifecycle management. The application must correctly consume and reload certificates as Kubernetes rotates them.
When implemented carefully, Pod certificates provide a clean foundation for mTLS and workload identity while keeping certificate provisioning and rotation closer to the Kubernetes platform instead of embedding credential-management logic throughout individual .NET services.

Join the conversation! Your thoughts help the community grow.