Platforms and DevOps
kubectl: x509 certificate signed by unknown authority fix
Unable to connect to the server: x509: certificate signed by unknown authorityUnable to connect to the server: x509: certificate signed by unknown authority means kubectl could not verify the API server's certificate with the CA in your kubeconfig. Usually the kubeconfig is out of date after a rebuild or CA rotation, points at the wrong cluster, or a proxy or load balancer presents a different certificate.
Newer kubectl versions print tls: failed to verify certificate: x509: certificate signed by unknown authority; it is the same error.
Quick fix
A fresh kubeconfig from the cluster fixes most cases.
Compare the CA your kubeconfig trusts with the certificate the server presents, using the commands below or the certificate decoder:
# CA in the current context's kubeconfig
kubectl config view --minify --raw -o jsonpath='{.clusters[0].cluster.certificate-authority-data}' \
| base64 -d | openssl x509 -noout -subject -fingerprint -sha256
# Server URL and the certificate chain it presents
kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}'; echo
openssl s_client -connect 203.0.113.10:6443 -showcerts </dev/null | grep -E 's:|i:'
If the server certificate's issuer is not the CA from your kubeconfig, get a fresh kubeconfig:
- kubeadm: copy
/etc/kubernetes/admin.conffrom a control-plane node to~/.kube/config. - Managed clusters: download the kubeconfig again from the provider's console or CLI.
- You only have the CA file: embed it into the cluster entry:
kubectl config set-cluster my-cluster --certificate-authority=ca.crt --embed-certs=true
Causes
A stale kubeconfig after a cluster rebuild or CA rotation is the most common cause.
1. Stale kubeconfig after rebuild or CA rotation
- Confirm: fingerprints differ between the kubeconfig CA and the server's issuing CA; the cluster was recently reinstalled.
- Fix: replace the kubeconfig as above. Kubeconfigs on CI runners and colleagues' laptops are stale too.
2. Wrong context or merged kubeconfig
With several clusters in one file, or KUBECONFIG listing multiple files, a cluster entry can end up with another cluster's CA.
- Confirm:
kubectl config current-contextandkubectl config view --minifyshow which cluster entry is used. - Fix: switch context with
kubectl config use-context, or fix the cluster entry.
3. Proxy in the path
kubectl honours HTTPS_PROXY. A TLS-inspecting corporate proxy replaces the API server certificate with its own.
- Confirm:
env | grep -i proxy; the issuer inopenssl s_client(run from the same shell) names the proxy. - Fix: add the API server address to
NO_PROXYso kubectl connects directly.
4. TLS-terminating load balancer
If a load balancer in front of the API server presents its own certificate, kubectl sees a certificate the cluster CA did not sign.
- Fix: use TCP (layer-4) pass-through for port 6443 so the API server's own certificate reaches the client, or point the kubeconfig at the balancer's CA (client-certificate authentication will then not work through a terminating balancer).
Fixes by environment
Every fix gives kubectl the cluster's current CA, the root certificate that signed the API server certificate; only the place to get it differs.
kubeadm: the cluster CA is /etc/kubernetes/pki/ca.crt. admin.conf embeds it, together with an admin client certificate.
Managed Kubernetes: regenerate credentials with the provider's tool (for example the cloud CLI's "get credentials" command) rather than editing CA data by hand.
Pods and webhooks inside the cluster: a similar error from the API server when calling an admission webhook means the webhook's caBundle does not match its serving certificate. If cert-manager manages it, check the Certificate resource; see cert-manager certificate not ready.
Other Go tools: Helm, k9s, Lens and Terraform's Kubernetes provider read the same kubeconfig, so one fix covers all of them. For the general Go error, see x509: certificate signed by unknown authority.
Don't do this
kubectl --insecure-skip-tls-verifyorinsecure-skip-tls-verify: truein kubeconfig. Your client certificate or token goes to whoever answers, and these credentials are usually cluster-admin.- Deleting
certificate-authority-datato fall back to the system store. The cluster CA is private, so this fails, and it invites trusting a public CA for an internal endpoint. - Sharing one admin kubeconfig by chat or e-mail to work around per-user setup. Generate per-user credentials instead.
FAQ
Does kubectl use the system CA store?
Not when the kubeconfig cluster entry has certificate-authority-data or certificate-authority, which is the normal case. Then only that CA is trusted for the API server. Adding the cluster CA to the OS store does not help; fix the kubeconfig.
I rebuilt the cluster with kubeadm and now kubectl fails. Why?
kubeadm reset followed by kubeadm init generates a new cluster CA, but your ~/.kube/config still contains the old one. Copy the new /etc/kubernetes/admin.conf from the control-plane node.
The error says certificate is valid for 10.96.0.1, not 203.0.113.10. Same problem?
No. That is a name mismatch: you connect through an address that is not in the API server certificate's SANs. Connect with a listed name, or add the address to the API server certificate SANs (kubeadm: apiServer.certSANs) and regenerate the certificate.
Is insecure-skip-tls-verify acceptable for a dev cluster?
It is risky even there: your kubeconfig sends a client certificate or bearer token, and without server verification anyone in the path can capture it and act as a cluster admin. Fetch the correct CA instead; it takes a minute.