EKS クラスターへのアクセス制御を EKS API 経由で実施可能になったので試してみた

先日のアップデートで EKS クラスターへのアクセス制御を EKS API 経由で実施可能になりました。

これまで、EKS クラスターの API Server へのアクセス制御は Kubernetes リソースである ConfigMap を利用して行う必要がありました。(EKS 自体の設定変更ではなく、kubectl 等でクラスターにアクセスする際の話になります)
クラスターを作成した IAM ユーザー(ロール)には自動で権限が付与されますが、全ての開発者が必ずしもこちらの権限でアクセスするわけではありません。
より柔軟にアクセス制御を行う際、 EKS を 作成した後に下記のような形式の Kubernetes のマニフェストファイルを記載してクラスターに適用していました。

Name:         aws-auth
Namespace:    kube-system
Labels:       <none>
Annotations:  <none>

Data
====
mapRoles:
----
- groups:
  - system:bootstrappers
  - system:nodes
  rolearn: arn:aws:iam::111122223333:role/my-node-role
  username: system:node:{{EC2PrivateDNSName}}


BinaryData
====

Events:  <none>

クラスターに対する IAM プリンシパルのアクセスの有効化 | Amazon EKS

しかし、クラスターへのアクセス制御であれば EKS 側の設定として扱える方がシンプルに感じます。
特にクラスター作成時に合わせて権限周りも設定したいと思う方は少なくないと思います。
私も Terraform でクラスターを作成する際に、アクセス可能な IAM プリンシパルを合わせて定義しようと思ったことがあるのですが、ConfigMap が作成されるタイミングの問題等で解決し辛いエラーに遭遇する場面がありました。(Terraform であれば Kuberentes リソースも扱えるものの、どうしても複雑な処理になってしまいます)
※ こちらの問題は GitHub の issue にも挙げられています。
Error The configmap "aws-auth" does not exist when deploying to AWS EKS
今回 EKS API から権限付与できるようになったため、クラスター作成時でもシンプルかつ問題を起こしづらい形で設定可能になりました。

また、クラスターを作成した IAM プリンシパルには自動で権限が付与されますが、こちらの設定は ConfigMap に定義されず、EKS の設定からも確認できませんでした。
今後新しいアクセス制御方式に移行することで、クラスターを作成した IAM プリンシパルも含めて一元的に管理可能になります。

クラスターへのアクセス制御において従来の方法より明らかにメリットがあるので、AWS 公式ドキュメントでも新しい方式への移行が推奨されています。

If your cluster is at or later than the platform version listed in the Prerequisites section for your cluster's Kubernetes version, we recommend that you use this option.
Allowing IAM roles or users access to Kubernetes objects on your Amazon EKS cluster | Amazon EKS

移行してみた

今回のアップデートに伴い、 EKS は Authentication mode を設定できるようになり、下記 3 つのモードが存在するようになりました。

  • ConfigMap
  • EKS API and ConfigMap
  • EKS API

既存クラスターは従来通りの ConfigMap になり、ConfigMap から EKS API and ConfigMap、EKS API and ConfigMap から EKS API へのみ移行可能です。
一時的に新旧方式を併用できるのは非常に良いですね。
移行した後に元に戻すことはできないので、EKS API and ConfigMap モードを利用して十分に検証を行った上で移行するようにしましょう。

今回、既存 EKS クラスターを EKS API モードに移行してみました。
とりあえずマネジメントコンソールから実行してみます。
Manage access をクリックして、Authentication mode を変更します。

ドキュメント記載の通り、いきなり EKS API に移行することはできません。
まずは新旧方式を併用できる EKS API and ConfigMap に移行します。

タイプ AccessConfigUpdate の変更が実行され、今回は 1 分程度で完了しました。
まずは定義されているアクセスエントリ(EKS クラスターへのアクセス許可設定)を確認します。

arn:aws:iam::xxxxxxxxxxx:role/aws-reserved/sso.amazonaws.com/ap-northeast-1/AWSReservedSSO_AdministratorAccess_befa221ae928f837 と記載されているのが、クラスターを作成した IAM プリンシパルです。(今回は IAM Identity Center の許可セットに紐づく IAM ロール)
これまでは EKS の設定として確認できませんでしたが、EKS のマネジメントコンソールから確認可能になっています。
また、AWS CLI からも確認できるようになっています。

$ aws eks list-access-entries --cluster-name test-cluster
{
    "accessEntries": [
        "arn:aws:iam::xxxxxxxxxxxx:role/aws-reserved/sso.amazonaws.com/ap-northeast-1/AWSReservedSSO_AdministratorAccess_befa221ae928f837",
        "arn:aws:iam::xxxxxxxxxxxx:role/initial-eks-node-group-20231229150836790600000004"
    ]
}

ちなみに、上記コマンドを ConfigMap モードのクラスターに実行するとエラーになりました。
Authentication mode を変更しないとアクセスエントリ関連コマンドは実行できないのでご注意下さい。

An error occurred (InvalidRequestException) when calling the ListAccessEntries operation: The cluster's authentication mode must be set to one of [API, API_AND_CONFIG_MAP] to perform this operation.

合わせて登録されている arn:aws:iam::xxxxxxxxxxxx:role/initial-eks-node-group-20231229150836790600000004 は EKS Node から API Server にアクセスするための権限です。
こちらは、ConfigMap としても登録されていますが、アクセスエントリとしても自動登録されました。

$ kubectl describe cm aws-auth -n kube-system
Name:         aws-auth
Namespace:    kube-system
Labels:       <none>
Annotations:  <none>

Data
====
mapRoles:
----
- groups:
  - system:bootstrappers
  - system:nodes
  rolearn: arn:aws:iam::xxxxxxxxxxxx:role/initial-eks-node-group-20231229150836790600000004
  username: system:node:{{EC2PrivateDNSName}}


BinaryData
====

Events:  <none>

新旧方式で同じ IAM プリンシパルに対して設定を行った場合、新方式(アクセスエントリ) が優先されるようです。

When API_AND_CONFIG_MAP is enabled, the cluster will source authenticated AWS IAM principals from Amazon EKS access entry APIs and the aws-auth configMap, with the access entry API taking precedence
A deep dive into simplified Amazon EKS access management controls

アクセスエントリを追加してみた

アクセスエントリを追加してみます。
今回は専用の IAM ユーザーを作成して試してみます。
このユーザーには aws eks update-kubeconfig コマンドによる kubeconfig ファイル自動作成用に eks:DescribeCluster アクションのみ許可しておきます。
アクセスエントリで権限設定を行えば、EKS 周りの権限は無くても kubectl コマンドを実行可能です。
アクセスエントリに権限を設定する際に Standard、EC2 Linux、EC2 Windows、FARGATE_LINUX 等のタイプが存在しますが、ユーザーが利用する IAM プリンシパルは Standard で定義する必要があります。

ユーザー名も定義したくなる所ですが、自動生成が推奨のようなので空欄にしておきます。

Unless you have a specific reason for specifying your own username, we recommend that don't specify one and let Amazon EKS auto-generate it for you
Creating access entries | Amazon EKS

また、アクセスポリシーとして下記 4 つが用意されております。

  • AmazonEKSClusterAdminPolicy
    • 全ての権限(ClusterRoleBindingで使用するとクラスター内全て、RoleBindingで使用すると名前空間内全て)
  • AmazonEKSAdminPolicy
    • 名前空間内で使うことを想定した管理者権限(Role と RoleBinding を作成する権限を含む)
  • AmazonEKSEditPolicy
    • 名前空間内で使うことを想定した各種リソースへの読み取り/書き込み権限(Role と RoleBinding を作成する権限は含まない)
  • AmazonEKSViewPolicy
    • 名前空間内で使うことを想定した各種リソースへの読み取り権限

まず、AmazonEKSViewPolicy を app 名前空間に対して付与してみます。

ポリシーを追加 をクリックしてから 次へ をクリックします。

作成した IAM ユーザーで aws eks update-kubeconfig --name test-cluster を実行してから各種コマンドを実行していきます。
default の名前空間への読み取りアクセスは拒否されました。

$ kubectl get pod
Error from server (Forbidden): pods is forbidden: User "arn:aws:iam::xxxxxxxxxxxx:user/kubernetes-developer" cannot list resource "pods" in API group "" in the namespace "default"

名前空間 app への読み取りアクセスは許可されました。

$ kubectl get pod -n app
No resources found in app namespace.

名前空間 app でも、書き込み権限は付与されていません。

$ kubectl run redis --image=redis -n app
Error from server (Forbidden): pods is forbidden: User "arn:aws:iam::xxxxxxxxxxxx:user/kubernetes-developer" cannot create resource "pods" in API group "" in the namespace "app"

想定通りの挙動になったので、アクセスポリシーを AmazonEKSAdminPolicy にして再度 Pod の作成を試みてみます。

$ kubectl run redis --image=redis -n app
pod/redis created

即座に設定変更が反映され、正しく実行できました。

さいごに

ConfigMap を活用した権限設定周りは複雑に感じていた部分でしたので、また一つ扱いやすくなったと感じています。
移行することによるデメリットも特に感じないので、今後は是非 EKS の IAM アクセスエントリを活用してみて下さい!