まとめ
あんまりやる機会はないだろうけど、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
0
Namespace
を削除すると、動いている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
が残るのは勉強になった。