EKSのaws-auth ConfigMapに変更が入って辛い

2024.02.29

困っていること

EKSクラスターを、TerraformのEKS公開モジュールを使ってプロビジョニングしています。現在使っているversionは19.17.1です。クラスターのversionは1.27です。

2月初旬頃から、EKSクラスターのkube-system namespaceのConfigMap aws-auth の内容が何者かによってTerraform外で更新されるようになっており、それによってterraform planterraform applyで以下のようなdiffが検出されることがあります。

  • mapRoles.groups配列内の要素順が異なる
  • mapRoles.groups配列内の文字列が全般「"」で囲まれていない→囲まれている
  # module.eks.kubernetes_config_map_v1_data.aws_auth[0] will be updated in-place
  ~ resource "kubernetes_config_map_v1_data" "aws_auth" {
      ~ data          = {
          ~ "mapRoles"    = <<-EOT
              - - groups:
              -   - system:bootstrappers
              -   - system:nodes
              -   rolearn: arn:aws:iam::012345678901:role/my-node-role
              -   username: system:node:{{EC2PrivateDNSName}}
              - - groups:
              -   - system:masters
              -   rolearn: arn:aws:iam::012345678901:role/AWSReservedSSO_AdministratorAccess_3e3617e16cf3782b
              -   username: AWSReservedSSO_AdministratorAccess_3e3617e16cf3782b:{{SessionName}}
              - - groups:
              -   - system:bootstrappers
              -   - system:nodes
              -   - system:node-proxier
              -   rolearn: arn:aws:iam::012345678901:role/my-fargate-profile-role
              -   username: system:node:{{SessionName}}
              + - "groups":
              +   - "system:bootstrappers"
              +   - "system:nodes"
              +   "rolearn": "arn:aws:iam::012345678901:role/my-node-role"
              +   "username": "system:node:{{EC2PrivateDNSName}}"
              + - "groups":
              +   - "system:bootstrappers"
              +   - "system:nodes"
              +   - "system:node-proxier"
              +   "rolearn": "arn:aws:iam::012345678901:role/my-fargate-profile-role"
              +   "username": "system:node:{{SessionName}}"
              + - "groups":
              +   - "system:masters"
              +   "rolearn": "arn:aws:iam::012345678901:role/AWSReservedSSO_AdministratorAccess_3e3617e16cf3782b"
              +   "username": "AWSReservedSSO_AdministratorAccess_3e3617e16cf3782b:{{SessionName}}"
            EOT
            # (2 unchanged elements hidden)
        }
        id            = "kube-system/aws-auth"
        # (2 unchanged attributes hidden)

<pre><code>    # (1 unchanged block hidden)
}
</code></pre>

aws-auth ConfigMapとは、クラスターにアクセスできるIAMプリンシパル(IAM RoleやIAM UserやAWSアカウントのルートユーザーのこと)を設定するために使うConfigMapです。

ここに書かれているIAMプリンシパルもしくはクラスターを作成したIAMプリンシパルでないと、クラスターにアクセスできません。間違った変更が入った場合、その後クラスターにアクセスできなくなるおそれがあります。ですのでとても重要な設定です。なのですが、毎度前述のようなdiffが検出されてしまうと、diff確認が疎かになって意図せぬ変更を見落としてしまうおそれがあります。

※ 厳密に言うと、aws-auth ConfigMapが必要になるのは、クラスターの設定項目Authentication modeでConfigMapを含んでいる場合のみです。以前はこの方法しか無かったのですが、このアップデートにより別の方法でも設定できるようになりました。

原因究明: だれがこの変更を実施しているのか

前述のとおり重大な障害を発生させるリスクがありますし、そうでなくても毎度よくわからないdiffが検出されるのはストレスなので、この問題を早急に解決したいと考えました。まずは原因究明、つまり誰がこの変更をTerraform外で実施しているのかの調査を行ないました。

EKSは監査ログを簡単にCloudWatch Logsに記録できる機能があります。

こちらを漁れば、aws-authConfigMapの変更履歴を把握できます。CloudWatch Logs Insightsで該当クラスターのコントロールプレーンのログを記録しているLog Groupに対して、以下の様なクエリを実行しました。

fields @timestamp, verb, user.username, user.extra.arn.0
| filter @logStream like "kube-apiserver-audit"
| filter objectRef.resource = "configmaps"
| filter objectRef.namespace = "kube-system"
| filter objectRef.name = "aws-auth"
| filter verb NOT IN ["get", "watch"]
| sort @timestamp desc
| limit 1000

結果、Terraform外で2回変更が実行されていることがわかりました。以下、時系列で説明します。

1. 弊社メンバーがTerraform経由で変更(terraform apply)

当然ですが、これは想定内の履歴です。

2. AWSWesleyClusterManagerLambda-NodeManagerRole〜 というIAM Roleが変更を実施

変更内容

Terraformでの定義内容と比べて、以下が異なります。

  • 文字列が「"」で囲まれていない
  • Fargate Profile用のロールについての定義がない
- groups:
  - system:bootstrappers
  - system:nodes
  rolearn: arn:aws:iam::012345678901:role/my-node-role
  username: system:node:{{EC2PrivateDNSName}}
- groups:
  - system:masters
  rolearn: arn:aws:iam::012345678901:role/AWSReservedSSO_AdministratorAccess_3e3617e16cf3782b
  username: AWSReservedSSO_AdministratorAccess_3e3617e16cf3782b:{{SessionName}}

AWSWesleyClusterManagerLambda-NodeManagerRole〜 IAM Roleについて

このロールは、このクラスターの存在するAWSアカウント内のロールではなく、外部アカウントのロールでした。かつその外部アカウントは同一Organizations内にあるわけでもない、完全に外部のアカウントでした。

調べてみると、NodeManagerRoleが付くIAM Roleは「Amazon EKS の内部サービスロールです。」という記述がありました。

Amazon CloudWatch で Amazon EKS の認証ログをチェックすると、次のサンプルテキストのようなテキストを含むエントリが表示されます。

level=info msg="mapping IAM role" groups="[]" role="arn:aws:iam::111122223333:role/XXXXXXXXXXXXXXXXXX-NodeManagerRole-XXXXXXXX" username="eks:node-manager"

このテキストを含むエントリが必要です。username は、マネージド型ノードグループと Fargate の特定のオペレーションを実行する、Amazon EKS の内部サービスロールです。

サービスロールとは、お客様に代わって AWS のサービスがアクションを実行するために引き受けるロールです。ということで、このロールはAWSが管理しているロールで、アカウントもAWSが使っているアカウントのようです。

Stack Overflowにも同様にAWS管理のIAM Role/アカウントであるというコメントが見つかりました。

権限を確認

また、このIAM ロールが紐づいているk8sユーザーが所属するk8sグループに紐づくk8sのロール(ややこしいな!)はkube-system namespaceのeks:node-managerであり、権限を確認すると以下だったので確かに aws-auth ConfigMapを更新する権限がありました。

kubectl get role eks:node-manager -o yaml -n kube-system出力結果抜粋

rules:
- apiGroups:
  - ""
  resourceNames:
  - aws-auth
  resources:
  - configmaps
  verbs:
  - get
  - update
  - patch
- apiGroups:
  - ""
  resources:
  - configmaps
  verbs:
  - create
- apiGroups:
  - ""
  resources:
  - events
  verbs:
  - get
  - list

3. 2の直後AWSWesleyClusterManagerLambda-FargateManagerRole〜 というIAM Roleがさらに変更を実施

「直後」は数十秒後だったり約15分後だったりバラツキがありました。

変更内容

- groups:
  - system:bootstrappers
  - system:nodes
  rolearn: arn:aws:iam::012345678901:role/my-node-role
  username: system:node:{{EC2PrivateDNSName}}
- groups:
  - system:masters
  rolearn: arn:aws:iam::012345678901:role/AWSReservedSSO_AdministratorAccess_3e3617e16cf3782b
  username: AWSReservedSSO_AdministratorAccess_3e3617e16cf3782b:{{SessionName}}
- groups:
  - system:bootstrappers
  - system:nodes
  - system:node-proxier
  rolearn: arn:aws:iam::012345678901:role/my-fargate-profile-role
  username: system:node:{{SessionName}}

2の変更に、Fargate Profile用のロールについての定義が追加されています。

Terraformでの定義内容と比べて、以下が異なります。

  • 文字列が「"」で囲まれていない
  • mapRoles.groups配列内の要素順が異なる

AWSWesleyClusterManagerLambda-FargateManagerRole〜 IAM Roleについて

2を実施した「NodeManagerRole」と同じアカウントのIAM Roleでした。ですのでこちらもAWS管理のアカウントの、AWS管理のIAM Roleと思われます。ただし2とは違って、公式ドキュメントにこのロールについての記述は見つけることができませんでした。

権限を確認

2と同様、このIAM ロールが紐づいているk8sユーザーが所属するk8sグループに紐づくk8sのロール(ややこしいな!)を調べました。するとkube-system namespaceのeks:fargate-managerロールであり、権限を確認すると以下だったので確かに aws-auth ConfigMapを更新する権限がありました。

kubectl get role eks:fargate-manager -o yaml -n kube-system出力結果抜粋

rules:
- apiGroups:
  - ""
  resourceNames:
  - aws-auth
  resources:
  - configmaps
  verbs:
  - get
  - update
  - patch
  - delete
- apiGroups:
  - ""
  resources:
  - configmaps
  verbs:
  - create
- apiGroups:
  - ""
  resources:
  - events
  verbs:
  - get
  - list

4. diff発生

2,3実施後にterraform planterraform applyを行なうと最初に説明したdiffが発生してしまいます。

解決方法の検討

前述の2と3の変更は一度きりではなく、定期的に実施されています。

解決方法の検討をした結果、「diff抑止は無理そう」→「aws-authConfigMapの使用をやめる」ということになりました。

diff抑止は無理そう

まず、2と3のAWS管理ロールによる変更実施を止める術は無さそうでした。2(NodeManagerRole)については「必要です」とドキュメントにも書いてあったので仕方ないですね。 正直 2と3の操作でAWSが何をしたいのかよくわからないですが…

また、別角度の解決法として「このような変更が入る前提で、Terraformのコードを修正してdiffが出ないようにする」が考えられます。なのですが、最初にお伝えした通り、EKSの公開モジュールを使っており、aws-authConfigMapの定義もこのモジュール内で行なっているので修正が難しいです。この部分だけ公開モジュール外で定義することも考えられますが、そうするくらいだったら後述の方法の方が望ましいと考えました。

aws-auth ConfigMapの使用をやめる

冒頭の方の注釈で軽く説明しましが、現在はEKSのアップデートにより aws-authConfigMapを使わずともIAMプリンシパルによるクラスターアクセスを設定する方法があります。

こちらの方法に移行すれば今回の問題も発生し無さそうと考えました。現在はまだ移行の検証中なのであくまで予測ですが。(今後結果を追記しようと思います。) また、こちらの方法にするほうが他にも色々メリットがあります。メリット詳細は↑のエントリをご確認ください!