昨日まではクラスターが正常だった
いつも通り kubectl get pods を実行すると、こんなエラーが返ってきた:
Unable to connect to the server: tls: certificate signed by unknown authority
何も変えていないはずなのに。kubectlがAPIサーバーから提示された証明書を信頼できず、TLSハンドシェイクがクラスターデータを1バイトも返す前に失敗している。
原因は主に4つ考えられる: クラスターの再構築、証明書のローテーション、別マシンからkubeconfigをコピーした、またはAPIサーバーの証明書が夜間にひっそりと期限切れになっていた場合だ。
デバッグ: 問題のある証明書を特定する
ステップ1 — 実際に使用しているkubeconfigを確認する
kubectl config view --raw | grep server
echo $KUBECONFIG
KUBECONFIG環境変数が設定されていると、デフォルトの~/.kube/configより優先される。先に進む前に、正しいファイルを参照しているか確認しよう。
ステップ2 — TLS接続を直接テストする
# kubeconfigからAPIサーバーのアドレスを取得
kubectl config view --raw -o jsonpath='{.clusters[0].cluster.server}'
# opensslで直接確認
openssl s_client -connect <api-server-host>:6443 2>&1 | head -30
出力の証明書チェーンを確認する。証明書が自己署名かどうか、CN/SANフィールドの内容、正確な有効期限がわかる。
ステップ3 — 証明書の有効期限を確認する
# コントロールプレーンノード上で実行
openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -dates
# または全証明書を一括確認(kubeadmクラスターの場合)
kubeadm certs check-expiration
Not Afterの日付が過去になっている? それが原因だ。
ステップ4 — kubeconfigに埋め込まれたCA証明書を確認する
# kubeconfigからCA証明書を抽出してデコード
kubectl config view --raw -o jsonpath='{.clusters[0].cluster.certificate-authority-data}' \
| base64 -d | openssl x509 -noout -text | grep -A2 'Validity\|Issuer\|Subject'
ここに表示された発行者と、APIサーバーが実際に提示しているものを比較する。不一致があれば、kubeconfigが古くなっている証拠だ — クラスター側が更新されて、kubeconfigが取り残されている。
解決策 — 状況に合ったものを選ぶ
シナリオA: kubeconfigが古い(最もよくあるケース)
クラスターのCAまたはAPIサーバーの証明書がローテーションされたが、ローカルのkubeconfigには古いCAデータが残っている。
# コントロールプレーンノードへのSSHアクセスがある場合
scp root@<control-plane-ip>:/etc/kubernetes/admin.conf ~/.kube/config
# またはコントロールプレーン上で直接実行
cat /etc/kubernetes/admin.conf
新しいadmin.confを取得してローカルのkubeconfigと置き換える。このリストの中で最も手っ取り早い修正方法だ。
シナリオB: APIサーバーの証明書が期限切れ(kubeadm)
# 全証明書を更新
sudo kubeadm certs renew all
# 更新を確認
kubeadm certs check-expiration
# コントロールプレーンのコンポーネントを再起動して新しい証明書を反映
sudo systemctl restart kubelet
# kubeconfigを更新
sudo cp /etc/kubernetes/admin.conf ~/.kube/config
sudo chown $(id -u):$(id -g) ~/.kube/config
APIサーバーのスタティックPodは自動的に再起動される — 通常60秒以内。再起動しない場合は強制的に行う:
sudo crictl ps | grep kube-apiserver
# コンテナIDを確認してから:
sudo crictl stop <container-id>
シナリオC: 自己署名証明書が信頼されない(新規クラスター構築時)
クラスターへの初回接続で、CA証明書がkubeconfigに含まれていない場合。または生のエンドポイントURLだけを渡されて、CAバンドルが添付されていない場合。
# オプション1: CA証明書をkubeconfigに追加
kubectl config set-cluster <cluster-name> \
--certificate-authority=/path/to/ca.crt \
--embed-certs=true
# オプション2: insecure-skip-tls-verifyを使用(デバッグ時のみ・一時的な使用に限る)
kubectl --insecure-skip-tls-verify get nodes
insecure-skip-tls-verify: trueをkubeconfigに恒久的に残してはならない。このフラグは証明書の問題を解決する間、サーバーに到達できるか確認するためだけに使い、その後は必ず削除すること。
シナリオD: APIサーバーのSAN不一致
接続先のIPやホスト名が証明書のSubject Alternative Namesに記載されていない。APIサーバーの前にロードバランサーを追加した後や、コントロールプレーンノードのIPが変わった後に発生する。
# 現在の証明書がカバーするSANを確認
openssl s_client -connect <api-server-ip>:6443 2>/dev/null \
| openssl x509 -noout -text | grep -A1 'Subject Alternative'
IPやホスト名が含まれていない? 正しいSANで証明書を再発行する。kubeadmの場合:
# 既存のapiserverの証明書を削除
sudo rm /etc/kubernetes/pki/apiserver.{crt,key}
# 新しいIP/ホスト名を追加して再生成
sudo kubeadm init phase certs apiserver \
--apiserver-cert-extra-sans=<new-ip>,<new-hostname>
# kubeletを再起動
sudo systemctl restart kubelet
シナリオE: マネージドクラスター(EKS/GKE/AKS)— kubeconfigが古い
# EKS — 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>
マネージドクラスターは独自のスケジュールでCAデータをローテーションする。クラウドCLIから常に最新のkubeconfigを取得するようにしよう。マシン間でkubeconfigをコピーするのは、また同じ問題に戻る原因になる。
修正を確認する
# 基本的な接続確認
kubectl cluster-info
# TLSエラーなしでノード一覧が返ってくるはず
kubectl get nodes
# 証明書の有効性を再確認
kubeadm certs check-expiration # kubeadmクラスターの場合
kubectl cluster-infoでAPIサーバーのURLとCoreDNSの行がTLS警告なしで表示されれば、修正完了だ。
再発防止のためにリマインダーを設定する
kubeadmのデフォルト証明書有効期間は1年——365日、時間単位で正確に。自動化がなければ、最悪のタイミングで来年また同じエラーが発生する。
# コントロールプレーンノードのcrontabに追加 — 毎月証明書チェックを実行
0 9 1 * * kubeadm certs check-expiration 2>&1 | mail -s "K8s cert check" ops@yourcompany.com
# または有効期限30日前に自動更新
0 9 1 * * bash -c 'kubeadm certs check-expiration 2>&1 | grep -q "<30d" && kubeadm certs renew all'
多くのチームは四半期ごとのメンテナンス作業としてkubeadm certs renew allを実行するだけで済ませている。それでも十分だ。証明書の期限切れで深夜2時に呼び出されるよりはるかにましだろう。

