EKSのノードのKubeletが突然Unauthorizedでクラスタ接続不可となった時の調査メモ

ある日開発環境の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の不備でした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116068/b8d11cc3-5407-2f7c-08e9-60f22caad539.png)

以下のURLにもあるような、マネージドノードのロールマッピングが手違いで消えてしまったのが原因でした。

https://amazon-eks.s3.us-west-2.amazonaws.com/cloudformation/2020-08-12/aws-auth-cm.yaml

```yaml
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](https://github.com/kubernetes-sigs/aws-iam-authenticator)を使ってトークンを取得して、そのトークンを `clusters.cluster.server` で定義されているサーバーに投げて認証しています。

```yaml
$ 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"
```

この動きをコマンドで追っていきます。これができるとチェックの手間が省けます。


```sh
# 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のエラーが出ます。

```json
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {

  },
  "status": "Failure",
  "message": "Unauthorized",
  "reason": "Unauthorized",
  "code": 401
}
```

成功すると以下のようなメッセージが返ります。

```json

{
  "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"
    ]
  }
}
```