まとめ
あんまりやる機会はないだろうけど、Podが生きている間にそれに紐づくNamespaceとServiceAccountを削除したときの挙動は次のようになる。
Podが生きている間にmetadata.namespaceのNamespaceを削除した場合Podが削除される
Podが生きている間にspec.serviceAccountNameのServiceAccountを削除した場合Podは削除されない- 自動マウントされた
ServiceAccount Tokenはそのまま残る- ただし
ServiceAccountが削除された時点でKubenretes APIの認証が通らなくなる
- ただし
環境
- kind
- v0.11.1 go1.17.3 darwin/amd64
- Kubernetes
- v1.21.1
もくじ
Namespace消す
とあるNamespaceでPodが生きているときに、kubectl delete namespaceしたらどうなるんだろう…?
# じゅんび
$ kubectl create namespace space-1
$ kubectl -n space-1 create serviceaccount user-1
$ kubectl -n space-1 run nginx --image=nginx --overrides='{ "spec": { "serviceAccountName" : "user-1" } }'
# Namespace: space-1でspec.serviceAccountName: user-1のPodが動いている状態
$ kubectl -n space-1 get pod nginx
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 15s
$ kubectl -n space-1 get pod nginx -o jsonpath="{.spec.serviceAccountName}"
user-1
# Podが動いてるNamespace消す
$ kubectl delete namespace space-1
namespace "space-1" deleted
# どこにもPodが残ってない
$ kubectl get pod -A | grep -c nginx
0Namespaceを削除すると、動いているPodがあっても一緒に削除されるらしい。
ServiceAccount消す
今度はPodのspec.serviceAccountNameに指定されたServiceAccountをPodが生きている間に消してみる。
# さっきと同じ状態
$ kubectl -n space-1 get pod nginx
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 15s
$ kubectl -n space-1 get pod nginx -o jsonpath="{.spec.serviceAccountName}"
user-1
$ kubectl -n space-1 get serviceaccount user-1
NAME SECRETS AGE
user-1 1 75s
# Podに紐付いてるServiceAccount消す
$ kubectl -n space-1 delete serviceaccount user-1
serviceaccount "user-1" deleted
# Podは生きてる上にserviceAccountNameもそのまま
$ kubectl -n space-1 get pod nginx
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 2m46s
$ kubectl -n space-1 get pod nginx -o jsonpath="{.spec.serviceAccountName}"
user-1
# PodにマウントされているServiceAccount Tokenは削除したServiceAccountのものが残っている
$ kubectl -n space-1 get pod nginx -o jsonpath="{.spec.volumes}"
[{"name":"kube-api-access-fdd7d","projected":{"defaultMode":420,"sources":[{"serviceAccountToken":{"expirationSeconds":3607,"path":"token"}},{"configMap":{"items":[{"key":"ca.crt","path":"ca.crt"}],"name":"kube-root-ca.crt"}},{"downwardAPI":{"items":[{"fieldRef":{"apiVersion":"v1","fieldPath":"metadata.namespace"},"path":"namespace"}]}}]}}]
$ kubectl -n space-1 exec nginx -it -- cat /var/run/secrets/kubernetes.io/serviceaccount/token | jq -R 'split(".") | .[1] | @base64d | fromjson | ."kubernetes.io"'
{
"namespace": "space-1",
"pod": {
"name": "nginx",
"uid": "c1595cec-699d-41dd-bb51-6f648b23e832"
},
"serviceaccount": {
"name": "user-1",
"uid": "e1d20d3d-5f9f-4ab0-b8e0-d021a42d189c"
},
"warnafter": 1637856366
}なるほど…?
Podのspec.serviceAccountNameに指定されたServiceAccountが削除されてもPodは消されることはなく、volumeとしてコンテナにマウントされたServiceAccount Tokenもそのままの状態で残るらしい。
じゃあそのTokenを使ったKubernetes APIの認証/認可はどうなるんだろう?
# またまたさっきと同じ状態
$ kubectl -n space-1 get pod nginx
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 15s
$ kubectl -n space-1 get pod nginx -o jsonpath="{.spec.serviceAccountName}"
user-1
$ kubectl -n space-1 get serviceaccount user-1
NAME SECRETS AGE
user-1 1 75s
# user-1にspace-1のPod操作権限を付与
$ kubectl -n space-1 create role pod-owner --verb="*" --resource="pods"
$ kubectl -n space-1 create rolebinding pod-owner-bind --role=pod-owner --serviceaccount=space-1:user-1
# この状態でServiceAccount Tokenを用いてKubernetes APIをたたくと成功(200 OK)する
$ kubectl -n space-1 exec nginx -it -- bash -c 'curl --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt --header "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" -I -X GET https://kubernetes.default.svc/api/v1/namespaces/space-1/pods'
HTTP/2 200
...
# ServiceAccountを削除
$ kubectl -n space-1 delete serviceaccount user-1
# Podに残ったServiceAccount Tokenを用いてKubernetes APIをたたくと失敗(401 Unauthorized)する
$ kubectl -n space-1 exec nginx -it -- bash -c 'curl --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt --header "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" -I -X GET https://kubernetes.default.svc/api/v1/namespaces/space-1/pods'
HTTP/2 401
...
# 同名のServiceAccountを再作成
$ kubectl -n space-1 create serviceaccount user-1
# しかし結果は変わらず
$ kubectl -n space-1 exec nginx -it -- bash -c 'curl --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt --header "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" -I -X GET https://kubernetes.default.svc/api/v1/namespaces/space-1/pods'
HTTP/2 401
...はえ〜
ServiceAccountが削除された時点でTokenでの認証ができなくなるみたい。
後から同名のServiceAccountを作ってもたぶんTokenのuidが新しいServiceAccountと合わないから認証ができないんじゃないかな…?
ちなみにkubectl edit podでspec.serviceAccountNameをいじろうとすると
Forbidden: pod updates may not change fields other than `spec.containers[*].image`, `spec.initContainers[*].image`, `spec.activeDeadlineSeconds` or `spec.tolerations` (only additions to existing tolerations)`
って怒られちゃうので、Podが生きてる間にServiceAccountを消してしまった場合はそのTokenでのAPI認証は諦めてPodを作り直すのがよさそう。
(というかPodが生きているうちはあまり消さないほうがいい)
おわり
こんなことは普段仕事でKubernetesを運用しているときは絶対やらないとは思うけど、すこし気になったので試してみた。
NamespaceもServiceAccountもPodを巻き添えにして削除されるものだと思いこんでいたので、ServiceAccountが消えてもPodとマウントされたTokenが残るのは勉強になった。
おまけ

