Certificate signing requests を理解する

# タイトル
Certificate signing requests を理解する

# 目的
- Certificate signing requests を理解する

# 手段
- マニュアルベースで手を動かす

### ざっくり理解する
![csr関連.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474478/5abe296e-0209-4896-a3cd-a92031702fb6.jpeg)


### 環境
- killercode 環境を活用

### Certificate signing requestsとは
CertificateSigningRequest(以下、CSR)は証明書に指定された署名者による署名を要求するために利用するリソースのことです。例えば、k8s 環境で新しいユーザを追加したい場合、ユーザは kube-apiserver 等にアクセスする必要があります。この新しいユーザは kubenetes 環境の ca 証明書に署名された証明書を提示してアクセスする必要があります。

ユーザ用の証明書を署名するためのリソースタイプを CertificateSigningRequest と呼びます。このリースタイプは X.509 証明書の発行を要求することを可能にします。

CSR の承認方法は下記３あります。
  1. controller は自動的に承認する
  2. REST API を利用して承認する
  3. 手動(`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` : 信頼の保証は全くありません

ユーザが利用する証明書の作成手順は以下の通りです。
  1. 秘密鍵の作成

```bash
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
```

  2. CSR ファイルの内容を base64 でエンコードする

```bash
controlplane $ cat myuser.csr | base64 | tr -d "\n"
LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ1ZqQ0NBVDRDQVFBd0VURVBNQTBHQTFVRUF3d0diWGwxYzJWeU1JSUJJakFOQmdrcWhraUc5dzBCQVFFRgpBQU9DQVE4QU1JSUJDZ0tDQVFFQXNIdnJESU5MM2oxQjdMSzkyaHlaWlBhalpUTmczenJpTSsvdGYwbzBBUzdjCjdEMk5YdVJodDY1VjJTTmllL1JpNW9Ua013eWJaVkFYV2IzamcvU05WMWhwYzdVOTI0TGNSbzFvMEtKdEtENm4KSCtOU1JSUzN1a3pzTWZvM0tkVFp6cTN5cHFYcDBETkc0ZTZSdUJDckVMbElNekhrRC9CVGI4SCtGWjIyVWVoaQphN0kxOS9OYitNekp3SWdnSVI5YmdPT3RESzczbkwvRnVscHhZa1hnYkFHL3UrOHAyNVFINW4vQUQzblAreHJECk82bm1icWEvOEtmeDQrMFNaakRpcjUzMmEzVEo4T1VjOVlLVjVnK01xMVVCdGRORWtVakwvZHRPNmtwRDd2d3gKTlRvVHlhRTNTc0k0V01rck1IMzhCakdmZDN2YXNOeWd1MUFyNkFPaTR3SURBUUFCb0FBd0RRWUpLb1pJaHZjTgpBUUVMQlFBRGdnRUJBQ3IvOFZFTEY5ajMwdEVGd1lseVFsZUx6Smo2Ull6UklUOGtDdFBRM1BmTHRWcUFvNGR4CjJEV2tFeURVaWNHTUluc3MwYnNOMVpnTXY5WTlKbzNHbFYvTmVVbkRlRTJyd1VINzBZajdkSm5rN3M4QXM4OXAKYXVIUWVjVk84NThhSXRZV0N1R3VsYTJsSmF0WkIyVlVpWW1YTG1OQW5rWGpkcnlyYWFYZTlGOGNtdkFnMThVeApFK1VDOFloZmxyNG82RW5uSnROSEI0NG0xVWFTdUIrWThWdHV2Q2RnWWQ3RUdmdURZM1dYQVF5MjNFM0E0anNLCm10S2Vzd3ZrL1YzNlBoTitZOWMwTVE5cGtPTWpKRlpUTmNBVFVUM2Y1L1U3Y2o0UXljbENqWlo1dW42czVoZGgKVTlQQW9ZT3FyVlUrNnFYb2gvb0kvQUxIbWg2dzJWSit2Yk09Ci0tLS0tRU5EIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLQo=
```

  3. CSR の作成

```bash
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 でエンコードした文字列を指定する
```

  4. CSR を承認する

```bash
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-----
```

  5. kubecofnig に作成したユーザ情報を追加する 

kubeconfig にユーザを追加する場合、次の手順で設定を作成します。

1. set-credential オプションで作成するユーザの credential を作成
2. set-context オプションでどのクラスターに対してアクセスするのかを指定
3. use-context オプションで作成した context を設定に反映する

```bash
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     
# 現在のコンテキストを確認する
```

  6. アクセス権を確認する 

```bash
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 オブジェクトを作成する必要があります

  7. Role 及び RoleBinding を作成する 

```bash
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 形式で作成する場合は下記フォーマットを利用します。

```bash
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は複数のリソースに対する権限を有することができます
```

# あとがき
誰かに分かり易く説明できるレベルで記載しないと、読み返したときに「やっぱり理解できていない事は他人に説明できないな～」と思いました。。。

# ソース
- [Certificates and Certificate Signing Requests](https://kubernetes.io/docs/reference/access-authn-authz/certificate-signing-requests/)
- [Certificates and Certificate Signing Requests](https://kubernetes.io/docs/reference/access-authn-authz/certificate-signing-requests/)