【Kubernetes】ServiceAccountについて理解する
はじめに
Service Accountについて、動かしながら基本的な部分を理解していきたいと思います。
ServiceAccountとは
サービスアカウント(Service Account)は、Kubernetes内で管理されているアカウントで、Podと紐づけることでPodからKubernetesAPIを操作できるようになります。
【Kubernetes】ユーザー管理について理解する
はじめに Kubernetesのユーザーについてざっくりまとめて、実際にユーザーを作成(?)して
Service Accountは、Podに紐づいたAPIの認証情報であるtokenを利用して、PodからKubernetesAPIを利用します。
ver1.24から、今まで自動で作成されていたtoken用のSecretが作成されなくなり、Pod内にtokenが紐付くようになったようです。
kubernetes/CHANGELOG/CHANGELOG-1.24.md at master · kubernetes/kubernetes
Production-Grade Container Scheduling and Management - 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 specification or in a container image. Using a Secret means that you don't need to include confidential data in your application code. Because Secrets can be created independently of the Pods that use them, there is less risk of the Secret (and its data) being exposed during the workflow of creating, viewing, and editing Pods.
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. But it returns as below. apiVersion: v1
defaultのServiceAccount
まずは、各Namespaceにデフォルトで作成されるdefault
というServiceAccountについて、確認していきます。
1❯ kubectl get sa
2NAME SECRETS AGE
3default 0 4h39m
4
5
6❯ kubectl describe sa default
7Name: default
8Namespace: default
9Labels: <none>
10Annotations: <none>
11Image pull secrets: <none>
12Mountable secrets: <none>
13Tokens: <none>
14Events: <none>
自分で作成していないdefault
というServiceAccountが確認できます。また、SECRETSの列が0になっており、tokenも紐づいていなくなっていることがわかります。
defaultのServiceAccountとPod
このdefault
というアカウントがどのように使われているか確認します。
まず、簡単なPodを作成します。
1apiVersion: v1
2kind: Pod
3metadata:
4 name: nginx
5spec:
6 containers:
7 - image: nginx
8 name: nginx
1kubectl apply -f nginx.yml
作成されたPodをyaml形式で確認してみます。
1❯ kubectl get pod
2NAME READY STATUS RESTARTS AGE
3nginx 1/1 Running 0 19s
4
5
6❯ kubectl get pod nginx -o yaml
7apiVersion: v1
8kind: Pod
9
10...
11
12spec:
13 containers:
14 - image: nginx
15 imagePullPolicy: Always
16 name: nginx
17
18 ...
19
20 volumeMounts:
21 - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
22 name: kube-api-access-d9mtw
23 readOnly: true
24
25 ...
26
27 serviceAccount: default
28 serviceAccountName: default
29
30 ...
31
32 volumes:
33 - name: kube-api-access-d9mtw
34 projected:
35 defaultMode: 420
36 sources:
37 - serviceAccountToken:
38 expirationSeconds: 3607
39 path: token
40
41...
default
のServiceAccountが自動で利用されており、token用のボリュームがマウントされていることが確認できます。
マウントされているtokenのファイルを見てみます。
1❯ kubectl exec -it nginx -- ls /var/run/secrets/kubernetes.io/serviceaccount
2ca.crt namespace token
3
4
5❯ kubectl exec -it nginx -- cat /var/run/secrets/kubernetes.io/serviceaccount/token
6eyJhbGciOiJSUzI1NiIsImtpZCI6InF2TDhTTHNtenhubFpZcnpwbU5UV2hOSjlYWHpyY0loNzdDREJIZGdwa0kifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNjg2NDU5ODk1LCJpYXQiOjE2NTQ5MjM4OTUsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0IiwicG9kIjp7Im5hbWUiOiJuZ2lueCIsInVpZCI6IjkwZmYxNjM0LTBkZWEtNDViOC04OWU2LWY5YzBlYjI2NDE0YyJ9LCJzZXJ2aWNlYWNjb3VudCI6eyJuYW1lIjoiZGVmYXVsdCIsInVpZCI6Ijk2MDE0NzE0LWViOTctNDEyYy1hYjZlLWYzY2FjZjEwNDQ3ZSJ9LCJ3YXJuYWZ0ZXIiOjE2NTQ5Mjc1MDJ9LCJuYmYiOjE2NTQ5MjM4OTUsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.tRGnrq3F0zVDZGk_lquPVsApIGtRkxxJWs_dvD3kUcktqdwtkT3nUKt5nr7RwJEA__O7yL3PmbdMqD0HevulnOyTQouoA3Ieu7Q8w539KmBJfXozB-1vzmi0XJVExv7SAx3JfOA-QQRn9I_CQSQXuZkXRnypWZ_i15uNMsC2CskEyW3UuwbVl0O79rI7p6OWT1pusmuPjBZCLF9c6ZgsC3bqbFihaXkU8_fmkGyuF4JQy6EqxCwYOmestCgYAVM9uYtA_yavwcNnqgDOctUKQeftcIvKxThNx2cQDaDe1a6RrnWvE6jytCFH9lLsohsS2zbQPl-uFYW73tnLjw4rlQ
token用のファイルがあり、その中にJWTが記述されています。
試しにデコードすると、tokenの内容が確認できます。
1❯ jwt decode "eyJhbGciOiJSUzI1NiIsImtpZCI6InF2TDhTTHNtenhubFpZcnpwbU5UV2hOSjlYWHpyY0loNzdDREJIZGdwa0kifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNjg2NDU5ODk1LCJpYXQiOjE2NTQ5MjM4OTUsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0IiwicG9kIjp7Im5hbWUiOiJuZ2lueCIsInVpZCI6IjkwZmYxNjM0LTBkZWEtNDViOC04OWU2LWY5YzBlYjI2NDE0YyJ9LCJzZXJ2aWNlYWNjb3VudCI6eyJuYW1lIjoiZGVmYXVsdCIsInVpZCI6Ijk2MDE0NzE0LWViOTctNDEyYy1hYjZlLWYzY2FjZjEwNDQ3ZSJ9LCJ3YXJuYWZ0ZXIiOjE2NTQ5Mjc1MDJ9LCJuYmYiOjE2NTQ5MjM4OTUsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.tRGnrq3F0zVDZGk_lquPVsApIGtRkxxJWs_dvD3kUcktqdwtkT3nUKt5nr7RwJEA__O7yL3PmbdMqD0HevulnOyTQouoA3Ieu7Q8w539KmBJfXozB-1vzmi0XJVExv7SAx3JfOA-QQRn9I_CQSQXuZkXRnypWZ_i15uNMsC2CskEyW3UuwbVl0O79rI7p6OWT1pusmuPjBZCLF9c6ZgsC3bqbFihaXkU8_fmkGyuF4JQy6EqxCwYOmestCgYAVM9uYtA_yavwcNnqgDOctUKQeftcIvKxThNx2cQDaDe1a6RrnWvE6jytCFH9lLsohsS2zbQPl-uFYW73tnLjw4rlQ"
2
3Token header
4------------
5{
6 "alg": "RS256",
7 "kid": "qvL8SLsmzxnlZYrzpmNTWhNJ9XXzrcIh77CDBHdgpkI"
8}
9
10Token claims
11------------
12{
13 "aud": [
14 "https://kubernetes.default.svc.cluster.local"
15 ],
16 "exp": 1686459895,
17 "iat": 1654923895,
18 "iss": "https://kubernetes.default.svc.cluster.local",
19 "kubernetes.io": {
20 "namespace": "default",
21 "pod": {
22 "name": "nginx",
23 "uid": "90ff1634-0dea-45b8-89e6-f9c0eb26414c"
24 },
25 "serviceaccount": {
26 "name": "default",
27 "uid": "96014714-eb97-412c-ab6e-f3cacf10447e"
28 },
29 "warnafter": 1654927502
30 },
31 "nbf": 1654923895,
32 "sub": "system:serviceaccount:default:default"
33}
ServiceAccountを作成する
次は、自分でServiceAccountを作成してみます。
1apiVersion: v1
2kind: ServiceAccount
3metadata:
4 name: test-sa
1kubectl apply -f test-sa.yml
test-sa
というServiceAccountが作成できました。Secretもtokenも紐付いていません。
1❯ kubectl get sa
2NAME SECRETS AGE
3default 0 5h18m
4test-sa 0 6m37s
5
6
7❯ kubectl describe sa test-sa
8Name: test-sa
9Namespace: default
10Labels: <none>
11Annotations: <none>
12Image pull secrets: <none>
13Mountable secrets: <none>
14Tokens: <none>
15Events: <none>
作成したServiceAccountをPodに紐付ける
作成したtest-sa
にRoleをつけて、Podに紐付けて、動きを見ていきます。
作成するRoleはPodの読み取り権限です。RoleBindingを使って、test-sa
にRoleを付与します。
1apiVersion: rbac.authorization.k8s.io/v1
2kind: Role
3metadata:
4 name: role-pod-read
5 namespace: default
6rules:
7 - apiGroups: [""]
8 resources: ["pods"]
9 verbs: ["get", "watch", "list"]
10---
11apiVersion: rbac.authorization.k8s.io/v1
12kind: RoleBinding
13metadata:
14 name: service-account-rolebinding
15 namespace: default
16subjects:
17 - kind: ServiceAccount
18 name: test-sa
19roleRef:
20 kind: Role
21 name: role-pod-read
22 apiGroup: rbac.authorization.k8s.io
1kubectl apply -f role.yml
次に、test-sa
を紐づけるPodを作成します。kubectl get pod
を実行するコンテナになります。
1apiVersion: v1
2kind: Pod
3metadata:
4 name: kubectl-pod
5spec:
6 containers:
7 - image: bitnami/kubectl
8 name: kubectl
9 command:
10 - sh
11 - -c
12 - |
13 while true
14 do
15 kubectl get pod
16 sleep 30
17 done
18 serviceAccountName: test-sa
1kubectl apply -f kubectl-pod.yml
ログを確認すると、kubectl get pod
が実行できていることが確認できます。
1❯ kubectl logs kubectl-pod
2NAME READY STATUS RESTARTS AGE
3kubectl-pod 0/1 ContainerCreating 0 4s
4nginx 1/1 Running 0 51m
5NAME READY STATUS RESTARTS AGE
6kubectl-pod 1/1 Running 0 34s
7nginx 1/1 Running 0 51m
8NAME READY STATUS RESTARTS AGE
9kubectl-pod 1/1 Running 0 64s
10nginx 1/1 Running 0 52m
試しに、kubectl get deploy
に変更してみると、下記のようなエラーになります。
1❯ kubectl logs kubectl-pod
2Error 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
参考
- Configure Service Accounts for Pods | Kubernetes
- Secrets | Kubernetes
- kubernetes - Service account secret is not listed. How to fix it? - Stack Overflow
- kubernetes/CHANGELOG-1.24.md at master · kubernetes/kubernetes
- BIG change in K8s 1.24 about ServiceAccounts and their Secrets | by Kim Wuestkamp | May, 2022 | ITNEXT
- ContainerSolutions/kubernetes-examples: Minimal self-contained examples of standard Kubernetes features and patterns in YAML
- bitnami/kubectl - Docker Image | Docker Hub