ある日開発環境のEKSのマネージドノードが突然クラスタに参加不可の状態になりました。
単純に自分の理解が足りてなかっただけなのですが、調査方法等のTipsを残しておきたいと思います。
事象
開発環境で開発をしていたら、ノードが全てNot Readyになっていました。
kubelet[14180]: E0106 06:58:01.678158 14180 reflector.go:178] k8s.io/kubernetes/pkg/kubelet/config/apiserver.go:46: Failed to list *v1.Pod: Unauthorized
kubelet[14180]: E0106 06:58:02.269813 14180 controller.go:136] failed to ensure node lease exists, will retry in 7s, error: Unauthorized
kubelet[14180]: E0106 07:00:31.476224 14180 kubelet_node_status.go:92] Unable to register node "ip-xxx-xxx-xxx-xxx.ap-northeast-1.compute.internal" with API server: Unauthorized
kubelet[14180]: E0106 07:11:24.484369 14180 reflector.go:178] k8s.io/client-go/informers/factory.go:135: Failed to list *v1.CSIDriver: Unauthorized
原因
今回の原因は画面にもメッセージに出ている通り、aws-authのConfigMapの不備でした。
以下のURLにもあるような、マネージドノードのロールマッピングが手違いで消えてしまったのが原因でした。
apiVersion: v1
kind: ConfigMap
metadata:
name: aws-auth
namespace: kube-system
data:
mapRoles: |
- rolearn: <ARN of instance role (not instance profile)>
username: system:node:{{EC2PrivateDNSName}}
groups:
- system:bootstrappers
- system:nodes
調査メモ
調査や調整に使えるTipsができたので、書いておきます。
Unauthorisedということで権限が問題なのですが、どこで権限を取得しているかをまず確認します。
kubeletは以下の設定ファイルを見ています。
ここを見るとわかるのですがaws-iam-authenticatorを使ってトークンを取得して、そのトークンを clusters.cluster.server
で定義されているサーバーに投げて認証しています。
$ cat /var/lib/kubelet/kubeconfig
apiVersion: v1
kind: Config
clusters:
- cluster:
certificate-authority: /etc/kubernetes/pki/ca.crt
server: https://xxxxxxxxxxxx.yyy.ap-northeast-1.eks.amazonaws.com
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubelet
name: kubelet
current-context: kubelet
users:
- name: kubelet
user:
exec:
apiVersion: client.authentication.k8s.io/v1alpha1
command: /usr/bin/aws-iam-authenticator
args:
- "token"
- "-i"
- "YourClusterName"
- --region
- "ap-northeast-1"
この動きをコマンドで追っていきます。これができるとチェックの手間が省けます。
# END_POINT= </var/lib/kubelet/kubeconfigのclusters.cluster.serverを設定>
# 以下で取得も可能
CLUSTER_NAME=YourClusterName
REGION=ap-northeast-1
END_POINT=$(aws eks describe-cluster --region ${REGION} --name ${CLUSTER_NAME} | jq -r '.cluster.endpoint')
# Kubeletが認証に使っているトークンを取得
# aws-iam-authenticatorは引数のクラスタ名やRegionが間違っていてもトークン取得できるので注意してください
USER_TOKEN=$(/usr/bin/aws-iam-authenticator token -i ${CLUSTER_NAME}--region ${REGION} --token-only)
# 認証処理を投げてみる
curl -XPOST --insecure ${END_POINT}/apis/authentication.k8s.io/v1/tokenreviews \
-H "Authorization: Bearer ${USER_TOKEN}" \
-H "Content-Type: application/json" \
-d "{\"apiVersion\": \"authentication.k8s.io/v1\",\"kind\": \"TokenReview\",\"spec\": {\"token\": \"${USER_TOKEN}\"}}"
認証失敗すると以下のようにUnauthorizedのエラーが出ます。
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {
},
"status": "Failure",
"message": "Unauthorized",
"reason": "Unauthorized",
"code": 401
}
成功すると以下のようなメッセージが返ります。
{
"kind": "TokenReview",
"apiVersion": "authentication.k8s.io/v1",
"metadata": {
"creationTimestamp": null,
"managedFields": [
{
"manager": "curl",
"operation": "Update",
"apiVersion": "authentication.k8s.io/v1",
"time": "2021-01-06T07:29:12Z",
"fieldsType": "FieldsV1",
"fieldsV1": {"f:spec":{"f:token":{}}}
}
]
},
"spec": {
"token": "k8s-aws-v1.xxxxx"
},
"status": {
"authenticated": true,
"user": {
"username": "system:node:ip-xxx-xxx-xxx-xxx.ap-northeast-1.compute.internal",
"uid": "heptio-authenticator-aws:123456789012:Axxxxxxxxxx",
"groups": [
"system:bootstrappers",
"system:nodes",
"system:authenticated"
],
"extra": {
"accessKeyId": ["Axxxxxx"]
}
},
"audiences": [
"https://kubernetes.default.svc"
]
}
}