Tanzu Mission ControlのNamespaceに対するRBAC設定の検証

Tanzu Mission Control（TMC）はTMCが管理しているNamespaceに対してWebUIからRBACが設定できる。
この挙動を確認した時のメモ。

## TMCのRBAC
TMCでは
```
　Organization：    TMC全体
    Workspaces：    Namespaceのグループ
      Namespace：   TMCで管理するNamespace
```
のような感じで各階層ごとにロールバインディング出来るようになっている。ただし、全てが所謂KubernetesのRBAC設定かと言うとそうでもなく、TMC内で適用されるRBACとKubernetesで適用されるRBACの大きく2種類に分かれる。
各階層で設定できる項目は異なる。

|対象|Organization|Workspaces|Namespace
|---|---|---|---|
|cluster|x|||
|clustergroup|x|||
|managementcluster|x|||
|organization|x|||
|provisioner|x|||
|workspace|x|x||
|namespace|x|x|x|

今回はここのNamespaceに対するRBACの検証を行う。
Namespaceに対しては標準で用意されているロールとして`namespace.admin`、`namespace.edit`、`namespace.view`があり、それぞれはWebUIから割り当てることが出来る。
ロールの割当は`Access`->`WORKSPACE`から対象のWorkspaceを開いてNamespaceを選択して割り当てる。
![1678608320360.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/4e496c01-5cef-78e8-263e-8d8815f635cd.png)

TMCからRBACを割り当てた際、クラスタ側でどのようなロールが割り当てられるかを確認する。

## 前準備
RBACの振る舞いを確認するために、権限設定したアカウントでkubectlを叩く必要がある。そのための準備を以下で実施する。
### TMC CLIの入手
TMCが生成するkubeconfig内でtmcコマンドを実行している。そのため、事前にTMC CLIを入手しておくこと。
CLIは`Automation Center`からダウンロードできる。

![1678604819078.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/0a6ff911-a8cc-a76e-2149-f5c3484e3399.png)


### TMCへのCLIでのログイン
`tmc login`を実行してログインする。
```
$ tmc login
i If you don't have an API token, visit the VMware Cloud Services console, select your organization, and create an API token with the TMC service roles:
  https://console.cloud.vmware.com/csp/gateway/portal/#/user/tokens
? API Token ****************************************************************
? Login context name xxx@mydomain.info
? Select default log level info
? Management Cluster Name
? Provisioner Name
√ Successfully created context imurata@vmware.com, to manage your contexts run `tmc system context -h`
```

tmc login実行時のTokenはTMCのWebUIからアカウントを選択して`My Account`を選択し、VMware Cloud Servicesの方のMy Accountの`API Tokens`タブを選択して生成する。

![1678605029591.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/6c8f258c-8cbf-4197-7a35-3867432ab4d3.png)

Login context nameは今回はログインIDを入力したが、名前なので任意のものでOK。それ以外は入力は必須ではない。

注意点として、TMCから取得したkubeconfig自体にアカウント情報が乗っていないようなので、複数アカウントを使い分けている人は、都度`tmc login`を実行し直す必要がある。

なお、ログインすると`$HOME`に`.vmware-cna-saas`というディレクトリが作成されて、その下にTokenなどを格納したファイルが作成される。
今回の場合だと以下のようになり、コンテキスト名(xxx@mydomain.info)のファイルにTokenなどが格納される。
```
.vmware-cna-saas/
├── contexts
│   └── xxx@mydomain.info
└── current-context
```
Tokenを忘れた時には上記ファイルの`refresh_token`から値を引っ張ってくるとよい。


### WorkspaceとNamespaceの作成
検証用にWorkspaceを作っておく。
左のサイドバーの`Workspaces`->`CREATE WORKSPACE`を選択し、Workspaceを作成する。
作成後、Namespaceを作成する。
今回はinfra-op-wsというWorkspaceを作成し、中にNamespaceとしてinfra-op, infra-op-nsを作成した。
![1678608571556.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/a9ddc235-1207-1242-86a8-2753856e4c7c.png)

### kubeconfigの取得
クラスタを操作するためのkubeconfigを取得する。
左サイドバーの`Clusters`からクラスタを選択し、右上の`ACTIONS`から`Access this cluster`を選択するとダウンロードできる。

![1678609010735.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/216d8d12-6394-c370-9903-ff5befdd5572.png)

入手後、ファイルの内容を$HOME/.kube/configに追記するか、`export KUBECONFIG=<ファイルパス>`を指定して、クラスタ操作が出来るようする。


## 検証


### namespace.view

このロールを割り当てると、以下のような形で対象Namespace内にrolebindingが作成される。

```
$ kubectl get rolebinding
NAME                                                                                                                                 ROLE               AGE
rid-ns-af0c4a3a-76b9-433c-a0cb-4b34478c3505-imurata-tkg-sof-default-tkg-wc-sof-infra-op-rbac.authorization.k8s.io-ClusterRole-view   ClusterRole/view   85s
```
これの中身を見ると、以下のようになっている。
```yaml
  roleRef:
    apiGroup: rbac.authorization.k8s.io
    kind: ClusterRole
    name: view
  subjects:
  - apiGroup: rbac.authorization.k8s.io
    kind: User
    name: xxx@mydomain.info
```
`ClusterRole`の`view`は標準で提供されるロールであり、作成権限を持たない。
権限の詳細は以下で確認できる。
```
$ kubectl describe clusterrole  view
：（省略）
  pods                                         []                 []                          [get list watch]
：（省略）
```
Pod関連に関しても、`create`や`delete`を含まないため、参照用の権限であることが分かる。

`tmc login`した環境で入手したkubeconfigを利用してkubectlを実行すると、以下のような結果となる。

```
$ kubectl get pod -n default
Error from server (Forbidden): pods is forbidden: User "xxx@mydomain.info" cannot list resource "pods" in API group "" in the namespace "default"
$ kubectl get pod -n infra-op
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          131m
$ kubectl run centos -n infra-op --image centos
Error from server (Forbidden): pods is forbidden: User "xxx@mydomain.info" cannot create resource "pods" in API group "" in the namespace "infra-op"
```
この結果からも、対象のNamespaceのPodの取得には成功するが、作成は出来なかったり、他のNamespaceに対しても権限を持たないことが分かる。

### namespace.edit
`namespace.edit`を割り当てた場合は以下のように`ClusterRole`の`edit`がアカウントと紐付けられる。
```
  roleRef:
    apiGroup: rbac.authorization.k8s.io
    kind: ClusterRole
    name: edit
```
`edit`の権限は以下のようにPodに対しての作成権限を持つ。
```
$ kubectl describe clusterrole edit
：（省略）
  pods                                         []                 []                          [create delete deletecollection patch update get list watch]
：（省略）
```
そのため、先程失敗したアカウントで再度作成を試みると、今度は作成に成功する。
```
$ kubectl run centos -n infra-op --image centos
pod/centos created
```
### namespace.admin
`namespace.admin`を割り当てた場合は以下のように`ClusterRole`の`admin`がアカウントと紐付けられる。
```
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: admin
```
`admin`の権限の特徴はRoleに関する操作も許可されている点である。
```
$ kubectl describe clusterrole admin |grep role
  rolebindings.rbac.authorization.k8s.io          []                 []                          [create delete deletecollection get list patch update watch]
  roles.rbac.authorization.k8s.io                 []                 []                          [create delete deletecollection get list patch update watch]
```  
そのため、`namespace.admin`を割り当てた状態だとrole作成もできる。
```
$ kubectl create role -n infra-op  foo --verb=get,list,watch --resource=pod
role.rbac.authorization.k8s.io/foo created
```
また、`namespace.admin`にはKubernetesのRBACだけではなくTMCの権限にも影響を及ぼす。
以下は`namespace.edit`でTMCからNamespaceの権限を参照した時の画面である。
![1678666050617.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/7663eda6-12fd-886e-1f60-0593e2292e61.png)

権限がない旨が表示される。
`namespace.admin`に変更すると、以下のようにTMCからNamespaceの権限設定が出来るようになる。
![1678666151927.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/955c5c9e-7089-8878-e447-f0e36c512971.png)

### まとめ
以下の振る舞いが確認できた。
- WebUIでロールを割り当てると、Namespace内にRolebindingが作成される
- RolebindingのロールはClusterRoleのadmin/edit/viewが対応する
- adminの時に限り、TMC側の権限にも影響を与え、WebUIでNamespaceのロール管理が出来るようになる

## おまけ：カスタムロール
ClusterRoleのadmin/edit/view以外を使いたい場合、カスタムロールで独自のロールを用意して割り当てる事もできる。
`Administration`->`Roles`から`CREATE CUSTOM ROLE`を選択することでカスタムロールが作成できる。

以下、入力項目と今回設定した値となる。
- Name：ロール名。KubernetesのRBACとして作成する場合、同名の`ClusterRole`も作成される。ここでは`test-k8s-rbac`とした。
- Description：説明。ロール割当時に表示される。ここでは`test for k8s rbac`とした。
- Role labels：ラベル。複数のロールをまとめて扱いたい時などに利用する。
- Role visibility：`Access`のどこで見せるかを指定。今回は`Namespace`のRBACとして指定したいので、`WORKSPACE`を選択し、`Namespace`のチェックボックスのみチェックを入れる。
- Tanzu permissions：TMC側の権限設定。今回はKubernetesのRBACだけ対象としているので一旦どれもチェックしない。
- Additional Kubernetes RBAC rules：`ClusterRole`の設定。今回は動作確認として`Pod`に`get`,`list`だけ出来る権限を設定する。※今回は設定していないが'*'も選択は出来ないが入力することで設定可能。
- Aggregation rule：複数のClusterRoleをまとめる際に指定する。今回は利用しない。
- Role deprecation：ロールを非推奨とする（新規にアタッチしようとしても、エラーが出るようになる）。今回は新規にアタッチするので設定しない。
  ![1678668355614.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/fd99c908-6643-8dba-4a3d-2351d82cef90.png)

ロール作成後、`Access`->`WORKSPACES`からNamespaceを選択して`CREATE ROLE BINDING`を選択すると、以下のように作成したロールが選択できるようになっている。
![1678668997713.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/d92f79be-3009-cd1e-608c-8ab718675c22.png)

クラスタ側では以下のような`RoleBinding`が確認できる。
```
$ kubectl get rolebinding
NAME                                                                                                                                          ROLE                        AGE
rid-ns-af0c4a3a-76b9-433c-a0cb-4b34478c3505-imurata-tkg-sof-default-tkg-wc-sof-infra-op-rbac.authorization.k8s.io-ClusterRole-test-k8s-rbac   ClusterRole/test-k8s-rbac   20s
```
紐付いている`ClusterRole`の`test-k8s-rbac`はクラスタ内に作成されており、以下のように定義されている。
```
$ kubectl describe clusterrole test-k8s-rbac
Name:         test-k8s-rbac
Labels:       tmc.cloud.vmware.com/crd-type=tmc-managed
Annotations:  <none>
PolicyRule:
  Resources  Non-Resource URLs  Resource Names  Verbs
  ---------  -----------------  --------------  -----
  pods.*     []                 []              [get list]
```
実際にPodを操作すると、権限が適切に割り当てられていることが分かる。
```
$ kubectl get pod -n infra-op
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          19h
$ kubectl delete pod -n infra-op nginx
Error from server (Forbidden): pods "nginx" is forbidden: User "xxx@mydomain.info" cannot delete resource "pods" in API group "" in the namespace "infra-op"
```

なお、割当後にカスタムロールを編集した場合、クラスタ側へは自動で変更が反映されるので、再アタッチ等の作業は不要である。

1ユーザに複数のロールを割り当てた場合、効果はORで適用されるため、view権限で割り当ててPodだけcreate/deleteを許したいようなケースでは`namespace.view`に加えてPodのcreate/deleteの権限を持たせたカスタムロールを作成して割り当てるとよい。