Using kubernetes_groups in EKS access entry: when and how

Xing Du
2 min readMay 6, 2024

AWS EKS access entry has an attribute called kubernetes_groups. If you are familiar with the managed access policies (see my other post), you may wonder why this is needed.

I’ll explain with a valid use cases on when to use kubernetes_groups and how to.

What problem does kubernetes_groups solve

As I mentioned before, the 4 managed EKS access policies are very coarse and do not allow customization. Courtesy of @mikestef9 (explanation): the 4 access entry policies map to the upstream Kubernetes user-facing roles:

  • cluster-admin
  • admin
  • edit
  • view

If your use case requires customization or finer granularity than these 4 roles, you’ll need to join EKS access entry with native k8s RBAC to achieve what you need to do.

Example

Your CD solution needs to run releases for your services to your EKS cluster. A dedicated IAM role (e.g. eks-service-deploy-role) was created and added to EKS access entries with AmazonEKSEditPolicy. This role is widely used by different teams working on different services.

It’s scope to get, create, update, and delete k8s resources for these services, no more and no less. AmazonEKSEditPolicy nearly worked, however:

  • it does not have permission to create namespace
  • it has no rules for custom resources and some of your helm charts contain custom resources

As a result, your helm upgrade --install --create-namespace failed due to permission errors. Thankfully, kubernetes_groups in EKS access entry solves this problem.

How to use kubernetes_groups

  • add kubernetes_groups = ["<group_name>"] to your EKS access entry
  • create additive custom role(s)
  • create role binding with a group subject matching the "<group_name>" assigned to EKS access entry

Any combination of ClusterRole/Role and ClusterRoleBinding/RoleBinding work for this solution. It comes down to how you design your k8s RBAC. I will not expand here, this topic deserves its own post.

In terraform source code, your change should look similar to:

access_entries = {
service_deploy_role = {
principal_arn = <my_role_arn>
+ kubernetes_groups = ["my-group"]
policy_associations = {
...ch
}
}
}
+resource "kubernetes_cluster_role" "custom_role" {
+ metadata {
+ name = "my-custom-cluster-role"
+ }
+
+ rule {
+ ...
+ }
+}
+resource "kubernetes_cluster_role_binding" "custom_role_bind" {
+ metadata {
+ ...
+ }
+ role_ref {
+ ...
+ name = "my-custom-cluster-role"
+ }
+
+ subject {
+ api_group = "rbac.authorization.k8s.io"
+ kind = "Group"
+ name = "my-group" # use `dynamic` + eks module output if you want to go fancy
+ }
+}

--

--

Xing Du

Minimalist. Game Developer. Software Engineer. DevOps enthusiast. Foodie. Gamer.