Error message
Unable to connect to the server: tls: failed to verify certificate: x509: certificate is valid for 10.96.0.1, 192.168.1.10, not 127.0.0.1
The address lists come from your certificate and kubeconfig. For DNS names the message reads "x509: certificate is valid for kubernetes, kubernetes.default, …, not k8s.example.com".
kubectl (client-go) — the API server address in the kubeconfig is not among the API server certificate's SANs
What it means
The API server's certificate is trusted (it chains to the cluster CA), but the address in your kubeconfig's server URL is not one of the names or IPs in its Subject Alternative Names. Go lists the IP SANs it found and the address it wanted. kubeadm issues the API server certificate for the service IP, node addresses and a few DNS names; any other way of reaching it needs an extra SAN.
Why it happens
Access through a load balancer or public IP
commonA load balancer, floating IP or NAT address in front of the control plane that was not passed as an extra SAN at kubeadm init.
SSH tunnels and port-forwards
commonReaching the API server as https://127.0.0.1:6443 through a tunnel asks for 127.0.0.1, which the certificate does not cover.
The node's IP address changed
occasionalSingle-node clusters on DHCP or VMs moved to another network keep a certificate for the old address.
How to fix it
- 1.
List the certificate's SANs
Compare them with the server URL in the kubeconfig.
bash # On a control-plane node: the names and addresses the API server certificate covers sudo openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -ext subjectAltName - 2.
Regenerate the API server certificate with extra SANs
kubeadm init phase certs apiserver issues a new certificate with --apiserver-cert-extra-sans; the old pair must be moved away first, and kube-apiserver restarted to load it.
bash # kubeadm: add the missing address/name to the API server certificate sudo mv /etc/kubernetes/pki/apiserver.{crt,key} /root/ sudo kubeadm init phase certs apiserver --apiserver-cert-extra-sans=203.0.113.20,k8s.example.com # then restart the kube-apiserver static pod (e.g. move its manifest out of /etc/kubernetes/manifests and back) - 3.
Tunnels: set tls-server-name
kubectl's tls-server-name makes it verify a name the certificate does cover while connecting to the tunnel address, instead of using insecure-skip-tls-verify.
bash # Through a tunnel or port-forward: keep verifying the name the certificate has kubectl config set-cluster my-cluster --server=https://127.0.0.1:6443 --tls-server-name=kubernetes