Error message
Unable to connect to the server: tls: failed to verify certificate: x509: certificate has expired or is not yet valid
Go appends both instants: "…: current time <client time> is after <notAfter>" (or "is before <notBefore>" for certificates that are not valid yet), which tells you which side is wrong.
kubectl (client-go) — the API server certificate (often after a year without kubeadm upgrades) is outside its validity period
What it means
The API server presented a certificate outside its validity period at kubectl's local time. In kubeadm clusters, control-plane certificates are issued for one year and are renewed automatically only during kubeadm upgrades, so clusters left untouched for a year fail exactly like this. A wrong clock on the client produces the same error.
Why it happens
kubeadm control-plane certificates expired after one year
commonapiserver, front-proxy and etcd certificates (and the client certificates in admin.conf) are valid for one year by default; they are renewed on kubeadm upgrade or with kubeadm certs renew.
Your kubeconfig's client certificate expired
occasionalAfter the server certificates were renewed, an old admin.conf with an expired client certificate fails authentication (with a different message, "You must be logged in to the server (Unauthorized)").
Clock skew
occasional"is before" in the full message points to a client clock behind the certificate's notBefore.
How to fix it
- 1.
List certificate expirations
kubeadm certs check-expiration shows every control-plane certificate with its remaining lifetime.
bash # On a control-plane node sudo kubeadm certs check-expiration - 2.
Renew and restart the control plane
kubeadm certs renew all writes new certificates; the static pods must be restarted to load them, and kubeconfigs with embedded client certificates must be refreshed.
bash sudo kubeadm certs renew all # restart the control-plane static pods so they load the new certificates, # then refresh your kubeconfig (the embedded client certificate was renewed too): sudo cp /etc/kubernetes/admin.conf "$HOME/.kube/config" - 3.
Check the client's time
Synchronise the clock if the full message says "is before".
bash date -u; timedatectl status | grep -i synchronized