[Kubernetes]ServiceAccountの動作を確認する

#はじめに
ServiceAccountは、Podで実行されるプロセスの認証、許可を行います。Pod起動時には必ず割り当てる必要があり、指定しない場合は「default」ServiceAccountが割り当てられます。

#ServiceAccountの作成

以下のマニフェストのServiceAccountを作成します。

```serviceAccount01.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: service-account01
automountServiceAccountToken: false #Podデプロイ時にトークンを自動マウントするかどうか
```

```
$ kubectl apply -f serviceAccount01.yaml
serviceaccount/service-account01 created
$ kubectl get serviceaccounts
NAME                SECRETS   AGE
default             1         112d
service-account01   1         16s
```

「default」はデフォルトのServiceAccountで、Pod作成時に何も指定しなければこれが割り当てられます。

##ServiceAccountの確認

作成したServiceAccountの詳細を確認します。
ServiceAccountを作成すると、それに紐づくSecretが作成されています。

```
$ kubectl get serviceaccounts service-account01 -o yaml
apiVersion: v1
automountServiceAccountToken: false
kind: ServiceAccount
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","automountServiceAccountToken":false,"kind":"ServiceAccount","metadata":{"annotations":{},"name":"service-account01","namespace":"default"}}
  creationTimestamp: "2020-06-17T12:49:24Z"
  name: service-account01
  namespace: default
  resourceVersion: "1842148"
  selfLink: /api/v1/namespaces/default/serviceaccounts/service-account01
  uid: aab6d349-f30a-4206-9575-118e1c083a60
secrets:
- name: service-account01-token-qfdgb
```

Secretを確認します。

```
$ kubectl get secrets
NAME                            TYPE                                  DATA   AGE
default-token-nstst             kubernetes.io/service-account-token   3      112d
service-account01-token-qfdgb   kubernetes.io/service-account-token   3      55s

$ kubectl get secrets service-account01-token-qfdgb -o yaml
apiVersion: v1
data:
  ca.crt: LS0tLS1CRU・・・
  token: ZXlKaGJHY2lPaUpTVXpJM・・・・
kind: Secret
metadata:
  annotations:
    kubernetes.io/service-account.name: service-account01
    kubernetes.io/service-account.uid: aab6d349-f30a-4206-9575-118e1c083a60
  creationTimestamp: "2020-06-17T12:49:24Z"
  name: service-account01-token-qfdgb
  namespace: default
  resourceVersion: "1842147"
  selfLink: /api/v1/namespaces/default/secrets/service-account01-token-qfdgb
  uid: 3ea76e94-e939-4abf-b155-87f66e37beb3
type: kubernetes.io/service-account-token
```

#Podの作成

作成したServiceAccountを指定してPodをデプロイします。

```pod01.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod01
spec:
  containers:
  - name: nginx
    image: nginx:latest
  serviceAccountName: service-account01
  automountServiceAccountToken: true #トークンを自動マウントする
```

ServiceAccount作成時にトークの自動マウント（automountServiceAccountToken）はfalseにしましたが、Podのマニフェストではtrueにしています。
ServiceAccountとPodの両方でautomountServiceAccountTokenが設定された場合は、Podの設定が優先されます。

このマニフェストをapplyして、Podの詳細を確認します。

```
$ kubectl apply -f pod01.yaml
pod/nginx-pod01 created
$ kubectl get pod nginx-pod01 -o yaml
apiVersion: v1
kind: Pod
metadata:
・・・
spec:
  automountServiceAccountToken: true
  containers:
・・・
    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: service-account01-token-qfdgb
      readOnly: true
・・・
```

SecretがVolumeとしてマウントされていますね。

コンテナにログインして確認します。

```
$ kubectl exec -it nginx-pod01 ls /var/run/secrets/kubernetes.io/serviceaccount
ca.crt  namespace  token
$ kubectl exec -it nginx-pod01 cat /var/run/secrets/kubernetes.io/serviceaccount/token
eyJhbGciOiJSUzI1NiIsImtpZCI6・・・
```

#トークンを利用したAPI Serverへのアクセス
ServiceAccountのトークンをAPI Serverへの認証情報として利用できます。これによって、PodからAPIサーバに対してコマンドを実行できるようになります。

##RBACの設定
ServiceAccountとClusterRoleを紐づけます。

###ClusterRole
まずはクラスタにあるClusterRoleを確認します。

```
$ kubectl get clusterrole
NAME                                                                   AGE
admin                                                                  112d
calico-kube-controllers                                                112d
calico-node                                                            112d
cluster-admin                                                          112d
edit                                                                   112d
metallb-system:controller                                              69d
metallb-system:speaker                                                 69d
system:aggregate-to-admin                                              112d
system:aggregate-to-edit                                               112d
・・・
view                                                                   112d
$ kubectl describe clusterrole view
Name:         view
Labels:       kubernetes.io/bootstrapping=rbac-defaults
              rbac.authorization.k8s.io/aggregate-to-edit=true
Annotations:  rbac.authorization.kubernetes.io/autoupdate: true
PolicyRule:
  Resources                                    Non-Resource URLs  Resource Names  Verbs
  ---------                                    -----------------  --------------  -----
  bindings                                     []                 []              [get list watch]
  configmaps                                   []                 []              [get list watch]
  endpoints                                    []                 []              [get list watch]
  events                                       []                 []              [get list watch]
  limitranges                                  []                 []              [get list watch]
  namespaces/status                            []                 []              [get list watch]
  namespaces                                   []                 []              [get list watch]
  persistentvolumeclaims/status                []                 []              [get list watch]
  persistentvolumeclaims                       []                 []              [get list watch]
  pods/log                                     []                 []              [get list watch]
  pods/status                                  []                 []              [get list watch]
  pods                                         []                 []              [get list watch]
```

「View」というClusterRoleにはPodのget/list/watchの権限がありますので、これとServiceAccountを紐づけます。

###ClusterRoleBinding

以下のマニフェストをapplyします。

```clusterRoleBinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: cluster-role-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: view
subjects:
- kind: ServiceAccount
  name: service-account01
  namespace: default
```

```
$ kubectl apply -f clusterRoleBinding.yaml
clusterrolebinding.rbac.authorization.k8s.io/cluster-role-binding created
$ kubectl get clusterrolebindings.rbac.authorization.k8s.io cluster-role-binding
NAME                   AGE
cluster-role-binding   75s
$ kubectl describe clusterrolebindings.rbac.authorization.k8s.io cluster-role-binding
Name:         cluster-role-binding
Labels:       <none>
Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                {"apiVersion":"rbac.authorization.k8s.io/v1","kind":"ClusterRoleBinding","metadata":{"annotations":{},"name":"cluster-role-binding"},"role...
Role:
  Kind:  ClusterRole
  Name:  view
Subjects:
  Kind            Name               Namespace
  ----            ----               ---------
  ServiceAccount  service-account01  default
```

Viewとservice-account01が紐づいたことがわかります。
これでservice-account01が割り当てられたPodは「View」と同じ権限を持ったことになります。

##確認
コンテナにログインして確認します。

```
$ kubectl exec -it nginx-pod01 /bin/bash
root@nginx-pod01:/# TOKEN=`cat /var/run/secrets/kubernetes.io/serviceaccount/token`
root@nginx-pod01:/# curl -H "Authorization: Bearer ${TOKEN}" --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt https://kubernetes/api/v1/namespaces/default/pods
{
  "kind": "PodList",
  "apiVersion": "v1",
  "metadata": {
    "selfLink": "/api/v1/namespaces/default/pods",
    "resourceVersion": "1850682"
  },
  "items": [
    {
      "metadata": {
        "name": "nginx-pod01",
・・・
```

Podのリストが表示されていますね。

#まとめ
今回はServiceAccountの動作を確認しました。セキュリティは大事ですので、しっかりと押さえないといけないですね。
これだけではなく、RBACなどもこれから確認したいと思います。