Kubernetes Certificates & TLS Explained: What Really Happens in the Backend
A beginner-friendly guide to how Kubernetes uses TLS certificates to secure your cluster. Learn what the CA is, which components get certificates, how mutual TLS works, and what happens behind the scenes from a security point of view.
TL;DR: Every component in a Kubernetes cluster proves who it is using TLS certificates signed by a trusted Certificate Authority (CA). This guide explains, in plain English, what a certificate is, who issues them, which parts of the cluster use them, and exactly what happens in the backend when one component talks to another securely.
You’re New to Kubernetes. Let’s Talk About Trust.
A Kubernetes cluster is a group of machines constantly talking to each other. The kubelet on a worker node talks to the API server. The API server talks to etcd. The scheduler talks to the API server. These conversations carry powerful instructions — “create this pod,” “delete that node,” “read every secret.”
Now the scary question: how does the API server know that the thing claiming to be a kubelet is actually a real kubelet, and not an attacker? If anyone could pretend to be a cluster component, the whole system would be wide open.
The answer is TLS certificates. Kubernetes expects that all API communication in the cluster is encrypted by default with TLS, and the certificates needed are created and distributed to the cluster components at install time. This post explains how that works, from zero.
First, Three Plain-English Definitions
Before we touch Kubernetes, let’s nail three words. Skip nothing here — the rest of the post depends on these.
TLS is the same technology behind the padlock in your browser (the “S” in HTTPS). It does two jobs: it encrypts the conversation so nobody can eavesdrop, and it lets each side verify who the other is.
A certificate is like a digital ID card. It says “I am kubelet-node-1” and is stamped by an authority everyone trusts. Technically it’s an X.509 certificate — just a file containing a public key plus some identity details, signed by a CA.
A Certificate Authority (CA) is the trusted stamp-issuer. It’s the boss everyone agrees to believe. If the CA signs your ID card, every component in the cluster will trust it. If your card isn’t signed by the cluster’s CA, you’re rejected instantly. The CA is the single root of trust for the entire cluster.
Hold onto that last idea: whoever controls the CA’s private key can mint an ID for anyone. That’s why protecting the CA key is the most important security job in the cluster.
Why Does This Matter? (The Security Point of View)
Here’s the part most beginners miss. A certificate in Kubernetes doesn’t just say “trust me” — it actually carries your identity and your permissions group inside it.
When a certificate is created, two fields matter enormously:
- CN (Common Name) = your username
- O (Organization) = your group
So when the API server checks your certificate, it reads the CN to learn who you are and the O to learn what group you belong to. It then hands that identity to RBAC (Role-Based Access Control), which decides what you’re allowed to do.
This is the whole security model in one sentence: the certificate answers “who are you?” and RBAC answers “what can you do?” Authentication first, authorization second. A valid certificate gets you in the door; RBAC decides which rooms you can enter.
How It Works: The Cluster’s PKI
PKI (Public Key Infrastructure) is just the fancy name for “the CA plus all the certificates it signs.” When you install a cluster with kubeadm, it automatically generates this whole structure and stores most certificates in /etc/kubernetes/pki.
Here’s the mental model:
+------------------------+
| Cluster Root CA | <- the trusted stamp
| (ca.crt + ca.key) |
+-----------+------------+
| signs every ID below
+---------------+----------------+
| | |
v v v
API server kubelet certs etcd certs
(serving + (one per node, (server + peer,
client to client to mutual TLS)
etcd) API server)
|
v
scheduler, controller-manager, kube-proxy
(each gets a client cert to talk to the API server)
Every arrow in a real cluster is a TLS connection, and every component holds a certificate signed by that one root CA. Let’s look at who gets what.
Who Gets a Certificate, and Why
| Component | Certificate it holds | Used to… |
|---|---|---|
| kubelet (each node) | Client cert | Authenticate to the API server as that node |
| API server | Serving cert + client cert | Serve HTTPS to everyone; authenticate to etcd |
| etcd | Server + peer certs | Encrypt + verify all database traffic (mutual TLS) |
| controller-manager | Client cert | Securely talk to the API server |
| scheduler | Client cert | Securely talk to the API server |
| kube-proxy | Client cert | Authenticate to the API server |
There’s also a special service account key pair (sa.key / sa.pub). This one isn’t a certificate — it’s the key used to sign the tokens that your pods use to talk to the API server. Which brings us to an important distinction.
Two Kinds of Identity: Certs vs Tokens
Beginners often blur these. Keep them separate:
- Certificates identify infrastructure and humans — nodes, the control plane components, and cluster admins.
- Service account tokens identify workloads — the pods you deploy. Each pod gets a token, not a certificate, to prove its identity to the API server.
Both are checked by the API server. They’re just two different ID formats for two different kinds of caller.
What Actually Happens in the Backend (Mutual TLS)
Let’s trace one real conversation: the API server talking to etcd, the database that holds the entire cluster’s state.
This is the most sensitive link in the cluster, because write access to etcd is equivalent to gaining root on the entire cluster. So Kubernetes protects it with mutual TLS (mTLS) — meaning both sides must show a valid ID, not just one.
Step by step, here’s what happens in the backend:
- The API server opens a connection to etcd and says “let’s speak TLS.”
- etcd presents its server certificate. The API server checks: “Is this signed by the CA I trust?” Yes → good.
- The API server presents its own client certificate. etcd checks: “Is this signed by a CA I trust, and is this client allowed?” etcd is configured with
--client-cert-auth, so it verifies the client’s certificate before allowing any access. - Both sides are now satisfied they’re talking to a trusted partner. An encrypted channel is established.
- Only now does any actual data — your secrets, configs, pod definitions — flow across the wire, fully encrypted.
If an attacker tried to connect to etcd without a certificate signed by the trusted CA, step 3 fails and the connection is dropped. No valid ID, no entry. That’s the entire defense, and it’s beautifully simple.
The same mutual handshake protects the API-server-to-kubelet link and etcd’s internal member-to-member (“peer”) traffic.
Hands-On: See and Create Certificates Yourself
1. Look at your cluster’s PKI
On a kubeadm control-plane node:
ls -l /etc/kubernetes/pki
# You'll see: ca.crt, ca.key, apiserver.crt, apiserver.key,
# apiserver-etcd-client.crt, front-proxy-ca.crt, sa.key, sa.pub, etc.
Inspect what’s inside a certificate — notice the CN and O fields that become your identity:
openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -subject -dates
# subject=CN = kube-apiserver
# notBefore / notAfter <- the expiry window
2. Issue a certificate for a new human user
This is the official way to give a teammate cluster access. Kubernetes provides a certificates.k8s.io API that issues certificates signed by a CA you control.
# (a) Create a private key - keep this secret!
openssl genrsa -out myuser.key 3072
# (b) Create a CSR. CN becomes the username, O becomes the group.
openssl req -new -key myuser.key -out myuser.csr -subj "/CN=myuser/O=developers"
Now submit it to the cluster as a CertificateSigningRequest:
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: myuser
spec:
request: <base64-encoded contents of myuser.csr>
signerName: kubernetes.io/kube-apiserver-client
usages:
- client auth
An administrator then reviews and approves it — nothing gets signed automatically:
kubectl get csr # see pending requests
kubectl certificate approve myuser # a human approves
That approval step is a deliberate security gate: the signing controller waits until a request is flagged “Approved” by a privileged user before issuing anything.
3. Check when your certificates expire
kubeadm certs check-expiration
Client certificates generated by kubeadm expire after 1 year by default. Renew them with:
kubeadm certs renew all # then restart the control plane pods
Common Pitfalls
- Ignoring certificate expiry. Kubeadm client certs last one year. If they expire, the control plane stops trusting itself and the cluster breaks. Check expiry on a schedule and automate renewal.
- Treating etcd casually. Read or write access to etcd is effectively cluster-admin. Always use mutual TLS to etcd and firewall it so only the API server can reach it.
- Leaving the CA key lying around. Anyone with
ca.keycan forge an ID for any identity, including a cluster admin. Lock it down; consider an external CA that keeps the key off the API server. - Confusing user auth with pod auth. Humans and nodes use certificates; pods use service account tokens. Don’t try to hand certificates to your workloads — use a separately generated CA distributed via a ConfigMap if your apps need their own TLS.
- Auto-approving every CSR. The approval step exists to stop unauthorized identities from joining. Don’t bypass it without understanding what you’re signing.
When to Use What
| Need | Use |
|---|---|
| Give a human admin/dev cluster access | Client certificate via the CSR API |
| Let a pod talk to the API server | Service account token (automatic) |
| Secure control-plane component traffic | Certificates from the cluster CA (automatic with kubeadm) |
| App-to-app TLS for your own workloads | A separate CA you generate, not the cluster root CA |
| Many users, central identity | OIDC / LDAP integration instead of per-user certs |
Key Takeaways
- Kubernetes encrypts all internal API traffic with TLS by default.
- A single Certificate Authority (CA) is the root of trust; it signs an ID for every component.
- A certificate’s CN = username and O = group — this is the identity RBAC then authorizes.
- Certificate = who you are; RBAC = what you can do. Authentication then authorization.
- The most sensitive links (API server ↔ etcd, API server ↔ kubelet) use mutual TLS: both sides must show a trusted ID.
- Certificates identify nodes, control-plane components, and humans; service account tokens identify pods.
- Protect the CA private key above all else, isolate etcd, and rotate certificates before they expire.
Further Reading
- Kubernetes — PKI certificates and requirements: https://kubernetes.io/docs/setup/best-practices/certificates/
- Kubernetes — Manage TLS Certificates in a Cluster: https://kubernetes.io/docs/tasks/tls/managing-tls-in-a-cluster/
- Kubernetes — Issue a Certificate for a Kubernetes API Client (CSR): https://kubernetes.io/docs/tasks/tls/certificate-issue-client-csr/
- Kubernetes — Certificate Management with kubeadm: https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/kubeadm-certs/
- Kubernetes — Securing a Cluster: https://kubernetes.io/docs/tasks/administer-cluster/securing-a-cluster/