【Kubernetes】ServiceAccountについて理解する

スポンサーリンク

はじめに

Service Accountについて、動かしながら基本的な部分を理解していきたいと思います。

ServiceAccountとは

サービスアカウント(Service Account)は、Kubernetes内で管理されているアカウントで、Podと紐づけることでPodからKubernetesAPIを操作できるようになります。

【Kubernetes】ユーザー管理について理解する
はじめにKubernetesのユーザーについてざっくりまとめて、実際にユーザーを作成(?)してみました。KubernetesでのユーザーKubernetesには以下の2種類のユーザーがあります。ユーザー(いわゆる通常のユーザー)...

Service Accountは、Podに紐づいたAPIの認証情報であるtokenを利用して、PodからKubernetesAPIを利用します。

ver1.24から、今まで自動で作成されていたtoken用のSecretが作成されなくなり、Pod内にtokenが紐付くようになったようです。

kubernetes/CHANGELOG-1.24.md at master · kubernetes/kubernetes
Production-Grade Container Scheduling and Management - kubernetes/CHANGELOG-1.24.md at master · kubernetes/kubernetes
Secrets
A Secret is an object that contains a small amount of sensitive data such as a password, a token, or a key. Such information might otherwise be put in a Pod spe...
Service account secret is not listed. How to fix it?
I have used kubectl create serviceaccount sa1 to create service account. Then I used kubectl get serviceaccount sa1 -oyaml command to get service account info. ...

defaultのServiceAccount

まずは、各Namespaceにデフォルトで作成されるdefaultというServiceAccountについて、確認していきます。

❯ kubectl get sa
NAME      SECRETS   AGE
default   0         4h39m

❯ kubectl describe sa default
Name:                default
Namespace:           default
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none>
Mountable secrets:   <none>
Tokens:              <none>
Events:              <none>

自分で作成していないdefaultというServiceAccountが確認できます。また、SECRETSの列が0になっており、tokenも紐づいていなくなっていることがわかります。

defaultのServiceAccountとPod

このdefaultというアカウントがどのように使われているか確認します。

まず、簡単なPodを作成します。

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - image: nginx
    name: nginx
kubectl apply -f nginx.yml

作成されたPodをyaml形式で確認してみます。

❯ kubectl get pod
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          19s

❯ kubectl get pod nginx -o yaml
apiVersion: v1
kind: Pod

...

spec:
  containers:
  - image: nginx
    imagePullPolicy: Always
    name: nginx

    ...

    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: kube-api-access-d9mtw
      readOnly: true

  ...

  serviceAccount: default
  serviceAccountName: default

  ...

  volumes:
  - name: kube-api-access-d9mtw
    projected:
      defaultMode: 420
      sources:
      - serviceAccountToken:
          expirationSeconds: 3607
          path: token

...

defaultのServiceAccountが自動で利用されており、token用のボリュームがマウントされていることが確認できます。

マウントされているtokenのファイルを見てみます。

❯ kubectl exec -it nginx -- ls /var/run/secrets/kubernetes.io/serviceaccount
ca.crt  namespace  token

❯ kubectl exec -it nginx -- cat /var/run/secrets/kubernetes.io/serviceaccount/token
eyJhbGciOiJSUzI1NiIsImtpZCI6InF2TDhTTHNtenhubFpZcnpwbU5UV2hOSjlYWHpyY0loNzdDREJIZGdwa0kifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNjg2NDU5ODk1LCJpYXQiOjE2NTQ5MjM4OTUsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0IiwicG9kIjp7Im5hbWUiOiJuZ2lueCIsInVpZCI6IjkwZmYxNjM0LTBkZWEtNDViOC04OWU2LWY5YzBlYjI2NDE0YyJ9LCJzZXJ2aWNlYWNjb3VudCI6eyJuYW1lIjoiZGVmYXVsdCIsInVpZCI6Ijk2MDE0NzE0LWViOTctNDEyYy1hYjZlLWYzY2FjZjEwNDQ3ZSJ9LCJ3YXJuYWZ0ZXIiOjE2NTQ5Mjc1MDJ9LCJuYmYiOjE2NTQ5MjM4OTUsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.tRGnrq3F0zVDZGk_lquPVsApIGtRkxxJWs_dvD3kUcktqdwtkT3nUKt5nr7RwJEA__O7yL3PmbdMqD0HevulnOyTQouoA3Ieu7Q8w539KmBJfXozB-1vzmi0XJVExv7SAx3JfOA-QQRn9I_CQSQXuZkXRnypWZ_i15uNMsC2CskEyW3UuwbVl0O79rI7p6OWT1pusmuPjBZCLF9c6ZgsC3bqbFihaXkU8_fmkGyuF4JQy6EqxCwYOmestCgYAVM9uYtA_yavwcNnqgDOctUKQeftcIvKxThNx2cQDaDe1a6RrnWvE6jytCFH9lLsohsS2zbQPl-uFYW73tnLjw4rlQ

token用のファイルがあり、その中にJWTが記述されています。

試しにデコードすると、tokenの内容が確認できます。

❯ jwt decode "eyJhbGciOiJSUzI1NiIsImtpZCI6InF2TDhTTHNtenhubFpZcnpwbU5UV2hOSjlYWHpyY0loNzdDREJIZGdwa0kifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNjg2NDU5ODk1LCJpYXQiOjE2NTQ5MjM4OTUsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0IiwicG9kIjp7Im5hbWUiOiJuZ2lueCIsInVpZCI6IjkwZmYxNjM0LTBkZWEtNDViOC04OWU2LWY5YzBlYjI2NDE0YyJ9LCJzZXJ2aWNlYWNjb3VudCI6eyJuYW1lIjoiZGVmYXVsdCIsInVpZCI6Ijk2MDE0NzE0LWViOTctNDEyYy1hYjZlLWYzY2FjZjEwNDQ3ZSJ9LCJ3YXJuYWZ0ZXIiOjE2NTQ5Mjc1MDJ9LCJuYmYiOjE2NTQ5MjM4OTUsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.tRGnrq3F0zVDZGk_lquPVsApIGtRkxxJWs_dvD3kUcktqdwtkT3nUKt5nr7RwJEA__O7yL3PmbdMqD0HevulnOyTQouoA3Ieu7Q8w539KmBJfXozB-1vzmi0XJVExv7SAx3JfOA-QQRn9I_CQSQXuZkXRnypWZ_i15uNMsC2CskEyW3UuwbVl0O79rI7p6OWT1pusmuPjBZCLF9c6ZgsC3bqbFihaXkU8_fmkGyuF4JQy6EqxCwYOmestCgYAVM9uYtA_yavwcNnqgDOctUKQeftcIvKxThNx2cQDaDe1a6RrnWvE6jytCFH9lLsohsS2zbQPl-uFYW73tnLjw4rlQ"

Token header
------------
{
  "alg": "RS256",
  "kid": "qvL8SLsmzxnlZYrzpmNTWhNJ9XXzrcIh77CDBHdgpkI"
}

Token claims
------------
{
  "aud": [
    "https://kubernetes.default.svc.cluster.local"
  ],
  "exp": 1686459895,
  "iat": 1654923895,
  "iss": "https://kubernetes.default.svc.cluster.local",
  "kubernetes.io": {
    "namespace": "default",
    "pod": {
      "name": "nginx",
      "uid": "90ff1634-0dea-45b8-89e6-f9c0eb26414c"
    },
    "serviceaccount": {
      "name": "default",
      "uid": "96014714-eb97-412c-ab6e-f3cacf10447e"
    },
    "warnafter": 1654927502
  },
  "nbf": 1654923895,
  "sub": "system:serviceaccount:default:default"
}

ServiceAccountを作成する

次は、自分でServiceAccountを作成してみます。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: test-sa
kubectl apply -f test-sa.yml

test-saというServiceAccountが作成できました。Secretもtokenも紐付いていません。

❯ kubectl get sa
NAME      SECRETS   AGE
default   0         5h18m
test-sa   0         6m37s

❯ kubectl describe sa test-sa
Name:                test-sa
Namespace:           default
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none>
Mountable secrets:   <none>
Tokens:              <none>
Events:              <none>

作成したServiceAccountをPodに紐付ける

作成したtest-saにRoleをつけて、Podに紐付けて、動きを見ていきます。

作成するRoleはPodの読み取り権限です。RoleBindingを使って、test-saにRoleを付与します。

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: role-pod-read
  namespace: default
rules:
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get", "watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: service-account-rolebinding
  namespace: default
subjects:
  - kind: ServiceAccount
    name: test-sa
roleRef:
  kind: Role
  name: role-pod-read
  apiGroup: rbac.authorization.k8s.io
kubectl apply -f role.yml

次に、test-saを紐づけるPodを作成します。kubectl get podを実行するコンテナになります。

apiVersion: v1
kind: Pod
metadata:
  name: kubectl-pod
spec:
  containers:
  - image: bitnami/kubectl
    name: kubectl
    command:
    - sh
    - -c
    - |
      while true
      do
        kubectl get pod
        sleep 30
      done
  serviceAccountName: test-sa
kubectl apply -f kubectl-pod.yml

ログを確認すると、kubectl get podが実行できていることが確認できます。

❯ kubectl logs kubectl-pod
NAME          READY   STATUS              RESTARTS   AGE
kubectl-pod   0/1     ContainerCreating   0          4s
nginx         1/1     Running             0          51m
NAME          READY   STATUS    RESTARTS   AGE
kubectl-pod   1/1     Running   0          34s
nginx         1/1     Running   0          51m
NAME          READY   STATUS    RESTARTS   AGE
kubectl-pod   1/1     Running   0          64s
nginx         1/1     Running   0          52m

試しに、kubectl get deployに変更してみると、下記のようなエラーになります。

❯ kubectl logs kubectl-pod
Error from server (Forbidden): deployments.apps is forbidden: User "system:serviceaccount:default:test-sa" cannot list resource "deployments" in API group "apps" in the namespace "default

参考

タイトルとURLをコピーしました