サービスロールをEKSクラスターのaws-authに設定すると認証エラーになる

 

はじめに

Reading this article in the hope it saves someone else a few hours of their life.
(この記事を読むことで他の誰かの生命を数時間節約できることを願っています)
 
※元ネタ
 

事象(エラー内容)

EKSクラスターに対してkubernetesコマンド(たとえばkubectl clsuter-infoなど)を実行すると、下記エラーメッセージが出力。
error: You must be logged in to the server (Unauthorized)
 
EKSのクラスターログ(Authenticator)には下記が出力。
time="2022-07-07T00:44:17Z" level=warning msg="access denied" arn="arn:aws:iam::123456789012:role/AWSCloud9SSMAccessRole" client="127.0.0.1:38914" error="ARN is not mapped" method=POST path=/authenticate
 
エラーのメッセージだけだと「見たままやんけ」と思うところですが、何度設定を見直しても合っているはずなのにこのエラーが出てだいぶハマった、というものです。
 

環境情報

  • EKS:1.21
  • kubectl:1.22.11
  • aws cli:2.7.14
 

詳細

案件でEKSクラスターをTerraform(EKS Module)で構築しました。
EKSはデフォルトだとクラスターを構築したユーザー(またはロール)しかkubernetesリソースへのアクセス権が無いため、必要なら個別に追加する必要があります。
今回はTerraformで追加していますが、手動で(kubernetesの構文で)追加する場合は下記を参考にして実施できます。
 
案件ではメンテナンス環境としてCloud9を利用しているので、Cloud9のIAMロールをsystem:mastersグループに追加しました。
設定値は下記のような感じです。
(関係無い部分は省略)
--------------------------------------------------------------------------
mapRoles:
----
- "groups":
  - "system:bootstrappers"
  - "system:nodes"
  "rolearn": "arn:aws:iam::123456789012:role/xxxxxxxx-nodegroup-role"
  "username": "system:node:{{EC2PrivateDNSName}}"
- "groups":
  - "system:masters"
  "rolearn": "arn:aws:iam::555807401321:role/service-role/AWSCloud9SSMAccessRole"
  "username": "maintenance_role"
--------------------------------------------------------------------------
 
その後こちらを参考にkubeconfigを設定しました。
設定後の結果は下記の通りです。
(こちらも関係ないところは省略)
--------------------------------------------------------------------------
- context:
    cluster: ''
    user: ''
  name: xxxxxxxx-cluster
current-context: arn:aws:eks:ap-northeast-1:123456789012:cluster/
xxxxxxxx-cluster
kind: Config
preferences: {}
users:
- name: arn:aws:eks:ap-northeast-1:123456789012:cluster/xxxxxxxx-cluster
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1beta1
      args:
      - --region
      - ap-northeast-1
      - eks
      - get-token
      - --cluster-name
      - xxxxxxxx-cluster
      - --role
      - arn:aws:iam::123456789012:role/service-role/AWSCloud9SSMAccessRole
      command: aws
--------------------------------------------------------------------------
 
この状態でkubernetesのコマンドを実行したところ、先述のエラーが出力されました。
 
  • IAMロールのARN名など間違っていないことは何度も確認
  • 一方で上記とは別に設定しているIAMロール(AWS SSOのロール)ではアクセスできている
  • そもそも同じaws-authとkubeconfigを設定している別クラスターでは正常にアクセスできている
 
という状況であり、何が違うのかわからず、ネットワークやkubectlの問題なども疑ったりしましたが、調査はかなり難航しました。
 

原因

最初にも貼ったGithubのIssueに答えがありました。
現行のaws-authにはIAMロールのパスを認識できない不具合があり、暫定としてARN名からパスを除去すると正常に認識できるようになるようです。
 
それを踏まえ、rolearnの部分を下記のように修正すると正常にコマンドが通るようになりました。
--------------------------------------------------------------------------
 "rolearn": "arn:aws:iam::123456789012:role/AWSCloud9SSMAccessRole"
--------------------------------------------------------------------------
 
※ただ、「同じaws-authとkubeconfigを設定している別クラスターでは正常にアクセスできている」という事象の説明にはなっていないので、こちらは残課題として何かわかったら追記します
 

おまけ

以降は切り分けとしてやったことを五月雨に記載します。
(結論として全く関係無かったので、参考まで)
 

仮説その①:Kubernetes BoundServiceAccountTokenVolume 機能(1.21)で認証の有効期間が切れている説

EKSの1.21以降、サービスアカウントトークンの有効期限が設定されるようになったため、そのせいで有効期限が切れて認証できなくなっているのではないかと考えました。
しかしこれは認証情報を更新できないkubernetesクライアント(CNIやkube-proxyなど)の話で、Cloudwatchログ上も該当するログは出ていなかったので関係ないと判断。
 
 

仮説その②:kubectlのバージョンが違うせいで繋がらなくなった説

残課題として残った、「別クラスターでは同じ設定で接続できている」に対するアプローチです。
kubernetesは過去2バージョンまで後方互換性があったと思いますが、kubectlのバージョン(あとはAWS CLIも)が違うことで何か良からぬことが起こっているのではないかと考えました。
実際、同じkubectl 1.21でも1.21.0と1.21.11で機能が変わっているようで、具体的にはkubeconfigの apiVersionv1alpha1からv1beta1に変わっていました。
1.21.11のkubectlでv1alpha1のapiを実行すると、下記のメッセージが出力されます。
--------------------------------------------------------------------------
$ kubectl cluster-info
Kubeconfig user entry is using deprecated API version client.authentication.k8s.io/v1alpha1. Run 'aws eks update-kubeconfig' to update.
 
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
--------------------------------------------------------------------------
 
ただこれもdeprecatedの警告であり、認証自体は通るので関係ありませんでした。