loading...
Cover image for A Simple Auth Proxy for EKS
Camptocamp Infrastructure Solutions

A Simple Auth Proxy for EKS

raphink profile image Raphaël Pinson ・3 min read

AWS EKS is a great option for a hosted Kubernetes cluster.

It is in particular easy to use for demos and training sessions.

However, EKS authentication is based off AWS IAM, which means users need an AWS account. Authenticating to EKS typically involves calling the aws eks get-token command in your .kube/config so as to retrieve an authentication token.

As we were setting up EKS for Kubernetes training, we needed a simple way for users without an AWS account to access the cluster, so we created a basic proxy service for the EKS get-token action.

GitHub logo camptocamp / aws-iam-authenticator-proxy

A simple HTTP proxy to share AWS IAM authentication

aws-iam-authenticator HTTP Proxy

Docker Pulls Go Report Card By Camptocamp

Amazon Services require valid accounts to be used. This proxy allows external users to access an AWS EKS cluster without requiring access to AWS credentials.

Disclaimer: the proxy does not implement any form of authentication. You are responsible for implementing whatever security measure you wish to enforce in front of it.

Example usage

In order to give access to an AWS EKS cluster without distribution credentials you can start the proxy with the necessary credentials as well as the cluster ID. For example, using Docker:

$ docker run --rm -p 8080:8080 \
             -e AWS_ACCESS_KEY_ID=<AWS_ACCESS_KEY_ID> \
             -e AWS_SECRET_ACCESS_KEY=<AWS_SECRET_ACCESS_KEY> \
             -e EKS_CLUSTER_ID=<EKS_CLUSTER_ID> \
             -e PSK="mysecretstring" \
    camptocamp/aws-iam-authenticator-proxy:latest
Enter fullscreen mode Exit fullscreen mode

You should then be able to retrieve authentication tokens for your user at http://localhost:8080.

If a PSK is passed, you will need to pass its value in the…

Deploying with Docker

The proxy can be deployed using Docker, with AWS credentials, e.g.:

docker run --rm -p 8080:8080 \
             -e AWS_ACCESS_KEY_ID=<AWS_ACCESS_KEY_ID> \
             -e AWS_SECRET_ACCESS_KEY=<AWS_SECRET_ACCESS_KEY> \
             -e EKS_CLUSTER_ID=<EKS_CLUSTER_ID> \
             -e PSK="mysecretstring" \
    camptocamp/aws-iam-authenticator-proxy:latest
Enter fullscreen mode Exit fullscreen mode

The rights on the cluster will depend on the user you chose to create the access key.

The PSK is optional, and allows to secure the proxy a little bit.

Once the proxy is started, you can access it at http://localhost:8080?psk=mysecretstring, so you can simply set your ~/.kube/config to use curl instead of aws:

users:
- name: <cluster_name>
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1alpha1
      command: curl
      args:
        - -s
        - "http://<your_ip>:8080/?psk=mysecretstring"
Enter fullscreen mode Exit fullscreen mode

Deploying in EKS

Since you've got an EKS cluster in the first place, you might as well deploy the proxy in it.

The repository provides a Helm chart for that, in the k8s directory of the GitHub project.

You can simply instantiate the chart with the following values:

eks_cluster_id: "<EKS_CLUSTER_ID>"
psk: "mysecretstring"
aws:
  access_key_id: "<AWS_ACCESS_KEY_ID>"
  secret_access_key: "<AWS_SECRET_ACCESS_KEY>"
Enter fullscreen mode Exit fullscreen mode

The AWS credentials will be stored in a Kubernetes secret and passed to the container.

Using

However, since we're in AWS, we can also use IAM roles for service accounts and bypass the access keys altogether. This is a much cleaner approach.

Here's how to do it, using Terraform to create the role and deploy the proxy.

First, create a role linked to OIDC:

module "iam_assumable_role_aws_iam_authenticator_proxy" {
  source                        = "terraform-aws-modules/iam/aws//modules/iam-assumable-role-with-oidc"
  version                       = "3.3.0"
  create_role                   = true
  number_of_role_policy_arns    = 0
  role_name                     = "aws-iam-authenticator-proxy"
  provider_url                  = replace(module.cluster.cluster_oidc_issuer_url, "https://", "")
  oidc_fully_qualified_subjects = ["system:serviceaccount:yournamespace:aws-iam-authenticator-proxy"]
}
Enter fullscreen mode Exit fullscreen mode

replacing yournamespace with the Kubernetes namespace where you will be deploying the proxy.

Now we can configure the cluster to use map that role to the Kubernetes role we want (e.g. system::masters to make it cluster admin).

We'll create a random PSK and generate the Kubeconfig file to use curl with the proxy:

data "aws_vpc" "this" {
  id = var.vpc_id
}

data "aws_subnet_ids" "private" {
  vpc_id = data.aws_vpc.this.id

  tags = {
    "kubernetes.io/role/internal-elb" = "1"
  }
}

module "cluster" {
  source  = "terraform-aws-modules/eks/aws"
  version = "13.1.0"

  cluster_name    = var.cluster_name
  cluster_version = "1.18"

  subnets          = data.aws_subnet_ids.private.ids
  vpc_id           = var.vpc_id
  enable_irsa      = true
  map_roles        = [
    {
      rolearn  = module.iam_assumable_role_aws_iam_authenticator_proxy.this_iam_role_arn,
      username = module.iam_assumable_role_aws_iam_authenticator_proxy.this_iam_role_name,
      groups   = ["system:masters"]
    },
  ]

  worker_groups = [
    {
      instance_type        = "m5a.large"
      asg_desired_capacity = 2
      asg_max_size         = 3
    }
  ]

  kubeconfig_aws_authenticator_command = "curl"
  kubeconfig_aws_authenticator_command_args = [
    "-s",
    "https://${var.auth_url}/?psk=${random_password.auth_proxy_psk.result}",
  ]
}

resource "random_password" "auth_proxy_psk" {
  length  = 16
  special = false
}
Enter fullscreen mode Exit fullscreen mode

Finally, we can deploy the proxy in Kubernetes using Helm:



resource "helm_release" "aws-iam-authenticator-proxy" {
  name              = "aws-iam-authenticator-proxy"
  chart             = "https://github.com/camptocamp/aws-iam-authenticator-proxy/tree/master/k8s"
  namespace         = "aws-iam-authenticator-proxy"
  dependency_update = true
  create_namespace  = tr

  values = [
    << EOT
eks_cluster_id: "${var.cluster_name}"
psk: "${random_password.auth_proxy_psk.result}"
serviceAccount:
  name: "aws-iam-authenticator-proxy"
  annotations:
    eks.amazonaws.com/role-arn: ${module.iam_assumable_role_aws_iam_authenticator_proxy.this_iam_role_arn}
EOT
  ]

  depends_on = [
    module.cluster,
  ]
}
Enter fullscreen mode Exit fullscreen mode

You can add an Ingress or configure the Service to use an L4 LoadBalancer by tuning the Helm values.

Discussion

pic
Editor guide