---
# System prepended metadata

title: Kubernetes RBAC with AWS IAM integration
tags: [kubernetes, sharing]

---

# Kubernetes RBAC with AWS IAM integration

# Overview

This documentation provides a comprehensive guide on implementing Role-Based Access Control (RBAC) in a Kubernetes environment seamlessly integrated with AWS Identity and Access Management (IAM). This integration allows organizations to leverage our existing AWS IAM infrastructure to manage and control access to Kubernetes resources.

This RBAC module is implemented by Terraform and can be found at: <**github_placeholder**>

## **Terminologies**

**RBAC** is a security mechanism that controls access to resources within a cluster. It allows you to define **who** (users or groups) can do **what** (verbs) on **which** resources (nouns).

- **Roles and RoleBindings:**
    - **Role:** set of permissions defined for a specific **namespace**. It specifies **what** actions (verbs) are allowed on **which** resources (nouns) **within** that **namespace**. For example, a role might grant read access to pods in a namespace.
    - **RoleBinding:** A role binding binds a **role** to a **user**, a **group**, or a **service account** within a specific **namespace**. It establishes the connection between the role and the entity (user, group, or service account) that should have the defined permissions.
- **ClusterRoles and ClusterRoleBindings:**
    - **ClusterRole:** Similar to a role, but it works across **all namespaces** in a cluster. It defines permissions for **cluster-level** resources, like nodes and persistent volumes.
    - **ClusterRoleBinding:** Binds a cluster role to a **user**, **group**, or **service account** across the **entire cluster**. It allows users or service accounts to have specific roles across all namespaces

![image](https://hackmd.io/_uploads/S1wsX_zkkx.png)


# Example

The below code snippet describes how the module is defined and mapping with existing AWS IAM roles

```java
module "k8s-rbac" {
  source = "../../modules/eks/eks-rbac"

  depends_on = [module.eks]

  cluster_roles = [
    {
      name      = "admin"
      privilege = "admin"
      trusted_role_arn = [
        local.administrator_role_arn
      ]
    },
    {
      name      = "developer"
      privilege = "developer"
      trusted_role_arn = [
        local.developer_role_arn
      ]
    }
  ]

  namespace_roles = [
    {
      namespace = "service-A"
      privilege = "readonly"
      trusted_role_arn = [
        local.service_A_readonly_role_arn
      ]
    },
    {
      namespace = "service-B"
      privilege = "developer"
      trusted_role_arn = [
        local.service_B_developer_role_arn
      ]
    }
  ]

  profile_roles = [
    {
      role_arn     = module.eks.aws_iam_role-node.arn
      profile_type = "node"
      privilege    = "node"
      name         = "node"
    },
    {
      role_arn     = module.eks.eks_default_auth_role_arn
      profile_type = "custom"
      privilege    = "admin"
      name         = "master-role"
    },
    {
      role_arn     = local.jenkins_oidc_role
      profile_type = "custom"
      privilege    = "admin"
      name         = "jenkins"
    },
    {
      role_arn     = module.eks.fargate_profile.fargate_profile_pod_execution_role_arn
      profile_type = "fargate"
      privilege    = "fargate"
      name         = "fargate"
    },
    {
      role_arn     = local.github_terraform_ops_role_arn
      profile_type = "custom"
      privilege    = "admin"
      name         = "github"
    }
  ]

  aws_auth_users = []

  tags = {
    environment = local.environment
  }
}

```

# How it works

## **Cluster roles and namespace roles**

Under the hood, this Terraform code **creates** the resources below

- An IAM role that **trust** the role arns in `trusted_role_arn` to assume it with `sts:AssumeRole`
    - IAM roles for cluster: `eks-admin-clusterrole` and `eks-developer-clusterrole`
    - IAM roles for namespace: `eks-service-A-readonly-namespace-role` and `eks-service-B-developer-namespace-role`
- **ClusterRole** and **ClusterRoleBindings** for `cluster_roles` array
- **Role** and **RoleBinding** for `namespace_roles` array

These **ClusterRoleBindings** and **RoleBindings** then will be linked to AWS IAM through `aws-auth` configmap inside `kube-system` namespace as the documentation above described

```java
- rolearn: arn:aws:iam::<account-id>:role/eks-admin-clusterrole
  username: admin
  groups:
  - custom:admin-group                      # clusterrolebinding
- rolearn: arn:aws:iam::<account-id>:role/eks-developer-clusterrole
  username: developer
  groups:
  - custom:developer-group                  # clusterrolebinding
- rolearn:
arn:aws:iam::<account-id>:role/eks-service-A-readonly-namespace-role
  username: service-A-readonly
  groups:
  - custom:service-A-readonly-group       # rolebinding
- rolearn:
arn:aws:iam::<account-id>:role/eks-service-B-developer-namespace-role
  username: service-B-developer
  groups:
  - custom:service-B-developer-group   # rolebinding
```

### **How does the trusted role work?**

As you can see from the previous sections, we specify which **IAM** roles are trusted by the newly created **IAM** roles through `trusted_role_arns` variable

It would look like this on the console, here, the **Administrator SSO** role are trusted to perform `sts:AssumeRole` action https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html

![image](https://hackmd.io/_uploads/r144r_GJJl.png)



If the user has permission to use this SSO role through logging in by SSO, he/she will have the permission to assume the `eks-admin-clusterrole` and perform actions inside the Kubernetes Cluster

## **Profile roles**

While `cluster_roles` and `namespace_roles` **creates** new IAM roles with associated Kubernetes permission, the `profile_roles` field is for specifying **existing** IAM roles on AWS IAM, that we need to map them into the Kubernetes cluster with special permission

The result `aws-auth` configmap will contain these data for these IAM roles

```java
- rolearn: arn:aws:iam::<account_id>:role/eks-node-cluster
  username: system:node:{{EC2PrivateDNSName}}
  groups:
    - system:bootstrappers                   # permission for managed nodes
    - system:nodes
- rolearn: arn:aws:iam::<account_id>:role/eks-auth-role
  username: master-role
  groups:
    - system:masters                         # admin
- rolearn: arn:aws:iam::<account_id>:role/jenkins-oidc-role
  username: jenkins
  groups:
    - system:masters                         # admin
- rolearn:
  arn:aws:iam::<account_id>:role/eks-dev-fargate-profile-2023112103250071030000000a
  username: system:node:{{SessionName}}
  groups:
    - system:bootstrappers                   # permission for fargate
    - system:nodes
    - system:node-proxier
- rolearn: arn:aws:iam::<account_id>:role/github-actions/role-terraform-ops
  username: github
  groups:
    - system:masters                         # admin
```

# Organizing RBAC with AWS SSO

## **Strategy**

We could organize the access permission to Kubernetes cluster by **mapping** the SSO roles to the cluster roles and namespaces role

The table below describes a good practice for this mapping

| **EKS roles** |  | **AWS SSO Roles** |
| --- | --- | --- |
| Cluster role | eks-admin-clusterrole | AdministratorAccess |
|  | eks-developer-clusterrole | KubernetesDevs |
|  | eks-viewer-clusterrole | BackendDevs |
| Namespace role | eks-service-B-admin-namespace-role | ServiceBAdmin |
|  | eks-service-B-admin-namespace-role | ServiceBDevs |

The table above can be translated to the Terraform code with similar configuration

```java
  cluster_roles = [
    {
      name      = "admin"
      privilege = "admin"
      trusted_role_arn = [
        "arn:aws:iam::<account_id>:role/aws-reserved/sso.amazonaws.com/us-west-2/AdministratorAccess"
      ]
    },
    {
      name      = "developer"
      privilege = "developer"
      trusted_role_arn = [
        "arn:aws:iam::<account_id>:role/aws-reserved/sso.amazonaws.com/us-west-2/KubernetesDevs"
      ]
    },
    {
      name      = "viewer"
      privilege = "readonly"
      trusted_role_arn = [
        "arn:aws:iam::<account_id>:role/aws-reserved/sso.amazonaws.com/us-west-2/BackendDevs"
      ]
    }
  ]

  namespace_roles = [
    {
      namespace = "service-B"
      privilege = "admin"
      trusted_role_arn = [
        "arn:aws:iam::<account_id>:role/aws-reserved/sso.amazonaws.com/us-west-2/ServiceBAdmin"
      ]
    },
    {
      namespace = "service-B"
      privilege = "developer"
      trusted_role_arn = [
        "arn:aws:iam::<account_id>:role/aws-reserved/sso.amazonaws.com/us-west-2/ServiceBDevs"
      ]
    },
  ]
```
