Featured image of post kubeconfigにベタ書きされたclient-certificate-dataをファイル化して使う

kubeconfigにベタ書きされたclient-certificate-dataをファイル化して使う

それはそう

冷静に考えれば大したことないんだけどちょっと詰まったので一応メモ.


まとめ

kubeconfigにベタ書きされているclient-certificate-data(クライアント証明書)とclient-key-data(秘密鍵)はbase64デコードするとファイルとして普通に使える.

# kubeconfigにベタ書きされたクライアント証明書(client.crt)と秘密鍵(client.key)をファイルに出力する
$ kubectl config view --minify --raw -o jsonpath='{.users[].user.client-certificate-data}' | base64 --decode > client.crt
$ kubectl config view --minify --raw -o jsonpath='{.users[].user.client-key-data}' | base64 --decode > client.key

# kubectlじゃなくてもOK
## awkでやるパターン
$ cat ~/.kube/config | grep client-certificate-data | awk '{print $2}' | base64 --decode > client.crt
$ cat ~/.kube/config | grep client-key-data | awk '{print $2}' | base64 --decode > client.key
## yqつかうパターン
$ cat ~/.kube/config | yq r - "users[*].user.client-certificate-data" | base64 --decode > client.crt
$ cat ~/.kube/config | yq r - "users[*].user.client-key-data" | base64 --decode > client.key

# クライアント証明書(client.crt)と秘密鍵(client.key)を使ってcurlでKubernetes APIにアクセス
$ curl --insecure --cert ./client.crt --key ./client.key https://<Kubernetes API>

環境

やりかた

Docker Desktopで作ったKubernetesクラスタへのクライアント認証の情報は~/.kube/config(kubeconfig)に自動でベタ書きされている.

# client-certificate-data : クライアント証明書
# client-key-data : クライアントの秘密鍵
$ kubectl config view --minify --raw
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS0t...Cg==
    server: https://kubernetes.docker.internal:6443
  name: docker-desktop
contexts:
- context:
    cluster: docker-desktop
    user: docker-desktop
  name: docker-desktop
current-context: docker-desktop
kind: Config
preferences: {}
users:
- name: docker-desktop
  user:
    client-certificate-data: LS0t...LS0K
    client-key-data: LS0t...Cg==

このクラスタのAPIへcurlで接続しようとすると, クライアント認証で弾かれてしまう.

# k8s API側がオレオレ証明書なので --insecure が必要
$ curl --insecure https://kubernetes.docker.internal:6443
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {

  },
  "status": "Failure",
  "message": "forbidden: User \"system:anonymous\" cannot get path \"/\"",
  "reason": "Forbidden",
  "details": {

  },
  "code": 403
}

おとなしくkubectlを使えばいいんだけど, 理由はさておきどうしてもcurlで接続したいことがあった.
curlでクライアント認証を突破するには--cert(クライアント証明書)と--key(クライアント秘密鍵)が必要なので,
kubeconfigにベタ書きされている値をbase64でデコードする.

# クライアント証明書をbase64デコード
$ kubectl config view --minify --raw -o jsonpath='{.users[].user.client-certificate-data}' | base64 -D
-----BEGIN CERTIFICATE-----
MIIDFTCCAf2gAwIBAgIICzCv4rM20vUwDQYJKoZIhvcNAQELBQAwFTETMBEGA1UE
...
QCUVil5khgn66X0Pd2GAs37k66Yyx7urGw==
-----END CERTIFICATE-----

# クライアントの秘密鍵をbase64デコード
$ kubectl config view --minify --raw -o jsonpath='{.users[].user.client-key-data}' | base64 -D
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAx6UtMTtlcvZWKPiQcDSlP7Ic2b2QOpigVifG6HOU5OtBc+Fn
...
PEUMoWLF7jKfAGRtKrnY9DTE4HeDoohXlDG47KC+TLrm1bSwxMIn
-----END RSA PRIVATE KEY-----

よくみるPEM形式の証明書と秘密鍵が確認できる.
あとはこれをファイルに出力するだけ.

# クライアント証明書(client.crt)と秘密鍵(client.key)をファイルに出力する
$ kubectl config view --minify --raw -o jsonpath='{.users[].user.client-certificate-data}' | base64 -D -o client.crt
$ kubectl config view --minify --raw -o jsonpath='{.users[].user.client-key-data}' | base64 -D -o client.key

作成したクライアント証明書と秘密鍵のファイルを使って再度KubernetesクラスタのAPIを叩いてみる.

# クライアント証明書(client.crt)と秘密鍵(client.key)を使って認証を突破
$ curl --insecure --cert ./client.crt --key ./client.key https://kubernetes.docker.internal:6443
{
  "paths": [
    "/api",
    "/api/v1",
    ...,
    "/version"
  ]
}

クライアント認証を突破できた.
やったぜ.

今回はクライアント証明書と秘密鍵をkubeconfigから取り出すのにkubectlを使ったけど,
yaml形式のファイルから任意の値を取り出せるならもちろん他の方法でもできる.
kubectlが使えなくてkubeconfigしかないような場合はこっちの方法を使うことが多そう.

# grepとawkでやる例
$ cat ~/.kube/config | grep client-certificate-data | awk '{print $2}' | base64 -D
$ cat ~/.kube/config | grep client-key-data | awk '{print $2}' | base64 -D
# yqでやる例
$ cat ~/.kube/config | yq r - "users[*].user.client-certificate-data" | base64 -D
$ cat ~/.kube/config | yq r - "users[*].user.client-key-data" | base64 -D
# いずれも出力はkubectl config viewから取り出したときと同じ

おわり

kubectlは使えないけどkubeconfigは存在する, みたいな環境でどうしてもKubernetesクラスタのAPIをたたく必要があったので一応やってみた.
kubectlが使える環境だけどcurlでのアクセスを試したい, というような場合は事前にServiceAccountを作ってBearer Tokenを発行したほうがたぶんはやい1.

おまけ

食パンクッションに乗るねこ