Sửa lỗi 'tls: certificate signed by unknown authority' — kubectl Không Kết Nối Được API Server

intermediate☸️ Kubernetes2026-04-23| Kubernetes 1.20+, kubectl (mọi phiên bản), Linux/macOS/Windows, cụm kubeadm, EKS, GKE, on-prem

Error Message

Unable to connect to the server: tls: certificate signed by unknown authority
#tls#chứng chỉ#kubectl#kubeconfig#api-server#kubernetes

Cluster vẫn ổn hôm qua

Bạn chạy lệnh kubectl get pods như thường lệ và nhận được cái này:

Unable to connect to the server: tls: certificate signed by unknown authority

Không có gì thay đổi — ít nhất bạn nghĩ vậy. kubectl đang từ chối tin tưởng chứng chỉ mà API server trình bày. Quá trình bắt tay TLS thất bại trước khi một byte dữ liệu cluster nào được trả về.

Có bốn nguyên nhân thường gặp: cluster đã được xây dựng lại, chứng chỉ đã được xoay vòng, bạn sao chép kubeconfig từ máy khác, hoặc chứng chỉ API server đã hết hạn âm thầm qua đêm.

Debug: xác định chứng chỉ nào gây ra vấn đề

Bước 1 — Kiểm tra kubeconfig bạn đang thực sự dùng

kubectl config view --raw | grep server
echo $KUBECONFIG

Biến môi trường KUBECONFIG nếu được đặt sẽ ghi đè mặc định ~/.kube/config. Hãy xác nhận bạn đang xem đúng file trước khi tiếp tục.

Bước 2 — Kiểm tra kết nối TLS trực tiếp

# Lấy địa chỉ API server từ kubeconfig
kubectl config view --raw -o jsonpath='{.clusters[0].cluster.server}'

# Sau đó kiểm tra với openssl
openssl s_client -connect <api-server-host>:6443 2>&1 | head -30

Xem chuỗi chứng chỉ trong kết quả đầu ra. Nó cho thấy chứng chỉ có tự ký hay không, các trường CN/SAN là gì, và ngày hết hạn chính xác.

Bước 3 — Kiểm tra ngày hết hạn chứng chỉ

# Trên node control plane
openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -dates

# Hoặc kiểm tra tất cả chứng chỉ cùng lúc (cluster dùng kubeadm)
kubeadm certs check-expiration

Thấy ngày Not After đã qua? Đó là thủ phạm của bạn.

Bước 4 — Kiểm tra CA cert nhúng trong kubeconfig

# Trích xuất và giải mã CA cert từ kubeconfig
kubectl config view --raw -o jsonpath='{.clusters[0].cluster.certificate-authority-data}' \
  | base64 -d | openssl x509 -noout -text | grep -A2 'Validity\|Issuer\|Subject'

So sánh issuer ở đây với những gì API server đang thực sự trình bày. Nếu không khớp nghĩa là kubeconfig đã cũ — cluster đã thay đổi mà không có nó.

Giải pháp — chọn cái phù hợp với tình huống của bạn

Tình huống A: Kubeconfig đã cũ (phổ biến nhất)

CA hoặc chứng chỉ API server của cluster đã được xoay vòng, nhưng kubeconfig cục bộ của bạn vẫn còn dữ liệu CA cũ.

# Nếu bạn có quyền truy cập SSH vào node control plane
scp root@<control-plane-ip>:/etc/kubernetes/admin.conf ~/.kube/config

# Hoặc trực tiếp trên control plane
cat /etc/kubernetes/admin.conf

Lấy admin.conf mới và thay thế kubeconfig cục bộ của bạn. Đây là cách sửa nhanh nhất trong danh sách này.

Tình huống B: Chứng chỉ API server đã hết hạn (kubeadm)

# Gia hạn tất cả chứng chỉ
sudo kubeadm certs renew all

# Xác minh việc gia hạn
kubeadm certs check-expiration

# Khởi động lại các thành phần control plane để nhận chứng chỉ mới
sudo systemctl restart kubelet

# Làm mới kubeconfig
sudo cp /etc/kubernetes/admin.conf ~/.kube/config
sudo chown $(id -u):$(id -g) ~/.kube/config

Các static pod của API server sẽ tự động khởi động lại — thường trong vòng 60 giây. Nếu chúng không khởi động, hãy buộc khởi động lại:

sudo crictl ps | grep kube-apiserver
# Ghi lại container ID, sau đó:
sudo crictl stop <container-id>

Tình huống C: Chứng chỉ tự ký không được tin tưởng (thiết lập cluster mới)

Kết nối lần đầu đến cluster và CA cert không có trong kubeconfig của bạn. Hoặc ai đó đưa cho bạn một URL endpoint thô không kèm CA bundle.

# Tùy chọn 1: Thêm CA cert vào kubeconfig
kubectl config set-cluster <cluster-name> \
  --certificate-authority=/path/to/ca.crt \
  --embed-certs=true

# Tùy chọn 2: Dùng insecure-skip-tls-verify (CHỈ ĐỂ DEBUG TẠM THỜI)
kubectl --insecure-skip-tls-verify get nodes

Đừng để insecure-skip-tls-verify: true trong kubeconfig một cách vĩnh viễn. Chỉ dùng cờ này để xác nhận server có thể kết nối được trong khi bạn giải quyết vấn đề chứng chỉ — sau đó xóa nó đi.

Tình huống D: SAN của API server không khớp

IP hoặc hostname bạn đang kết nối không có trong Subject Alternative Names của chứng chỉ. Điều này xảy ra sau khi thêm load balancer phía trước API server, hoặc sau khi node control plane nhận IP mới.

# Kiểm tra các SAN mà chứng chỉ hiện tại bao gồm
openssl s_client -connect <api-server-ip>:6443 2>/dev/null \
  | openssl x509 -noout -text | grep -A1 'Subject Alternative'

IP hoặc hostname bị thiếu? Hãy cấp lại chứng chỉ với các SAN đúng. Với kubeadm:

# Xóa chứng chỉ apiserver hiện có
sudo rm /etc/kubernetes/pki/apiserver.{crt,key}

# Thêm IP/hostname mới và tạo lại
sudo kubeadm init phase certs apiserver \
  --apiserver-cert-extra-sans=<new-ip>,<new-hostname>

# Khởi động lại kubelet
sudo systemctl restart kubelet

Tình huống E: Cluster được quản lý (EKS/GKE/AKS) — kubeconfig cũ

# EKS — làm mới kubeconfig
aws eks update-kubeconfig --name <cluster-name> --region <region>

# GKE
gcloud container clusters get-credentials <cluster-name> --zone <zone>

# AKS
az aks get-credentials --resource-group <rg> --name <cluster-name>

Các cluster được quản lý tự xoay vòng dữ liệu CA theo lịch riêng của chúng. Luôn lấy kubeconfig mới từ cloud CLI. Việc sao chép kubeconfig giữa các máy chính là lý do bạn lại rơi vào tình huống này.

Xác minh bản sửa lỗi

# Kiểm tra kết nối cơ bản
kubectl cluster-info

# Nên trả về danh sách node mà không có lỗi TLS
kubectl get nodes

# Kiểm tra lại tính hợp lệ của chứng chỉ
kubeadm certs check-expiration  # nếu là cluster kubeadm

Khi kubectl cluster-info hiển thị URL của API server và dòng CoreDNS mà không có cảnh báo TLS, bạn đã xong.

Đặt nhắc nhở trước khi nó xảy ra lần nữa

Thời hạn mặc định của chứng chỉ kubeadm là 1 năm — 365 ngày, tính đến từng giờ. Nếu không có tự động hóa, lỗi này sẽ quay lại vào năm sau vào thời điểm tệ nhất có thể.

# Thêm vào crontab trên node control plane — chạy kiểm tra chứng chỉ hàng tháng
0 9 1 * * kubeadm certs check-expiration 2>&1 | mail -s "K8s cert check" ops@yourcompany.com

# Hoặc thiết lập tự động gia hạn 30 ngày trước khi hết hạn
0 9 1 * * bash -c 'kubeadm certs check-expiration 2>&1 | grep -q "<30d" && kubeadm certs renew all'

Nhiều team chỉ đơn giản chạy kubeadm certs renew all trong cửa sổ bảo trì hàng quý và coi như xong. Cách đó cũng hiệu quả. Cả hai đều tốt hơn là bị gọi lúc 2 giờ sáng vì một chứng chỉ đã hết hạn.

Related Error Notes