Kubernetesでユーザを作成する（X509 Client Certs編）

#　概要
Kubernetesではクライアントの認証の方法が複数ありますが、今自分が管理しているクラスタではクライアント証明書で認証しています。
新しくユーザを作りなくなったときにどうやって作成するか分からなかったので調べました。

k8sだとユーザ作るのですらハードル高くないですか...？

# 参考
- https://kubernetes.io/docs/reference/access-authn-authz/authentication/
- https://www.linkedin.com/pulse/adding-users-quick-start-kubernetes-aws-jakub-scholz

# 詳細

## User accounts
[別の記事](https://qiita.com/knqyf263/items/ecc799650fe247dce9c5)にも書いたのですが、KubernetesにはService accountsとUser accountsが存在します。

>User accounts are for humans. Service accounts are for processes, which run in pods.

Service accountsはPod内で実行されるプロセスのためのアカウントなので、kubectlなどで使うものではないようです。
そこで、User　accountsが必要になります。

ところが、 `kubectl get users` や `kubectl create users` などというコマンドは存在しませんし、APIも存在しません。

>Kubernetes does not have objects which represent normal user accounts. Normal users cannot be added to a cluster through an API call.

上記に書いてある通り、実はKubernetesにはuserというオブジェクトは存在しません。
APIで追加したりすることも出来ません。

ですが、APIリクエストは認証される必要がありユーザと紐付けられます。

>API requests are tied to either a normal user or a service account, or are treated as anonymous requests.

また、認証されたユーザは `system:authenticated` グループに属することになります。
このユーザ自体はk8sには存在せず、認証したときにユーザ名の文字列が認識されるイメージです（うまい表現が思いつかなかったので誰か補足を期待してます）。

## X509 Client Certs
今回はX509 Client Certsでの認証について書きます。

>If a client certificate is presented and verified, the common name of the subject is used as the user name for the request. 

上記にある通りクライアント証明書の検証が通ると、SubjectのCN(Common Name)がユーザ名として扱われます。
O(Organization)がグループ名になります。Oは複数かけるため、複数のグループに所属させることも可能です。

流れとしては、クライアント証明書を作ってCSRを作成し、KubernetesのCAに署名してもらった証明書を使う感じです。
細かく知りたい人はドキュメントを読んでもうとして、やり方について説明します。

### 秘密鍵の生成
まず秘密鍵を作ります。

```
$ openssl genrsa -out knqyf263.pem 2048
```

### CSRの作成
上の鍵からCSRを作成します。

```
$ openssl req -new -key knqyf263.pem -out knqyf263.csr -subj "/CN=knqyf263"
```

### 署名
上で書いたように、KubernetesのCAに署名して貰う必要があります。
CSRを投げるためのAPIが存在するので、そちらを使います。

上のCSRはBase64する必要があるので、先にBase64します。

```console
$ cat knqyf263.csr | base64 | tr -d '\n'
```

これを以下のYAMLに書きます。

```
$ vim csr.yaml
apiVersion: certificates.k8s.io/v1beta1
kind: CertificateSigningRequest
metadata:
  name: user-request-knqyf263
spec:
  groups:
  - system:authenticated
  request: [BASE64エンコードしたやつを書く]
  usages:
  - digital signature
  - key encipherment
  - client auth
```

ではこのCSRをkubectlで作成します。

```console
$ kubectl create -f csr.yaml
```

以下でCSRを見ることが出来ますが、まだCONDITIONがPendingになっています。

```
$ kubectl get csr
NAME                   AGE       REQUESTOR   CONDITION
user-request-knqyf263   2s        admin       Pending
```

### Approve
上のCSRをapproveする必要があります。
これはapproveする権限を持っている人が実行する必要があります。

```
$ kubectl certificate approve user-request-knqyf263
```

### 証明書の取り出し
無事にapproveされたので証明書を取り出します。

```
$ kubectl get csr user-request-knqyf263 -o jsonpath='{.status.certificate}' | base64 -d > knqyf263.crt
```

### kubectlの設定
証明書を作ったのでkubectlの設定をします。

```
$ kubectl config set-cluster cluster_name --insecure-skip-tls-verify=true --server=https://api.my-cluster.example.com
$ kubectl config set-credentials knqyf263 --client-certificate=knqyf263.crt --client-key=knqyf263.pem --embed-certs=true
$ kubectl config set-context cluster_name --cluster=cluster_name --user=knqyf263
$ kubectl config use-context cluster_name
```

これで設定は終わりですが、この状態でkubectlを実行してもエラーになります。

```
$ kubectl get pods
Error from server (Forbidden): User "knqyf263" cannot list pods in the namespace "default". (get pods)
```

これは今作ったユーザにはRoleが割り当てられていないためです。

### ClusterRoleBinding
ユーザとviewのRoleをBindします。

```
$ vim knqyf263-view-all.yaml
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: knqyf263-view-all
subjects:
- kind: User
  name: knqyf263
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: view
  apiGroup: rbac.authorization.k8s.io
$ kubectl create -f knqyf263-view-all.yaml
```

これで無事に見られるようになります。

```
$ kubectl get pods
```

### cluster-admin
ちなみにデフォルトでcluster-adminというClusterRoleBindingがあり、これは `system:masters` というグループにcluster-adminロールをバインドしています。
そのため、最初のCSRを作るときにOに `system:masters` を入れておくと上のClusterRoleBindingを書かなくても最初からcluster-admin権限で操作可能になります。

```
openssl req -new -key knqyf263.pem -out knqyf263.csr -subj "/O=system:masters/CN=knqyf263" 
```

# まとめ
KubernetesでX509クライアント証明書による認証をしてる場合にユーザ作成する手順を書きました。
細かいところは省略したので興味があれば調べてみてください。

今回思ったのはただユーザ作りたいだけなのにKubernetes難しすぎでは...？という気持ちになりました。
もし他に簡単な方法があれば教えて頂けると助かります。