yoshikenがプログラミングや日記、ポエムを書いていくページです


90日後に死んだEKS

EKS1.21以上にすると90日後にサービスアカウントトークンの有効期限が来て死ぬ

TL;DR

  • KubernetesのBoundServiceAccountTokenVolumeにサービスアカウントトークンの有効期限が導入された
  • EKS1.21から上記機能がデフォルトで有効になっている
  • kube2iamやK8s-External-Secretなどで古いやつ使ってると90日後に有効期限が切れてサービスが死ぬ

何が起きたか

唐突に9/6以降のcron job達がクレデンシャルを取得できずに死んでいった。

不幸中の幸いでメインのサービスのserverは諸々の事情があってクレデンシャルはkube2iamで取得していなかったのでメインサービス自体は死ななかっった。

調査

とりあえず困ったらlogを見る。大事。

以下のlogが発見できクレデンシャル周りを疑う

failed fetch events: NoCredentialProviders: no valid providers in chain. Deprecated.\\\\n\\\\tFor verbose messaging see aws.Config.CredentialsChainVerboseErrors

最初はk8sの証明書周りが取得できないのかと思っていたが(前科あり)、問題なさそう。

AWS固有のクレデンシャル、つまりはIAM周りが怪しいのでは?とkub2iamのlogを見たら以下のlog

"E0905 16:42:08.534890       1 reflector.go:300] github.com/jtblin/kube2iam/vendor/k8s.io/client-go/tools/cache/reflector.go:94: Failed to watch *v1.Namespace: the server has asked for the client to provide credentials (get namespaces)\n"

つまりは 各podにIAMを割り振りするkube2iam自体がクレデンシャルを取得できない ということ。

kube2iamって何やねんって話はここではしないのでgithubでも見てくれ。

https://github.com/jtblin/kube2iam

特定

エラー文で検索してもいまいちピンとくる解決法が見当たらない。最近kube2iam周りも触った記憶も記録もない。

で、「もしかしたらAWSコンソール画面にヒントとかないかな〜。流石にご都合主義かな〜。」と見に行ったらあった。

Kubernetes BoundServiceAccountTokenVolume 機能 では、サービスアカウントトークンの有効期限が導入されました。この機能は EKS v1.21 以降のクラスターでデフォルトで有効になっています。API サーバーのリクエストエラーを回避するには、アプリケーションの依存関係を更新してサービスアカウントトークンを再取得する必要があります。

あーたしかにトークン切れたら出そうなエラーだな〜。でも最近式年遷宮したし可能性が低いかな〜。とか思いつつ少し深堀りした。

("式年遷宮"とは俗に言うClusterMigrationと呼ばれるやつで詳しくは過去に登壇したスライド見てくれ

https://docs.aws.amazon.com/eks/latest/userguide/kubernetes-versions.html#kubernetes-1.21

BoundServiceAccountTokenVolume graduated to beta and is enabled by default in Kubernetes version 1.21. This feature improves security of service account tokens by allowing workloads running on Kubernetes to request JSON web tokens that are audience, time, and key bound. Service account tokens now have an expiration of one hour. In previous Kubernetes versions, they didn't have an expiration. This means that clients that rely on these tokens must refresh the tokens within an hour. (中略) If your workload is using an older client version, then you must update it. To enable a smooth migration of clients to the newer time-bound service account tokens, Kubernetes version 1.21 adds an extended expiry period to the service account token over the default one hour. For Amazon EKS clusters, the extended expiry period is 90 days. Your Amazon EKS cluster's Kubernetes API server rejects requests with tokens older than 90 days. We recommend that you check your applications and their dependencies to make sure that the Kubernetes client SDKs are the same or later than the versions listed previously.

え"

For Amazon EKS clusters, the extended expiry period is 90 days. Your Amazon EKS cluster's Kubernetes API server rejects requests with tokens older than 90 days.

🤔

🤔🤔🤔🤔🤔🤔🤔🤔

$aws eks describe-cluster --name xxxxxxxxxxxx --query "cluster.createdAt" --output text
2022-06-06T22:29:01.251000+09:00
$kubectl get pod -n kube-system
NAME                                            READY   STATUS    RESTARTS   AGE
aws-load-balancer-controller-xxxxxxxxxxxxxxxx   1/1     Running   0          23h
aws-load-balancer-controller-xxxxxxxxxxxxxxxx   1/1     Running   0          23h
aws-node-xxxxx                                  1/1     Running   0          93d
aws-node-xxxxx                                  1/1     Running   0          93d
coredns-xxxxxxxxxx-xxxxx                        1/1     Running   0          93d
coredns-xxxxxxxxxx-xxxxx                        1/1     Running   0          93d
kube-proxy-xxxxx                                1/1     Running   0          93d
kube-proxy-xxxxx                                1/1     Running   0          93d
kube2iam-xxxxx                                  1/1     Running   0          93d
kube2iam-xxxxx                                  1/1     Running   0          93d
kubernetes-external-secrets-xxxxxxxxxxxxxxx     1/1     Running   2          92d

今日は9/8

障害は9/6

EKS及びkube2iam作成は6/6

もろに90日後やんけ!!!!!!!!!!!!!!!!!

対応

他にもサービスアカウントのtoken切れがいないか以下のクエリをCloudWatch Logs Insightsでコントロールプレーンのログで走らせる。弊社の場合しれっとkubernetes-external-secretsも死んでいた。(kube2iamもそうなんだが完全に死んでいるわけではなくたまにクレデンシャルが取れているときがあるのは結局謎だった

fields @timestamp
| filter @logStream like /kube-apiserver-audit/
| filter @message like /seconds after warning threshold/
| parse @message "subject: *, seconds after warning threshold:*\"" as subject, elapsedtime

もとより諸々のAPIやらmoduleが古いので最新にする予定だったが今回の障害で優先順位が上がった。

とりあえずの対応として新たにサービスアカウントのトークンさえ発行できればええんやろ精神で再起動でトークンを発行し直して、90日後のgoogleCalendarに予定を入れた。

$kubectl rollout restart daemonset kube2iam -n kube-system
$kubectl rollout restart deploy kubernetes-external-secrets -n kube-system

まとめ

本質的なところは前の記事でも書いたが、EKSアップデートの引き継ぎが中途半端だったというところに起因してしまう。

それでも強いて言うなら

パッチノートに赤文字で Important って書いてあるやつはちゃんと見ましょう。

AWSコンソール画面はチラチラ見にいきましょう。

アップデートはこまめにしましょう。

以上3点。得るものは少なった。リカバリーの工数は多かった。