タイトル
Certificate signing requests を理解する
目的
- Certificate signing requests を理解する
手段
- マニュアルベースで手を動かす
ざっくり理解する
環境
- killercode 環境を活用
Certificate signing requestsとは
CertificateSigningRequest(以下、CSR)は証明書に指定された署名者による署名を要求するために利用するリソースのことです。例えば、k8s 環境で新しいユーザを追加したい場合、ユーザは kube-apiserver 等にアクセスする必要があります。この新しいユーザは kubenetes 環境の ca 証明書に署名された証明書を提示してアクセスする必要があります。
ユーザ用の証明書を署名するためのリソースタイプを CertificateSigningRequest と呼びます。このリースタイプは X.509 証明書の発行を要求することを可能にします。
CSR の承認方法は下記3あります。
- controller は自動的に承認する
- REST API を利用して承認する
- 手動(
kubectl certificate approve
)コマンドで承認する
approveされた後はsigningする。(承認→署名の流れ)
古い CRS リソースの自動削除処理(garbage collection)が実装されています。
- Approved requests: 1時間後に自動的に削除
- Denied requests: 1時間後に自動的に削除
- Failed requests: 1時間後に自動的に削除
- Pending requests: 24時間後に削除
- All requests: 証明書の有効期限切れ後に自動的に削除
Sinerは署名自体やエンティティを抽象的に表す。
Kubernetes 内の signer 一覧は以下の通りです。 -
kubernetes.io/kube-apiserver-client
: APIサーバーがクライアント証明書として承認する証明書に署名します -
kubernetes.io/kube-apiserver-client-kubelet
: APIサーバーによってクライアント証明書として承認されるクライアント証明書に署名します。 kube-controller-managerによって自動承認される場合があります。 -
kubernetes.io/kubelet-serving
: APIサーバーが有効なkubeletサービング証明書として承認するサービング証明書に署名しますが、それ以外の保証はありません。 -
kubernetes.io/legacy-unknown
: 信頼の保証は全くありません
ユーザが利用する証明書の作成手順は以下の通りです。
- 秘密鍵の作成
controlplane $ openssl genrsa -out myuser.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
....................+++++
...+++++
e is 65537 (0x010001)
# 秘密鍵の生成
controlplane $ openssl req -new -key myuser.key -out myuser.csr -subj "/CN=myuser" # ユーザ名を指定する
controlplane $ ls |grep myuser.
myuser.csr
myuser.key
- CSR ファイルの内容を base64 でエンコードする
controlplane $ cat myuser.csr | base64 | tr -d "\n"
LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ1ZqQ0NBVDRDQVFBd0VURVBNQTBHQTFVRUF3d0diWGwxYzJWeU1JSUJJakFOQmdrcWhraUc5dzBCQVFFRgpBQU9DQVE4QU1JSUJDZ0tDQVFFQXNIdnJESU5MM2oxQjdMSzkyaHlaWlBhalpUTmczenJpTSsvdGYwbzBBUzdjCjdEMk5YdVJodDY1VjJTTmllL1JpNW9Ua013eWJaVkFYV2IzamcvU05WMWhwYzdVOTI0TGNSbzFvMEtKdEtENm4KSCtOU1JSUzN1a3pzTWZvM0tkVFp6cTN5cHFYcDBETkc0ZTZSdUJDckVMbElNekhrRC9CVGI4SCtGWjIyVWVoaQphN0kxOS9OYitNekp3SWdnSVI5YmdPT3RESzczbkwvRnVscHhZa1hnYkFHL3UrOHAyNVFINW4vQUQzblAreHJECk82bm1icWEvOEtmeDQrMFNaakRpcjUzMmEzVEo4T1VjOVlLVjVnK01xMVVCdGRORWtVakwvZHRPNmtwRDd2d3gKTlRvVHlhRTNTc0k0V01rck1IMzhCakdmZDN2YXNOeWd1MUFyNkFPaTR3SURBUUFCb0FBd0RRWUpLb1pJaHZjTgpBUUVMQlFBRGdnRUJBQ3IvOFZFTEY5ajMwdEVGd1lseVFsZUx6Smo2Ull6UklUOGtDdFBRM1BmTHRWcUFvNGR4CjJEV2tFeURVaWNHTUluc3MwYnNOMVpnTXY5WTlKbzNHbFYvTmVVbkRlRTJyd1VINzBZajdkSm5rN3M4QXM4OXAKYXVIUWVjVk84NThhSXRZV0N1R3VsYTJsSmF0WkIyVlVpWW1YTG1OQW5rWGpkcnlyYWFYZTlGOGNtdkFnMThVeApFK1VDOFloZmxyNG82RW5uSnROSEI0NG0xVWFTdUIrWThWdHV2Q2RnWWQ3RUdmdURZM1dYQVF5MjNFM0E0anNLCm10S2Vzd3ZrL1YzNlBoTitZOWMwTVE5cGtPTWpKRlpUTmNBVFVUM2Y1L1U3Y2o0UXljbENqWlo1dW42czVoZGgKVTlQQW9ZT3FyVlUrNnFYb2gvb0kvQUxIbWg2dzJWSit2Yk09Ci0tLS0tRU5EIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLQo=
- CSR の作成
cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: myuser # ユーザ名を指定する
spec:
request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ1ZqQ0NBVDRDQVFBd0VURVBNQTBHQTFVRUF3d0diWGwxYzJWeU1JSUJJakFOQmdrcWhraUc5dzBCQVFFRgpBQU9DQVE4QU1JSUJDZ0tDQVFFQXNIdnJESU5MM2oxQjdMSzkyaHlaWlBhalpUTmczenJpTSsvdGYwbzBBUzdjCjdEMk5YdVJodDY1VjJTTmllL1JpNW9Ua013eWJaVkFYV2IzamcvU05WMWhwYzdVOTI0TGNSbzFvMEtKdEtENm4KSCtOU1JSUzN1a3pzTWZvM0tkVFp6cTN5cHFYcDBETkc0ZTZSdUJDckVMbElNekhrRC9CVGI4SCtGWjIyVWVoaQphN0kxOS9OYitNekp3SWdnSVI5YmdPT3RESzczbkwvRnVscHhZa1hnYkFHL3UrOHAyNVFINW4vQUQzblAreHJECk82bm1icWEvOEtmeDQrMFNaakRpcjUzMmEzVEo4T1VjOVlLVjVnK01xMVVCdGRORWtVakwvZHRPNmtwRDd2d3gKTlRvVHlhRTNTc0k0V01rck1IMzhCakdmZDN2YXNOeWd1MUFyNkFPaTR3SURBUUFCb0FBd0RRWUpLb1pJaHZjTgpBUUVMQlFBRGdnRUJBQ3IvOFZFTEY5ajMwdEVGd1lseVFsZUx6Smo2Ull6UklUOGtDdFBRM1BmTHRWcUFvNGR4CjJEV2tFeURVaWNHTUluc3MwYnNOMVpnTXY5WTlKbzNHbFYvTmVVbkRlRTJyd1VINzBZajdkSm5rN3M4QXM4OXAKYXVIUWVjVk84NThhSXRZV0N1R3VsYTJsSmF0WkIyVlVpWW1YTG1OQW5rWGpkcnlyYWFYZTlGOGNtdkFnMThVeApFK1VDOFloZmxyNG82RW5uSnROSEI0NG0xVWFTdUIrWThWdHV2Q2RnWWQ3RUdmdURZM1dYQVF5MjNFM0E0anNLCm10S2Vzd3ZrL1YzNlBoTitZOWMwTVE5cGtPTWpKRlpUTmNBVFVUM2Y1L1U3Y2o0UXljbENqWlo1dW42czVoZGgKVTlQQW9ZT3FyVlUrNnFYb2gvb0kvQUxIbWg2dzJWSit2Yk09Ci0tLS0tRU5EIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLQo=
signerName: kubernetes.io/kube-apiserver-client
expirationSeconds: 86400 # CSR の有効期限を指定する
usages:
- client auth
EOF
# request は csr ファイルの内容を base64 でエンコードした文字列を指定する
- CSR を承認する
kubectl get csr # CSR リクエストを確認
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
csr-wl6nk 13d kubernetes.io/kube-apiserver-client-kubelet system:node:controlplane <none> Approved,Issued
myuser 44s kubernetes.io/kube-apiserver-client kubernetes-admin 24h Pending
kubectl certificate approve myuser # CSR リクエストを承認
certificatesigningrequest.certificates.k8s.io/myuser approved
kubectl get csr/myuser -o yaml # CSR から証明書情報を取り出す
kind: CertificateSigningRequest
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"certificates.k8s.io/v1","kind":"CertificateSigningRequest","metadata":{"annotations":{},"name":"myuser"},"spec":{"expirationSeconds":86400,"request":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ1ZqQ0NBVDRDQVFBd0VURVBNQTBHQTFVRUF3d0diWGwxYzJWeU1JSUJJakFOQmdrcWhraUc5dzBCQVFFRgpBQU9DQVE4QU1JSUJDZ0tDQVFFQXNIdnJESU5MM2oxQjdMSzkyaHlaWlBhalpUTmczenJpTSsvdGYwbzBBUzdjCjdEMk5YdVJodDY1VjJTTmllL1JpNW9Ua013eWJaVkFYV2IzamcvU05WMWhwYzdVOTI0TGNSbzFvMEtKdEtENm4KSCtOU1JSUzN1a3pzTWZvM0tkVFp6cTN5cHFYcDBETkc0ZTZSdUJDckVMbElNekhrRC9CVGI4SCtGWjIyVWVoaQphN0kxOS9OYitNekp3SWdnSVI5YmdPT3RESzczbkwvRnVscHhZa1hnYkFHL3UrOHAyNVFINW4vQUQzblAreHJECk82bm1icWEvOEtmeDQrMFNaakRpcjUzMmEzVEo4T1VjOVlLVjVnK01xMVVCdGRORWtVakwvZHRPNmtwRDd2d3gKTlRvVHlhRTNTc0k0V01rck1IMzhCakdmZDN2YXNOeWd1MUFyNkFPaTR3SURBUUFCb0FBd0RRWUpLb1pJaHZjTgpBUUVMQlFBRGdnRUJBQ3IvOFZFTEY5ajMwdEVGd1lseVFsZUx6Smo2Ull6UklUOGtDdFBRM1BmTHRWcUFvNGR4CjJEV2tFeURVaWNHTUluc3MwYnNOMVpnTXY5WTlKbzNHbFYvTmVVbkRlRTJyd1VINzBZajdkSm5rN3M4QXM4OXAKYXVIUWVjVk84NThhSXRZV0N1R3VsYTJsSmF0WkIyVlVpWW1YTG1OQW5rWGpkcnlyYWFYZTlGOGNtdkFnMThVeApFK1VDOFloZmxyNG82RW5uSnROSEI0NG0xVWFTdUIrWThWdHV2Q2RnWWQ3RUdmdURZM1dYQVF5MjNFM0E0anNLCm10S2Vzd3ZrL1YzNlBoTitZOWMwTVE5cGtPTWpKRlpUTmNBVFVUM2Y1L1U3Y2o0UXljbENqWlo1dW42czVoZGgKVTlQQW9ZT3FyVlUrNnFYb2gvb0kvQUxIbWg2dzJWSit2Yk09Ci0tLS0tRU5EIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLQo=","signerName":"kubernetes.io/kube-apiserver-client","usages":["client auth"]}}
creationTimestamp: "2025-02-25T12:02:36Z"
name: myuser
resourceVersion: "3380"
uid: 93e9d69d-7329-4966-9eb8-b9d66ff1a5ee
spec:
expirationSeconds: 86400
groups:
- kubeadm:cluster-admins
- system:authenticated
request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ1ZqQ0NBVDRDQVFBd0VURVBNQTBHQTFVRUF3d0diWGwxYzJWeU1JSUJJakFOQmdrcWhraUc5dzBCQVFFRgpBQU9DQVE4QU1JSUJDZ0tDQVFFQXNIdnJESU5MM2oxQjdMSzkyaHlaWlBhalpUTmczenJpTSsvdGYwbzBBUzdjCjdEMk5YdVJodDY1VjJTTmllL1JpNW9Ua013eWJaVkFYV2IzamcvU05WMWhwYzdVOTI0TGNSbzFvMEtKdEtENm4KSCtOU1JSUzN1a3pzTWZvM0tkVFp6cTN5cHFYcDBETkc0ZTZSdUJDckVMbElNekhrRC9CVGI4SCtGWjIyVWVoaQphN0kxOS9OYitNekp3SWdnSVI5YmdPT3RESzczbkwvRnVscHhZa1hnYkFHL3UrOHAyNVFINW4vQUQzblAreHJECk82bm1icWEvOEtmeDQrMFNaakRpcjUzMmEzVEo4T1VjOVlLVjVnK01xMVVCdGRORWtVakwvZHRPNmtwRDd2d3gKTlRvVHlhRTNTc0k0V01rck1IMzhCakdmZDN2YXNOeWd1MUFyNkFPaTR3SURBUUFCb0FBd0RRWUpLb1pJaHZjTgpBUUVMQlFBRGdnRUJBQ3IvOFZFTEY5ajMwdEVGd1lseVFsZUx6Smo2Ull6UklUOGtDdFBRM1BmTHRWcUFvNGR4CjJEV2tFeURVaWNHTUluc3MwYnNOMVpnTXY5WTlKbzNHbFYvTmVVbkRlRTJyd1VINzBZajdkSm5rN3M4QXM4OXAKYXVIUWVjVk84NThhSXRZV0N1R3VsYTJsSmF0WkIyVlVpWW1YTG1OQW5rWGpkcnlyYWFYZTlGOGNtdkFnMThVeApFK1VDOFloZmxyNG82RW5uSnROSEI0NG0xVWFTdUIrWThWdHV2Q2RnWWQ3RUdmdURZM1dYQVF5MjNFM0E0anNLCm10S2Vzd3ZrL1YzNlBoTitZOWMwTVE5cGtPTWpKRlpUTmNBVFVUM2Y1L1U3Y2o0UXljbENqWlo1dW42czVoZGgKVTlQQW9ZT3FyVlUrNnFYb2gvb0kvQUxIbWg2dzJWSit2Yk09Ci0tLS0tRU5EIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLQo=
signerName: kubernetes.io/kube-apiserver-client
usages:
- client auth
username: kubernetes-admin
status:
certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM5akNDQWQ2Z0F3SUJBZ0lRTzJoYlFaMS82QVhtMVp6UFNrRXJBREFOQmdrcWhraUc5dzBCQVFzRkFEQVYKTVJNd0VRWURWUVFERXdwcmRXSmxjbTVsZEdWek1CNFhEVEkxTURJeU5URXhOVGcwTTFvWERUSTFNREl5TmpFeApOVGcwTTFvd0VURVBNQTBHQTFVRUF4TUdiWGwxYzJWeU1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBCk1JSUJDZ0tDQVFFQXNIdnJESU5MM2oxQjdMSzkyaHlaWlBhalpUTmczenJpTSsvdGYwbzBBUzdjN0QyTlh1UmgKdDY1VjJTTmllL1JpNW9Ua013eWJaVkFYV2IzamcvU05WMWhwYzdVOTI0TGNSbzFvMEtKdEtENm5IK05TUlJTMwp1a3pzTWZvM0tkVFp6cTN5cHFYcDBETkc0ZTZSdUJDckVMbElNekhrRC9CVGI4SCtGWjIyVWVoaWE3STE5L05iCitNekp3SWdnSVI5YmdPT3RESzczbkwvRnVscHhZa1hnYkFHL3UrOHAyNVFINW4vQUQzblAreHJETzZubWJxYS8KOEtmeDQrMFNaakRpcjUzMmEzVEo4T1VjOVlLVjVnK01xMVVCdGRORWtVakwvZHRPNmtwRDd2d3hOVG9UeWFFMwpTc0k0V01rck1IMzhCakdmZDN2YXNOeWd1MUFyNkFPaTR3SURBUUFCbzBZd1JEQVRCZ05WSFNVRUREQUtCZ2dyCkJnRUZCUWNEQWpBTUJnTlZIUk1CQWY4RUFqQUFNQjhHQTFVZEl3UVlNQmFBRkVsaUd5SUdYVGF3THh1Si9wTHQKZERXd1U1N05NQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUJBM2VFc2VEVFhWN1FJWGlkT1I1RlpDODRmd29MaApFK2Joc05EMFp4VWljdWpObTNLTTVOM0JONkJyNzRMOWRhNTRZNHc1ZEVKWURZM2xOQUhwcnVyeWxrK3hmVHJUCmtaK01sVzFiSEVGSEpyMzdPSHA0dm5TM3pOc2cySjJHMVZjTStxcnN1cjlZR3MwZGVXTzkvLzh6L3RWRlJVaFIKWXpwdVlJcThCc1d5SnQxZ0NhZm5MUDREZENjTjg5UUsxVTllUDRjL2xVejNDMXdqS0VkT1FYVXZCd2J5V0VHZApXWG5URXZiNmE0ZkJ4Sy9lenhFOGl2ZHJMMWdvVUJ1bXVaY290TU5BWmRKRk05VStaam9icUZUYkNnSWQ5ZDBCCmFRZUhyWDdrT2trZWt0UWwyOWdEZW9JcG1oZjVnWFV0QzFJai9ITFJmMzdtdCtITjNEM2ZGVWRUCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
conditions:
- lastTransitionTime: "2025-02-25T12:03:43Z"
lastUpdateTime: "2025-02-25T12:03:43Z"
message: This CSR was approved by kubectl certificate approve.
reason: KubectlApprove
status: "True"
type: Approved
kubectl get csr myuser -o jsonpath='{.status.certificate}'| base64 -d > myuser.crt # CSR オブジェクトから証明書情報のみを myuser.crt に書き出す
cat myuser.crt
-----BEGIN CERTIFICATE-----
MIIC9jCCAd6gAwIBAgIQO2hbQZ1/6AXm1ZzPSkErADANBgkqhkiG9w0BAQsFADAV
MRMwEQYDVQQDEwprdWJlcm5ldGVzMB4XDTI1MDIyNTExNTg0M1oXDTI1MDIyNjEx
NTg0M1owETEPMA0GA1UEAxMGbXl1c2VyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAsHvrDINL3j1B7LK92hyZZPajZTNg3zriM+/tf0o0AS7c7D2NXuRh
t65V2SNie/Ri5oTkMwybZVAXWb3jg/SNV1hpc7U924LcRo1o0KJtKD6nH+NSRRS3
ukzsMfo3KdTZzq3ypqXp0DNG4e6RuBCrELlIMzHkD/BTb8H+FZ22Uehia7I19/Nb
+MzJwIggIR9bgOOtDK73nL/FulpxYkXgbAG/u+8p25QH5n/AD3nP+xrDO6nmbqa/
8Kfx4+0SZjDir532a3TJ8OUc9YKV5g+Mq1UBtdNEkUjL/dtO6kpD7vwxNToTyaE3
SsI4WMkrMH38BjGfd3vasNygu1Ar6AOi4wIDAQABo0YwRDATBgNVHSUEDDAKBggr
BgEFBQcDAjAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFEliGyIGXTawLxuJ/pLt
dDWwU57NMA0GCSqGSIb3DQEBCwUAA4IBAQBA3eEseDTXV7QIXidOR5FZC84fwoLh
E+bhsND0ZxUicujNm3KM5N3BN6Br74L9da54Y4w5dEJYDY3lNAHprurylk+xfTrT
kZ+MlW1bHEFHJr37OHp4vnS3zNsg2J2G1VcM+qrsur9YGs0deWO9//8z/tVFRUhR
YzpuYIq8BsWyJt1gCafnLP4DdCcN89QK1U9eP4c/lUz3C1wjKEdOQXUvBwbyWEGd
WXnTEvb6a4fBxK/ezxE8ivdrL1goUBumuZcotMNAZdJFM9U+ZjobqFTbCgId9d0B
aQeHrX7kOkkektQl29gDeoIpmhf5gXUtC1Ij/HLRf37mt+HN3D3fFUdT
-----END CERTIFICATE-----
- kubecofnig に作成したユーザ情報を追加する
kubeconfig にユーザを追加する場合、次の手順で設定を作成します。
- set-credential オプションで作成するユーザの credential を作成
- set-context オプションでどのクラスターに対してアクセスするのかを指定
- use-context オプションで作成した context を設定に反映する
kubectl config set-credentials myuser --client-key=myuser.key --client-certificate=myuser.crt --embed-certs=true
User "myuser" set.
kubectl config set-context myuser --cluster=kubernetes --user=myuser
Context "myuser" created.
kubectl config use-context myuser
k config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
kubernetes-admin@kubernetes kubernetes kubernetes-admin
* myuser kubernetes myuser
# 現在のコンテキストを確認する
- アクセス権を確認する
k get po
No resources found in default namespace.
k get po -A
Error from server (Forbidden): pods is forbidden: User "myuser" cannot list resource "pods" in API group "" at the cluster scope
# アクセス権は限定されている
作成したユーザに対して RBAC を適用する場合、role オブジェクト及び rolebinding オブジェクトを作成する必要があります
- Role 及び RoleBinding を作成する
kubectl create role developer --verb=create --verb=get --verb=list --verb=update --verb=delete --resource=pods
role.rbac.authorization.k8s.io/developer created
# role を作成
kubectl create rolebinding developer-binding-myuser --role=developer --user=myuser
rolebinding.rbac.authorization.k8s.io/developer-binding-myuser created
# 作成した role とユーザを rolebinding オブジェクトとして作成
次に、clusterrole を yaml 形式で作成する場合は下記フォーマットを利用します。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: csr-creator
rules:
- apiGroups: # API グループを指定
- certificates.k8s.io
resources:
- certificatesigningrequests # リソースを指定
verbs: # 許可する verb を指定
- create
- get
- list
- watch
# この ClusterRole は certificatesigningrequests リソースに対して、create・get・list・watch の権限を有します
# また、`- apiGroups` を複数記述することも可能です。一つのClusterRoleは複数のリソースに対する権限を有することができます
あとがき
誰かに分かり易く説明できるレベルで記載しないと、読み返したときに「やっぱり理解できていない事は他人に説明できないな~」と思いました。。。