[Kubernetes] シチュエーション別 よく使う証明書発行コマンド

# はじめに
Kubernetesを扱っていると様々な場面で証明書発行が必要となります。
昨今[cert-manager](https://cert-manager.io/docs/)でも証明書の自動発行が可能ですが、今回は自前で証明書発行を行うコマンドを記載します。

# シチュエーション
1. TLS接続可能なPodをデプロイする場合
1. TLS接続可能なIngressをデプロイする場合
1. X509クライアント証明書認証を行う場合

# コマンド
## TLS接続可能なPodをデプロイする場合
### insecureな接続でもよい
クライアント証明書を必要としないinsecureな接続の場合は以下コマンドを使用します。
証明書を使用してPod作成後は、`curl -k　https://<host>:<port>`コマンドで接続します。
```
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout nginx.key  -out nginx.crt　-subj "/CN=mynginxsvc/O=mynginxsvc"
```

### secureな接続をしたい
opensslでも可能ですが、cfsslの方がわかりやすく簡単であるため、こちらを使用します。
なお、CNやSAN(hostsの値)などは適宜変更します。少し長いので手順ごとに記載します。
#### profile作成
```
$ mkdir testcrt
$ cd testcrt
$ cat << EOT > ca-config.json
> {
>     "signing": {
>         "default": {
>         "expiry": "8760h"
>         },
>         "profiles": {
>             "server": {
>                 "expiry": "8760h",
>                 "usages": ["signing", "key encipherment", "server auth"]
>             },
>             "client": {
>                 "expiry": "8760h",
>                 "usages": ["signing", "key encipherment", "client auth"]
>             },
>             "client-server": {
>                 "expiry": "8760h",
>                 "usages": ["signing", "key encipherment", "server auth", "client auth"]
>             }
>         }
>     }
> }
> EOT
```
#### CA作成
```
$ cat << EOT > ca.json
> {
>   "CN": "my-ca.example.com",
>   "key": {
>     "algo": "ecdsa",
>     "size": 256
>   },
>   "names": [
>   {
>     "C": "JP",
>     "ST": "Tokyo",
>     "L": "Minato-ku",
>     "O": "my-group"
>   }
>  ]
> }
> EOT

$ cfssl genkey -initca ca.json | cfssljson -bare ca
$ ls -l testcrt
total 32
-rw-------  1 user  group  227  6 21 10:28 ca-key.pem
-rw-r--r--  1 user  group  460  6 21 10:28 ca.csr
-rw-r--r--  1 user  group  186  6 21 10:27 ca.json
-rw-r--r--  1 user  group  761  6 21 10:28 ca.pem
```
#### server証明書作成
```
$ cat << EOT > server.json
> {
>     "CN": "my-nginx",
>     "hosts": [
>         "127.0.0.1",
>         "localhost",
>         "*.svc.cluster.local"
>     ],
>     "key": {
>         "algo": "ecdsa",
>         "size": 256
>     },
>     "names": [
>         {
>             "C": "JP",
>             "ST": "Tokyo",
>             "L": "Minato-ku",
>             "O": "my-group"
>         }
>     ]
> }
> EOT

$ cfssl gencert -ca ca.pem -ca-key ca-key.pem -config ca-config.json -profile server server.json | cfssljson -bare server
$ ls -l testcrt
total 80
-rw-r--r--  1 user  group  579  6 21 11:49 ca-config.json
-rw-------  1 user  group  227  6 21 10:28 ca-key.pem
-rw-r--r--  1 user  group  460  6 21 10:28 ca.csr
-rw-r--r--  1 user  group  186  6 21 10:27 ca.json
-rw-r--r--  1 user  group  761  6 21 10:28 ca.pem
-rw-r--r--  1 user  group  361  6 21 12:21 cserver.json
-rw-------  1 user  group  227  6 21 12:26 server-key.pem
-rw-r--r--  1 user  group  538  6 21 12:26 server.csr
-rw-r--r--  1 user  group  334  6 21 12:26 server.json
-rw-r--r--  1 user  group  883  6 21 12:26 server.pem
```
#### client証明書作成
```
$ cat << EOT > client.json
> {
>     "CN": "my-client",
>     "hosts": [
>         "127.0.0.1",
>         "localhost"
>     ],
>     "key": {
>         "algo": "ecdsa",
>         "size": 256
>     },
>     "names": [
>         {
>             "C": "JP",
>             "ST": "Tokyo",
>             "L": "Minato-ku",
>             "O": "my-group"
>         }
>     ]
> }
> EOT

$ cfssl gencert -ca ca.pem -ca-key $ cfssl gencert -ca ca.pem -ca-key ca-key.pem -config ca-config.json -profile client client.json | cfssljson -bare client
$ ls -l testcrt
total 112
-rw-r--r--  1 user  group  579  6 21 11:49 ca-config.json
-rw-------  1 user  group  227  6 21 10:28 ca-key.pem
-rw-r--r--  1 user  group  460  6 21 10:28 ca.csr
-rw-r--r--  1 user  group  186  6 21 10:27 ca.json
-rw-r--r--  1 user  group  761  6 21 10:28 ca.pem
-rw-------  1 user  group  227  6 21 12:34 client-key.pem
-rw-r--r--  1 user  group  509  6 21 12:34 client.csr
-rw-r--r--  1 user  group  304  6 21 12:33 client.json
-rw-r--r--  1 user  group  859  6 21 12:34 client.pem
-rw-r--r--  1 user  group  361  6 21 12:21 cserver.json
-rw-------  1 user  group  227  6 21 12:26 server-key.pem
-rw-r--r--  1 user  group  538  6 21 12:26 server.csr
-rw-r--r--  1 user  group  334  6 21 12:26 server.json
-rw-r--r--  1 user  group  883  6 21 12:26 server.pem
```
#### secret作成
```
$ kubectl create secret generic nginx-certs-keys --from-file=./server.pem --from-file=./server-key.pem --from-file=ca.pem
```
#### 接続テスト
このsecretをPodにmountし、端末にCA証明書をインストール後、以下コマンドで接続可能となる。
```
curl --head --cert client.pem --key client-key.pem https://<host>:<port>
```

## TLS接続可能なIngressをデプロイする場合
```
$ openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=nginxsvc/O=nginxsvc"
```

## X509クライアント証明書認証を行う場合
#### 秘密鍵およびCSRの作成
CNにはユーザ名を指定します。
```
$ openssl genrsa -out jane.key 2048
$ openssl req -new -key jane.key -subj "/CN=jane" -out jane.csr
```
#### 証明書の作成
[CertificateSigningRequest](https://kubernetes.io/docs/reference/access-authn-authz/certificate-signing-requests/#normal-user)リソースにて作成します。

# 最後に
シチュエーション別によく使う証明書発行コマンドを記載してみました。
これ以外にも証明書が必要な場面は多々ありますが、誰かの助けになれば幸いです。