Elevating EKS Security Through IAM Roles

30 Jan, 2024 | 4 minutes read

In this blog post we will take a look of a native-AWS way to attach an IAM role into the Kubernetes POD, without third party software, such as kube2iam and kiam. This is possible thanks to the integration between AWS IAM and Kubernetes ServiceAccount, following the approach of IAM Roles for Service Accounts (IRSA).

IAM Roles for Service Accounts (IRSA).

There are many benefits of using IRSA with Kubernetes PODs

  • Granular restriction (per cluster, per namespace, etc.)
    It’s also possible to not use it
  • More flexible than the other tools
  • One less point of failure (maybe a few lesser)
  • Lesser resources consumption
  • Implementing best practice, there are more pods per worker node
  • Latency may reduce by ~50ms
    Especially for the first request
  • Prevent issues with caching the credentials
    This software takes a few minutes to update its cache.
  • Better auditing
    Instead of checking the logs of kube2iam/kiam pods, you can check AWS CloudTrails
  • Easier to set up
  • AWS provides full support

There are a few pre-requirements that are needed to use the IAM role in a POD.

  • An IAM OpenID Connect provider pointing to the AWS EKS OpenID Connect provider URL
  • AWS EKS cluster 1.13 or above
  • A trust relationship between your IAM Role and the OpenID Provider

To illustrate all of these items and to follow security best practices, an Amazon Elastic Kubernetes Service cluster was created by the following cluster.yaml file:

apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: demo-k8s
  region: us-east-1
  version: "1.28"
  
vpc:
  id: vpc-xxxxxxxx
  cidr: "172.31.0.0/16"
  subnets:
    private:
      us-east-1a:
          id: "subnet-xxxxxxxx"
          cidr: "172.31.48.0/20"
      us-east-1b:
          id: "subnet-xxxxxxxx"
          cidr: "172.31.0.0/20"
      us-east-1c:
          id: "subnet-xxxxxxxx"
          cidr: "172.31.16.0/20"
   
nodeGroups:
  - name: linux-node
    instanceType: t2.micro
    desiredCapacity: 2
    volumeSize: 8
    ssh:
      allow: true
    privateNetworking: true
    availabilityZones: ["us-east-1a", "us-east-1b", "us-east-1c"]

eksctl create cluster -f cluster.yaml

Furthermore, we will follow these steps:

  • Create an AWS OpenID Connect provider
  • Link the OIDC provider to the EKS OIDC URL
  • Create an IAM Role
  • Create an IAM Policy (only via terraform)
  • Attach the IAM Policy to the IAM Role
  • Set up the Trust Relationship, adhering to security best practices, between the IAM Role and the OpenID Connect provider in the Amazon Elastic Kubernetes Service
  • Create a Kubernetes ServiceAccount

Amazon AWS EKS Security Best Practices and Tools

The tools that are going to be used are AWS cli, eksctl, kubectl and AWS console.

With this command aws eks describe-cluster –name demo-k8s –query “cluster.identity.oidc.issuer” we are going to check the existing EKS cluster OIDC URL.

The output is https://oidc.eks.us-east-1.amazonaws.com/id/<OIDC_ID>

After that, with command aws iam list-open-id-connect-providers we are listing the existing IAM OIDC providers. If <OIDC_ID> from the previous command is not included, we will associate it with this command: eksctl utils associate-iam-oidc-provider –region=us-east-1 –cluster=demo-k8s –approve.

Furthermore, from AWS console we are creating an IAM policy with minimal permissions on EKS cluster, i.e. list and read.

IAM role

Then, the IAM role will be created by the eksctl and attach the pre-existing policy <POLICY_NAME> into it.

eksctl create iamserviceaccount ^

 --cluster=demo-k8s ^

 --role-name=pod-creator ^

 --namespace=default ^

 --name=svc-test ^

 --attach-policy-arn=arn:aws:iam::xxxxxxxx:policy/test-k8s-read-policy ^

 --approve

After this, we have created an IAM ServiceAccount, default/svc-test for the default namespace and use it in a pod creation yaml.

Also, from AWS console can be checked the existence of an IAM role.

IAM role

This is a very simple example for a pod definition:

apiVersion: v1
kind: Pod
metadata:
  name: amazonlinux
  namespace: default
spec:
  serviceAccountName: svc-test
  containers:
    - name: amazonlinux
      image: amazonlinux
      command: [ "sh", "-c", "sleep 8h" ]

kubectl apply -f pod.yaml

pod/amazonlinux created in the Kubernetes cluster.

With the command, kubectl get pods/amazonlinux-o yaml a serviceAccount name can be checked, in our case svc-test.

Why an IAM Role for EKS?

For several reasons, creating an IAM (Identity and Access Management) role for Amazon EKS (Elastic Kubernetes Service) is important. It primarily conforms to the principle of least privilege and follows security best practices, which enhances the overall security of your Amazon Elastic Kubernetes Service infrastructure. You reduce potential risks and vulnerabilities by granting only the necessary permissions.

Furthermore, the integration of IAM Roles with EKS is effortless and robust, especially considering its compatibility with other AWS services. This collaboration under the shared responsibility model ensures AWS is responsible for a consistent and comprehensive security framework across your entire cloud environment, specifically your Amazon Elastic Kubernetes Service.

One of the primary benefits is the ability to customize permissions for your EKS nodes. This customization allows you to precisely customize access rights to the needs of your application, giving you granular control. The whole process can be automated with the Infrastructure as a Code tools, like Terraform.

Conclusion

Conclusively, IAM Roles following the security best practices are the first and most important step in securing our Kubernetes deployment on the Amazon Elastic Kubernetes Service. They follow the principle of least privilege, providing a fundamental level of protection against potential threats. Additionally, their adaptability enables us to adapt security measures to the specific needs of our environment. However, in best practice, it is critical to understand that, while IAM Roles are an important starting point in the shared responsibility model, ongoing customization is essential. This adaptability ensures that our security strategy remains dynamic and effective in dealing with a constantly changing landscape of potential threats. In essence, IAM Roles are the foundation upon which we continuously build and refine our Kubernetes security framework.