Kubernetes RBAC(特定動作のみできるサーバを提供する)

# 前提
今回なんでこんなことをするかという背景として、
社内ツールをkubernetes上で動かしていて、それをあるmasterとは別のサーバにNATすることで、NATサーバのIPからアプリケーションにアクセスできるようにしていたのですが、興味などでkubectlに触れてみたいと思う方もいらっしゃるかなと思いました。

そういう訳で、そのNATサーバーからkubectlを打てるようにしてあげようと思ったのですが、podに変更を加えられたくなかったので、Podの情報だけはを見れるようにしようということで、以下のことをしていくこととなりました。

# まず初めに
提供するサーバに、kubernetesを操作するサーバの/root/.kube/configをコピーしておきます。

これで、そのサーバからkubernetesが操作できると思います。

# ClusterRoleの準備
ClusterRoleのmanifestを作成します。

```clusterRole.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: confined-role
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list"]
```

適応します。

```
# kubectl apply -f clusterRole.yaml
clusterrole.rbac.authorization.k8s.io/confined-role created

# kubectl get clusterrole
NAME                                                                   AGE
admin                                                                  2d3h
cluster-admin                                                          2d3h
confined-role                                                          15s
edit                                                                   2d3h
<省略>
```
作成された事を確認できました。


# ClusterRoleBinding
ClusterRoleBindingのmanifestを作成します。

```clusterRoleBinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: confined-rolebinding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: confined-role
subjects:
- apiGroup: ""
  kind: ServiceAccount
  name: confined-sa
  namespace: default
```

これで、下準備ができました。

# Service Accountの作成
Service Accountを作成します。

```
# kubectl create sa confined-sa
serviceaccount/confined-sa created

# kubectl get sa
NAME                                   SECRETS   AGE
1cb2dc0b-0ae3-4d11-8be6-134366812874   1         2d3h
confined-sa                            1         15s
default                                1         2d3h


# kubectl get sa confined-sa -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: "2019-11-28T06:23:37Z"
  name: confined-sa
  namespace: default
  resourceVersion: "272115"
  selfLink: /api/v1/namespaces/default/serviceaccounts/confined-sa
  uid: faecd7c4-ffd9-4d8f-a080-55eff0b4dfa8
secrets:
- name: confined-sa-token-kfsn6
```

上の表示では secretの箇所に、confined-sa-token-kfsn6 と出てきました。
この表示されたSecretをyaml形式で取得し、Tokenを確認します。


```
# kubectl get secret confined-sa-token-kfsn6 -o yaml
apiVersion: v1
data:
  ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMrekNDQWVPZ0F3SUJBZ0lVVWdkdHNzcmxuTk5PRnZUdkpiamorbEdadjh3d0RRWUpLb1pJaHZjTkFRRUwKQlFBd0RURUxNQWtHQTFVRUF4TUNZMkV3SGhjTk1Ua3hNVEkxTVRJd05qSTNXaGNOTWpNeE1USTFNVEl3TmpJMwpXakFOTVFzd0NRWURWUVFERXdKallUQ0NBU0l3RFFZSktvWklodmNOQVFFQkJRQURnZ0VQQURDQ0FRb0NnZ0VCCkFOZGhFUzlobG81R2d4YUt3dWY1cmJlSTlYRTBJaVc0cWk5MkNUS1d5RmMxSXprV3FFRm40a0JYY1h3TlFJQ28KL09TdzJ1QTVGU0JJYzZyc3hSNjNiMVhEYjlDQWVWRkFGNG9XNXRWbW5qOW53cEMvVCtSZDFiMFFmMjZ3ckI4OQpQZmdqK0pod0UvUnBMc0tEUTJrQmkrUEpzbUlCTmpHdjAwMnNOTW9rYTVuNCtzU2ZGTkhkV2ErMUJGcWxGbUhiCmcxc0c3VEI5Y28yb25jTndabGxkemJKSUhYQXVRcC9RWkQ0QW9GRUhIRFZoMjBxZ1VXUFZBNkJlcklCaVorN28Ka0Z1eTdpcHB5RFdWSkhmTFBZRlF6MFppaHpkTkpCQkhKdDcvVFNNQTlidy9TZ0ZydUsrUXIzMUhaOXJpZ0M4TgpTU3B5djVIMjNmbG5HOE9ldHlIdkw5OENBd0VBQWFOVE1GRXdIUVlEVlIwT0JCWUVGTzIxT0I1TUtOZlhMWjRXClJKQnlkZVBacWpPSk1COEdBMVVkSXdRWU1CYUFGTzIxT0I1TUtOZlhMWjRXUkpCeWRlUFpxak9KTUE4R0ExVWQKRXdFQi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFIcTIrSVplOU41bzZYdWFCUUhKY29sTgpQc0RCS0lUTkxlWTJvaWpaQlBEVkhqanhnR2xHWTlKc2RWRzFITWNQc1lIVnd3bTljOTVEL1hnN1V4RWwvNVp4CkRkVDVDSnNLQWxlZGhsL3oxckFRZk9FN25HOU1FdU5oSFdKdTBTMXpQYVN0dElRVVhoU3drZ2MrcnQxMThPSFYKajdKc25lWEMrcVlTK0lEV09YWFI5S2VMRXJjc256eXBtVzE2bVRBTmtPblBlQzBTWlRzUWV0UDhORFBYRis0OAppMXlWL1A3WjZsaVl3TERPQlFJOFkwZzFJOEtCTTR2RXNQUlJOOStBbkg1OTAyNCtvNklnVnptQXhmT1RhSzVMCnN0M3cwSlJRYjVGcTIwaEYxK3NCZlNFdCttc2JnNmFCNmlaMlFCMWFSZm9LdnprSW1rOUVuZTlYZkNoVEo5dz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
  namespace: ZGVmYXVsdA==
  token: ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXRwWkNJNklpSjkuZXlKcGMzTWlPaUpyZFdKbGNtNWxkR1Z6TDNObGNuWnBZMlZoWTJOdmRXNTBJaXdpYTNWaVpYSnVaWFJsY3k1cGJ5OXpaWEoyYVdObFlXTmpiM1Z1ZEM5dVlXMWxjM0JoWTJVaU9pSmtaV1poZFd4MElpd2lhM1ZpWlhKdVpYUmxjeTVwYnk5elpYSjJhV05sWVdOamIzVnVkQzl6WldOeVpYUXVibUZ0WlNJNkltTnZibVpwYm1Wa0xYTmhMWFJ2YTJWdUxXdG1jMjQySWl3aWEzVmlaWEp1WlhSbGN5NXBieTl6WlhKMmFXTmxZV05qYjNWdWRDOXpaWEoyYVdObExXRmpZMjkxYm5RdWJtRnRaU0k2SW1OdmJtWnBibVZrTFhOaElpd2lhM1ZpWlhKdVpYUmxjeTVwYnk5elpYSjJhV05sWVdOamIzVnVkQzl6WlhKMmFXTmxMV0ZqWTI5MWJuUXVkV2xrSWpvaVptRmxZMlEzWXpRdFptWmtPUzAwWkRobUxXRXdPREF0TlRWbFptWXdZalJrWm1FNElpd2ljM1ZpSWpvaWMzbHpkR1Z0T25ObGNuWnBZMlZoWTJOdmRXNTBPbVJsWm1GMWJIUTZZMjl1Wm1sdVpXUXRjMkVpZlEuRnZyV1hBUUMzVXJreG1IczM1SDlkbndUbUlJLWZoME1GTVJBbEVrZjNrdU1JVHFsbWl2VUMwLThORkdYdzMybDJrQm9TWmV0T18tNnlTbjZKSno3bk10cUZPVkZfMVpDZEtnZ2M5RE9xNkVueThSMnZYRWZPOFQ4YVhTMldfQ0Zza1lPVUttSjJFRkVTSU05RlNheXo0cHpkZU12RW5ObUw1dER3b1BXVHZGSU1TSjNtbDVNLUM0ZG9rWmtWSHB6RHQxLVRhMVR0emJlejFFRmNkb200blpyUTNLZWJ3cWx5MnhDeEg3YXdreldEbkdmSWtTVFVWRkRZWkk2SnBIMURxVVVYOXpxYzBCNW9XaVdVdzZucC1lRDFsWkMycXBUZVRTUGlyUUw0aE12dDVGUlNXdFByMlVOQXZDVENZeGNLSUl6Y2NIdXRzZklSaGJ6cVpYMzBB
kind: Secret
metadata:
  annotations:
    kubernetes.io/service-account.name: confined-sa
    kubernetes.io/service-account.uid: faecd7c4-ffd9-4d8f-a080-55eff0b4dfa8
  creationTimestamp: "2019-11-28T06:23:37Z"
  name: confined-sa-token-kfsn6
  namespace: default
  resourceVersion: "272114"
  selfLink: /api/v1/namespaces/default/secrets/confined-sa-token-kfsn6
  uid: aff16ff4-986b-40df-b3d4-51d300f0bb3a
type: kubernetes.io/service-account-token
```

このｔokenの値はBase64でエンコードされているため、デコードしてあげます。

```
# echo -n 'ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXRwWkNJNklpSjkuZXlKcGMzTWlPaUpyZFdKbGNtNWxkR1Z6TDNObGNuWnBZMlZoWTJOdmRXNTBJaXdpYTNWaVpYSnVaWFJsY3k1cGJ5OXpaWEoyYVdObFlXTmpiM1Z1ZEM5dVlXMWxjM0JoWTJVaU9pSmtaV1poZFd4MElpd2lhM1ZpWlhKdVpYUmxjeTVwYnk5elpYSjJhV05sWVdOamIzVnVkQzl6WldOeVpYUXVibUZ0WlNJNkltTnZibVpwYm1Wa0xYTmhMWFJ2YTJWdUxXdG1jMjQySWl3aWEzVmlaWEp1WlhSbGN5NXBieTl6WlhKMmFXTmxZV05qYjNWdWRDOXpaWEoyYVdObExXRmpZMjkxYm5RdWJtRnRaU0k2SW1OdmJtWnBibVZrTFhOaElpd2lhM1ZpWlhKdVpYUmxjeTVwYnk5elpYSjJhV05sWVdOamIzVnVkQzl6WlhKMmFXTmxMV0ZqWTI5MWJuUXVkV2xrSWpvaVptRmxZMlEzWXpRdFptWmtPUzAwWkRobUxXRXdPREF0TlRWbFptWXdZalJrWm1FNElpd2ljM1ZpSWpvaWMzbHpkR1Z0T25ObGNuWnBZMlZoWTJOdmRXNTBPbVJsWm1GMWJIUTZZMjl1Wm1sdVpXUXRjMkVpZlEuRnZyV1hBUUMzVXJreG1IczM1SDlkbndUbUlJLWZoME1GTVJBbEVrZjNrdU1JVHFsbWl2VUMwLThORkdYdzMybDJrQm9TWmV0T18tNnlTbjZKSno3bk10cUZPVkZfMVpDZEtnZ2M5RE9xNkVueThSMnZYRWZPOFQ4YVhTMldfQ0Zza1lPVUttSjJFRkVTSU05RlNheXo0cHpkZU12RW5ObUw1dER3b1BXVHZGSU1TSjNtbDVNLUM0ZG9rWmtWSHB6RHQxLVRhMVR0emJlejFFRmNkb200blpyUTNLZWJ3cWx5MnhDeEg3YXdreldEbkdmSWtTVFVWRkRZWkk2SnBIMURxVVVYOXpxYzBCNW9XaVdVdzZucC1lRDFsWkMycXBUZVRTUGlyUUw0aE12dDVGUlNXdFByMlVOQXZDVENZeGNLSUl6Y2NIdXRzZklSaGJ6cVpYMzBB' |base64 -d
eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImNvbmZpbmVkLXNhLXRva2VuLWtmc242Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImNvbmZpbmVkLXNhIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiZmFlY2Q3YzQtZmZkOS00ZDhmLWEwODAtNTVlZmYwYjRkZmE4Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlZmF1bHQ6Y29uZmluZWQtc2EifQ.FvrWXAQC3UrkxmHs35H9dnwTmII-fh0MFMRAlEkf3kuMITqlmivUC0-8NFGXw32l2kBoSZetO_-6ySn6JJz7nMtqFOVF_1ZCdKggc9DOq6Eny8R2vXEfO8T8aXS2W_CFskYOUKmJ2EFESIM9FSayz4pzdeMvEnNmL5tDwoPWTvFIMSJ3ml5M-C4dokZkVHpzDt1-Ta1Ttzbez1EFcdom4nZrQ3Kebwqly2xCxH7awkzWDnGfIkSTUVFDYZI6JpH1DqUUX9zqc0B5oWiWUw6np-eD1lZC2qpTeTSPirQL4hMvt5FRSWtPr2UNAvCTCYxcKIIzccHutsfIRhbzqZX30A
```

これを、configファイルに登録してあげます。

```
# kubectl config set-context confined-sa --token 'eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImNvbmZpbmVkLXNhLXRva2VuLWtmc242Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImNvbmZpbmVkLXNhIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiZmFlY2Q3YzQtZmZkOS00ZDhmLWEwODAtNTVlZmYwYjRkZmE4Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlZmF1bHQ6Y29uZmluZWQtc2EifQ.FvrWXAQC3UrkxmHs35H9dnwTmII-fh0MFMRAlEkf3kuMITqlmivUC0-8NFGXw32l2kBoSZetO_-6ySn6JJz7nMtqFOVF_1ZCdKggc9DOq6Eny8R2vXEfO8T8aXS2W_CFskYOUKmJ2EFESIM9FSayz4pzdeMvEnNmL5tDwoPWTvFIMSJ3ml5M-C4dokZkVHpzDt1-Ta1Ttzbez1EFcdom4nZrQ3Kebwqly2xCxH7awkzWDnGfIkSTUVFDYZI6JpH1DqUUX9zqc0B5oWiWUw6np-eD1lZC2qpTeTSPirQL4hMvt5FRSWtPr2UNAvCTCYxcKIIzccHutsfIRhbzqZX30A'
Context "confined-sa" created.
```

ちゃんと作成されたかを確認します。

```
# kubectl config get-contexts
CURRENT   NAME            CLUSTER         AUTHINFO                               NAMESPACE
*         SampleCluster   SampleCluster   1cb2dc0b-0ae3-4d11-8be6-134366812874   default
          confined-sa
```

実際にこのcontextを使用します。

```
# kubectl config use-context confined-sa
Switched to context "confined-sa".
```

再度、get-contextを打つと`*`がついて、contextが切り替わったことがわかります。

podを見れるか確認します。

```
# kubectl get pods
The connection to the server localhost:8080 was refused - did you specify the right host or port?
```

これは、正しくconfigファイルが設定されていない場合に起こります。

configファイルに変更を加えます。

```
# vi .kube/config

編集
- context:
    cluster: SampleCluster
    user: confined-sa
  name: confined-sa

以下を追記
- name: confined-sa
  user:
    token: eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImNvbmZpbmVkLXNhLXRva2VuLWtmc242Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImNvbmZpbmVkLXNhIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiZmFlY2Q3YzQtZmZkOS00ZDhmLWEwODAtNTVlZmYwYjRkZmE4Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlZmF1bHQ6Y29uZmluZWQtc2EifQ.FvrWXAQC3UrkxmHs35H9dnwTmII-fh0MFMRAlEkf3kuMITqlmivUC0-8NFGXw32l2kBoSZetO_-6ySn6JJz7nMtqFOVF_1ZCdKggc9DOq6Eny8R2vXEfO8T8aXS2W_CFskYOUKmJ2EFESIM9FSayz4pzdeMvEnNmL5tDwoPWTvFIMSJ3ml5M-C4dokZkVHpzDt1-Ta1Ttzbez1EFcdom4nZrQ3Kebwqly2xCxH7awkzWDnGfIkSTUVFDYZI6JpH1DqUUX9zqc0B5oWiWUw6np-eD1lZC2qpTeTSPirQL4hMvt5FRSWtPr2UNAvCTCYxcKIIzccHutsfIRhbzqZX30A
```


ここでcontextsを確認します。

```
# kubectl config get-contexts
CURRENT   NAME            CLUSTER         AUTHINFO                               NAMESPACE
          SampleCluster   SampleCluster   1cb2dc0b-0ae3-4d11-8be6-134366812874   default
*         confined-sa     SampleCluster   confined-sa
```

情報が変わりました。

ここで、再度podの情報を確認していきます。

```
# kubectl get pods
Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:default:confined-sa" cannot list resource "pods" in API group "" in the namespace "default"
```

しっかりブロックされました。

では、先ほど作成したClusterRoleを反映させていきます。

一旦、権限のあるContextに戻ります。

```
# kubectl config use-context SampleCluster
Switched to context "SampleCluster".
```

それでは、先ほど作っておいたclusterRoleBindingを適用します。

```
# kubectl apply -f clusterRoleBinding.yaml
clusterrolebinding.rbac.authorization.k8s.io/confined-rolebinding created
```

それでは、また先ほどのService AccountのContextに戻ります。

```
# kubectl config use-context confined-sa
Switched to context "confined-sa".
```

それでは、podが見れるかを確認します。

```
# kubectl get pods -n developing
NAME                                 READY   STATUS    RESTARTS   AGE
deploy-automation-54b5dd5779-wxnr4   1/1     Running   0          27h
```


できました！

ちなみに、podを作ったりはもちろんできません。

```
# kubectl run nginx --image nginx
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
Error from server (Forbidden): deployments.apps is forbidden: User "system:serviceaccount:default:confined-sa" cannot create resource "deployments" in API group "apps" in the namespace "default"
```

では最後に、全権限を持つユーザを消します。

```
# vi .kube/config
以下の2つを消す。
- context:
    cluster: SampleCluster
    namespace: default
    user: 1cb2dc0b-0ae3-4d11-8be6-134366812874
  name: SampleCluster
  
- name: 1cb2dc0b-0ae3-4d11-8be6-134366812874
  user:
    token: eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6IjFjYjJkYzBiLTBhZTMtNGQxMS04YmU2LTEzNDM2NjgxMjg3NC10b2tlbi04ZjdzbCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiIxY2IyZGMwYi0wYWUzLTRkMTEtOGJlNi0xMzQzNjY4MTI4NzQiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiI5OTc3NTI0MC1jZTQ0LTRhMjgtODNiYi04OGM2ZTNmMGI1NmMiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDoxY2IyZGMwYi0wYWUzLTRkMTEtOGJlNi0xMzQzNjY4MTI4NzQifQ.Xo5MGt4Tk246lJyzoX4ZlFGuJuY8_d0V8STtA49oaUXpghA470n3CxAOjAvH0v5YCVA7iM7U1GZsvyEGXupO46jeRE0py3X3qLqAP02J8jSP5lodRfY5VoyUOgmOqcPcqRiOgYJvJLEafyANL8iRy4fB0MdxWSoczUIJWi8wZGymNbMQ7h9vwrbCRAef9k-TAmFojAFkAyckjEJ6g5mk8Hk8Tgv-SgIfd7iK8dRY6E6flghKMhRHbaq62bC6Pr2OKmHUMdp2GJrenZ04V-BGpmkf69qCiZg-fZ8seA0jO9_ri8Z65K2NjVaTeIO2My1a-7osFxdnajr6gOaWRAw_VQ
```

それでは、contextもきれいにします。

```
# kubectl config delete-context SampleCluster
deleted context SampleCluster from /root/.kube/config

# kubectl config get-contexts
CURRENT   NAME          CLUSTER         AUTHINFO      NAMESPACE
*         confined-sa   SampleCluster   confined-sa
```

これで、このサーバはpodしか見れないようになりました。

# 終わりに
こんな感じで、これ以外にも誰かにある権限をもったServerを提供することができると思いますので、参考にしていただけたら嬉しいです。