Certified Kubernetes Administrator (CKA) #8 証明書管理: PKI、kubeconfig、証明書更新
#7 etcd バックアップと復旧 でクラスターの状態を守る方法を扱ったなら、今回はクラスターのすべての通信を支える TLS 証明書 を扱います。Kubernetes でコンポーネント同士がやり取りする通信はすべて TLS で暗号化され、相互認証されます。kubectl が apiserver を呼ぶときも、apiserver が etcd を呼ぶときも、kubelet が apiserver に報告するときも、証明書が身元を証明します。
問題は、この証明書に 有効期間 があるという点です。kubeadm が発行する証明書はほとんど 1 年がデフォルトで、期限が切れるとコンポーネント同士が互いを信頼できなくなり、クラスターが丸ごと止まります。kubectl が急に効かなくなり、control plane が立ち上がれなくなります。CKA で証明書管理は Cluster Architecture ドメインの核心であり、Troubleshooting でよく出る落とし穴でもあるので、この記事で PKI 構造と更新手順を手に覚えさせます。
クラスターは巨大な PKI である #
Kubernetes クラスターはそれ自体が一つの PKI (Public Key Infrastructure) です。すべてのコンポーネントが証明書で身元を証明し、その証明書を発行して署名した CA (Certificate Authority) を共通して信頼することで互いを信頼します。CA はすなわち信頼の根です。apiserver が「このリクエストを送った kubelet は本当に kubelet なのか」を判断するとき、その kubelet の証明書がクラスター CA で署名されているかを確認します。
この構造で証明書は二種類の役割を同時に果たします。
- サーバー証明書。apiserver のように接続を受ける側が「自分が本当にそのサーバーだ」を証明します
- クライアント証明書。kubelet や controller-manager のように接続をかける側が「自分が誰だ」を証明します
apiserver は他のすべてのコンポーネントが経由する関門なので、サーバー証明書とクライアント証明書を両方持ちます。apiserver はクライアントたちにはサーバーですが、etcd にはクライアントだからです。
PKI ディレクトリ構造 #
kubeadm でインストールしたクラスターの証明書はすべて control plane ノードの /etc/kubernetes/pki/ に集まっています。このディレクトリを一度覚えておけば試験で迷いません。
ls -1 /etc/kubernetes/pki/ca.crt # クラスタールート CA 証明書 (信頼の根)
ca.key # ルート CA 秘密鍵 (これで他の証明書を署名)
apiserver.crt # apiserver サーバー証明書
apiserver.key
apiserver-kubelet-client.crt # apiserver が kubelet を呼ぶときに使うクライアント証明書
apiserver-kubelet-client.key
front-proxy-ca.crt # aggregation layer 用の CA
front-proxy-client.crt
sa.key # ServiceAccount トークン署名用のキーペア
sa.pub
etcd/ # etcd 専用の証明書ディレクトリetcd/ の中には etcd 自体の CA と証明書が別に入っています。etcd はクラスターで最も機密性の高いデータを持っているので、別の信頼体系を使います。
ls -1 /etc/kubernetes/pki/etcd/ca.crt # etcd 専用 CA
ca.key
server.crt # etcd サーバー証明書
server.key
peer.crt # etcd メンバー同士の通信用
peer.key
apiserver-etcd-client.crt # apiserver が etcd に接続するときに使うクライアント証明書誰が誰を信頼するか #
証明書のファイル名を見るだけで信頼関係が読み取れます。核心は 誰がどの CA で署名され、相手がその CA を信頼するか です。
| 通信 | クライアント | サーバー | 署名 CA |
|---|---|---|---|
| kubectl → apiserver | admin 証明書 | apiserver.crt | ca.crt |
| kubelet → apiserver | kubelet 証明書 | apiserver.crt | ca.crt |
| apiserver → kubelet | apiserver-kubelet-client | kubelet サーバー証明書 | ca.crt |
| apiserver → etcd | apiserver-etcd-client | etcd/server.crt | etcd/ca.crt |
| etcd ↔ etcd | etcd/peer | etcd/peer | etcd/ca.crt |
ここで重要な点は etcd が別の CA を使うという事実です。apiserver が etcd に接続するには etcd CA で署名されたクライアント証明書が必要です。だから apiserver-etcd-client.crt はクラスター CA ではなく etcd CA で署名されます。
証明書の中身を直接覗く #
openssl で証明書を 1 枚開いてみると、上の関係が目に入ってきます。CKA ではこのコマンドで期限と身元 (Subject) を確認することが多いです。
openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -text出力で見るべき三か所です。
- Subject。この証明書が誰を証明するか (例:
CN=kube-apiserver) - Issuer。誰が署名したか (
CN=kubernetes、つまりクラスター CA) - Validity。
Not BeforeとNot After。このNot Afterが期限の時刻
クライアント証明書では Subject の CN と O (Organization) が特に重要です。Kubernetes は CN をユーザー名として、O をグループとして解釈します。たとえば CN=jane, O=dev で署名された証明書で接続すると、apiserver はそのリクエストを jane ユーザー、dev グループのリクエストとして認識します。このマッピングが #9 RBAC で権限付与の出発点になります。
kubeconfig: 証明書を持ち歩く財布 #
証明書ファイルがクラスターの身元証明だとすれば、kubeconfig はその証明を持ってどのクラスターにどの身分で接続するかをまとめておく設定ファイルです。kubectl も、controller-manager も、scheduler も、すべて kubeconfig を通して apiserver に接続します。
kubeconfig は三つのブロックと、それをまとめる context で構成されます。
- clusters。apiserver アドレス (
server) とそのサーバーを検証する CA (certificate-authority-data) - users。接続する身元。クライアント証明書 (
client-certificate-data+client-key-data) やトークン - contexts。どの cluster にどの user で、どの namespace で接続するかをまとめた組み合わせ
# 現在の kubeconfig 全体を見る (機密データは隠して)
k config view
# 現在アクティブな context
k config current-context
# context の一覧
k config get-contextscontrol plane の kubeconfig ファイル #
kubeadm は control plane コンポーネントが使う kubeconfig を /etc/kubernetes/ に作っておきます。これらのファイルも中に証明書を抱えているので、一緒に更新の対象 になります。
ls -1 /etc/kubernetes/*.confadmin.conf # クラスター管理者 (kubectl) 用。通常 ~/.kube/config にコピー
controller-manager.conf # kube-controller-manager が apiserver に接続するとき
scheduler.conf # kube-scheduler が apiserver に接続するとき
kubelet.conf # ノードの kubelet が apiserver に接続するとき
super-admin.conf # 非常用の管理者 kubeconfig (最新の kubeadm)admin.conf の中のクライアント証明書は CN=kubernetes-admin, O=system:masters で署名されています。system:masters グループは RBAC を迂回する事実上の最高権限グループなので、このファイルはすなわちクラスター全体に対するマスターキーです。だから admin.conf はむやみにコピーしたり露出させたりしてはいけません。
# ~/.kube/config は通常 admin.conf をコピーしたもの
sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config証明書の期限確認 #
CKA で証明書の問題はたいてい「kubectl が効かない、原因を見つけて直せ」という形で出ます。最初のステップは常に 期限切れの確認 です。kubeadm が専用コマンドを提供します。
kubeadm certs check-expirationCERTIFICATE EXPIRES RESIDUAL TIME EXTERNALLY MANAGED
admin.conf Jun 06, 2027 09:00 UTC 364d no
apiserver Jun 06, 2027 09:00 UTC 364d no
apiserver-etcd-client Jun 06, 2027 09:00 UTC 364d no
apiserver-kubelet-client Jun 06, 2027 09:00 UTC 364d no
controller-manager.conf Jun 06, 2027 09:00 UTC 364d no
scheduler.conf Jun 06, 2027 09:00 UTC 364d no
etcd-server Jun 06, 2027 09:00 UTC 364d no
...
CERTIFICATE AUTHORITY EXPIRES RESIDUAL TIME
ca Jun 04, 2035 09:00 UTC 9y
etcd-ca Jun 04, 2035 09:00 UTC 9yここで二つを読み取ります。個別の証明書 はたいてい 1 年 (RESIDUAL TIME が短い) で、CA は 10 年とずっと長いです。つまり定期的に更新しなければならないのは個別の証明書で、CA はクラスターの寿命の間ほとんど触りません。
kubeadm コマンドを使えない状況 (apiserver がすでに死んでいる場合など) では、openssl で直接確認します。
# 期限だけ素早く
openssl x509 -enddate -noout -in /etc/kubernetes/pki/apiserver.crt
# notAfter=Jun 6 09:00:00 2027 GMT
# 複数の証明書を一度に
for f in /etc/kubernetes/pki/*.crt; do
echo "$f"
openssl x509 -enddate -noout -in "$f"
done証明書の更新 #
期限が迫っているか、すでに過ぎているなら kubeadm certs renew で更新します。最もよく使う形はすべての証明書を一度に更新することです。
# kubeadm 管理のすべての証明書を一度に更新
kubeadm certs renew allcertificate embedded in the kubeconfig file for the admin to use renewed
certificate for serving the Kubernetes API renewed
certificate the apiserver uses to access etcd renewed
certificate for the API server to connect to kubelet renewed
...
Done renewing certificates. You must restart the kube-apiserver,
kube-controller-manager, kube-scheduler and etcd, so that they can use the new certificates.最後の行を見逃してはいけません。更新だけでは終わりません。 control plane コンポーネントは起動時に証明書をメモリに読み込むので、ディスクの証明書を新しいものに入れ替えても、再起動するまでは古い証明書をそのまま持ち続けます。
control plane の再起動: マニフェストを少しの間移す #
control plane コンポーネントは static Pod として動いています (この動作原理は #2 で扱いました)。static Pod は kubelet が /etc/kubernetes/manifests/ のマニフェストを監視し、ファイルができれば立ち上げ、消えれば落とすという方式で動作します。だからマニフェストを少しの間別の場所に移してから戻すと、コンポーネントがきれいに再起動されます。
# マニフェストを少しの間外に移す → kubelet が static Pod を落とす
mv /etc/kubernetes/manifests /etc/kubernetes/manifests.bak
# コンポーネントがすべて落ちるまで少し待ってから戻す
mv /etc/kubernetes/manifests.bak /etc/kubernetes/manifestsマニフェストを戻すと kubelet が再び static Pod を立ち上げ、このとき新しい証明書を読み込みます。単に kubelet 自体を再起動するだけでは static Pod が再び立ち上がらないことがあるので、マニフェストを移す方式が最も確実です。
更新後は ~/.kube/config も新しい admin 証明書で再びコピーしないと、kubectl が新しい身元で接続しません。
sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 更新が反映されたか再確認
kubeadm certs check-expirationkubelet 証明書は自動更新される #
control plane 証明書と違い、kubelet のクライアント証明書はたいてい自動で更新 されます。kubelet 設定の rotateCertificates: true (デフォルト値) がオンになっていれば、kubelet が期限が近づいたとき自ら新しい証明書を要求して入れ替えます。だから kubeadm certs renew の対象には kubelet のクライアント証明書が含まれません。
# kubelet 設定で自動更新の有無を確認
grep rotateCertificates /var/lib/kubelet/config.yaml
# rotateCertificates: true
# kubelet が持っている現在の証明書
ls -l /var/lib/kubelet/pki/この自動更新のおかげで、ノードが複数あっても kubelet 証明書を一つひとつ更新する必要がありません。ただし自動更新が動作するには kubelet が apiserver と通信できなければならないので、ノードが長く落ちていて証明書が期限切れのまま戻ってくると更新が阻まれることがあります。
ユーザー証明書の発行: CertificateSigningRequest #
新しい管理者や開発者にクラスターへのアクセスを与えるには、その人の分のクライアント証明書を発行する必要があります。直接 CA キーで署名することもできますが、Kubernetes はこれを API で処理する CertificateSigningRequest (CSR) リソースを提供します。ユーザーが CSR を提出すると管理者が承認し、クラスターが署名した証明書を返すという流れです。
# 1) 秘密鍵と CSR を生成 (ユーザー側)
openssl genrsa -out jane.key 2048
openssl req -new -key jane.key -out jane.csr -subj "/CN=jane/O=dev"ここで CN=jane はユーザー名、O=dev はグループになります。この身元がそのまま RBAC の主体になります。
# 2) CertificateSigningRequest を提出
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: jane-csr
spec:
request: <jane.csr を base64 -w0 でエンコードした値>
signerName: kubernetes.io/kube-apiserver-client
usages:
- client authrequest には cat jane.csr | base64 -w0 の結果を入れます。signerName は発行する証明書の用途を指定し、一般ユーザーのクライアント証明書には kubernetes.io/kube-apiserver-client を使います。
# 3) 提出された CSR を確認 → 承認
k get csr
k certificate approve jane-csr
# 4) 署名された証明書を取り出す
k get csr jane-csr -o jsonpath='{.status.certificate}' | base64 -d > jane.crt承認直後に CSR の状態が Approved,Issued に変わり、.status.certificate に署名された証明書が base64 で入ります。これを取り出して jane.crt として保存すると、jane のクライアント証明書が完成します。
# 5) jane の kubeconfig を構成
k config set-credentials jane \
--client-certificate=jane.crt --client-key=jane.key --embed-certs=true
k config set-context jane-context --cluster=kubernetes --user=janeここまでは jane が 誰なのか を証明する段階までです。jane が実際に何ができるかは RoleBinding で権限をまとめてあげて初めて決まります。認証 (authentication) と認可 (authorization) は別物であり、認可側の RBAC は #9 で詳しく扱います。間違って作った CSR を片付けるときは k certificate deny で拒否するか k delete csr <名前> で削除します。
よくはまる落とし穴 #
証明書作業で点数を取りこぼす箇所はほぼ決まっています。
- 期限切れの証明書では kubectl が効かない。 apiserver が死ぬかクライアント証明書が期限切れになると、
kubectlがUnauthorizedや接続拒否で阻まれます。このときは kubectl ではなくopensslとkubeadm certsでディスクの証明書を直接確認するのが出発点です。 - 更新後の再起動漏れ。
kubeadm certs renew allだけを回して control plane を再起動しないと、コンポーネントが古い証明書を使い続けます。マニフェストを移して static Pod を必ず立て直さなければなりません。 - admin.conf のコピー漏れ。 更新後に
~/.kube/configを新しい admin.conf で再びコピーしないと、kubectl が依然として古い証明書で接続しようとして失敗します。 - CSR の承認忘れ。 CSR を提出だけして
k certificate approveを抜かすと証明書が発行されません。状態がPendingかApproved,Issuedか必ず確認します。 - CN/O のタイプミス。 ユーザー名とグループは証明書の Subject に刻まれて署名されるので、発行後には変えられません。CSR を作るとき
-subjの CN と O を正確に書きます。
試験のポイント #
/etc/kubernetes/pki/の構成を覚えます。ca.crt/ca.keyが信頼の根であり、etcd はetcd/配下に別の CA を置きます。- kubeconfig は clusters + users + contexts の組み合わせであり、
k config viewで構造を、k config current-contextで現在の身元を確認します。 - 期限確認は
kubeadm certs check-expirationが基本で、apiserver が死んでいればopenssl x509 -enddate -noout -in <ファイル>で直接見ます。 - 更新は
kubeadm certs renew all→ マニフェストを移して control plane を再起動 →~/.kube/configの再コピー、の 3 段階で覚えます。 - kubelet 証明書は
rotateCertificatesで自動更新されるので、別途の作業は通常必要ありません。 - ユーザー証明書は CSR を提出し
k certificate approveで承認したあと、.status.certificateを取り出して使います。身元 (CN/O) が RBAC の主体になります。
まとめ #
この記事で押さえたこと:
- クラスターは巨大な PKI であり、すべての通信は CA で署名された証明書で相互認証する TLS です。
- PKI ディレクトリ
/etc/kubernetes/pki/に CA とコンポーネント別の証明書が集まっており、etcd は別の CA を使います。 - kubeconfig は clusters/users/contexts で身元と接続先をまとめ、control plane は
*.confファイルで apiserver に接続します。 - 期限確認 は
kubeadm certs check-expirationとopenssl、更新 はkubeadm certs renew allのあとの control plane 再起動が対になります。 - ユーザー証明書 は CSR の提出と承認で発行し、認証と認可は別物です。
次へ: RBAC #
証明書で「誰なのか」を証明する方法を身につけました。次はその身元がクラスターで「何ができるか」を決める番です。
#9 RBAC では、Role と ClusterRole で権限のまとまりを定義し、RoleBinding と ClusterRoleBinding でユーザー・グループ・ServiceAccount にその権限を結びつける方法、そして kubectl auth can-i で権限を検証する方法まで、自分で作りながら整理します。この記事で作った jane が実際に仕事をできるようにする段階です。