DEV Community

Hagai Hillel
Hagai Hillel

Posted on

K8S - How to use EKS (AWS) Refresh token

Skuber

The Skuber client is a Scala library designed for interacting with Kubernetes clusters. It offers a high-level, strongly typed API for managing Kubernetes resources such as Pods, Services, Deployments, ReplicaSets, and Ingresses.
https://github.com/hagay3/skuber

How to use EKS (AWS) Refresh token

Background
Step-by-step guide
Setup the environment variables
Create IAM Role
Create a service account
Create the aws-auth mapping
Refresh EKS Code Examples)

Background

Skuber has the functionality to refresh EKS (AWS) token with an IAM role and cluster configurations.

The initiative:

Step-by-step guide

Pay attention to the fact that skuber can be deployed in one cluster and the cluster you want to control can be a remote cluster.
In this guide I will use the following:

SKUBER_CLUSTER - the cluster skuber app will be deployed on.
REMOTE_CLUSTER - the cluster that skuber will be connected to.

Setup the environment variables

  • Make sure aws cli is configured properly
export ACCOUNT_ID=$(aws sts get-caller-identity --output text --query Account)
echo $ACCOUNT_ID
Enter fullscreen mode Exit fullscreen mode

Set the cluster name and region that need access to (REMOTE_CLUSTER)
use aws eks list-clusters to see the cluster names.

export REMOTE_CLUSTER=example-cluster
export REGION=us-east-1
Enter fullscreen mode Exit fullscreen mode

Set the cluster name which skuber app will run from (SKUBER_CLUSTER)

Set the namespace name which skuber app will run from

Set the oidc provider id

Set the service account name that skuber app will be attached to (we will create it later)

export SKUBER_CLUSTER=skuber-cluster
export SKUBER_NAMESPACE=skuber-namespace
export OIDC=$(aws eks describe-cluster --name $SKUBER_CLUSTER --output text --query cluster.identity.oidc.issuer | cut -d'/' -f3,4,5)
echo $OIDC
export SKUBER_SA=skuber-serviceaccount
Enter fullscreen mode Exit fullscreen mode

Create IAM Role

This role will allow skuber service account to assume this role.

cat > skuber_iam_role.json  <<EOL
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::${ACCOUNT_ID}:oidc-provider/${OIDC}"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringLike": {
                    "${OIDC}:sub": "system:serviceaccount:${SKUBER_NAMESPACE}:${SKUBER_SA}"
                }
            }
        }
    ]
}
EOL
Enter fullscreen mode Exit fullscreen mode

Create and set IAM role name

export IAM_ROLE_NAME=skuber-eks
aws iam create-role \
--role-name $IAM_ROLE_NAME \
--description "Kubernetes role for skuber client" \
--assume-role-policy-document file://skuber_iam_role.json \
--output text \
--query 'Role.Arn'
Enter fullscreen mode Exit fullscreen mode

Create a service account

Change the context to SKUBER_CLUSTER and create the service account

kubectl config use-context arn:aws:eks:${REGION}:${ACCOUNT_ID}:cluster/${SKUBER_CLUSTER}

kubectl apply -n $
-f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: ${SKUBER_SA}
EOF
Enter fullscreen mode Exit fullscreen mode

Create the aws-auth mapping

In order to map aws iam role to the actual kubernetes cluster permissions, we need to create a mapping:
IAM Role -> Kubernetes Permissions

For this example I'm using existing masters permissions group, its recommended to create something more specific with RBAC.

  • Create this mapping on every cluster that skuber will be able to interact with.

Change the context to REMOTE_CLUSTER.

kubectl config use-context arn:aws:eks:${REGION}:${ACCOUNT_ID}:cluster/${REMOTE_CLUSTER}
kubectl edit configmap aws-auth -n kube-system
Enter fullscreen mode Exit fullscreen mode

Add the following mapping

  • Replace the variables with the actual values
    - rolearn: arn:aws:iam::$ACCOUNT_ID:role/$IAM_ROLE_NAME
      username: ci
      groups:
        - system:masters
Enter fullscreen mode Exit fullscreen mode

Refresh EKS Code Examples

  • Set the environment variables according to REMOTE_CLUSTER
export namespace=default
export serverUrl=$(aws eks describe-cluster --name $REMOTE_CLUSTER --output text --query cluster.endpoint)
export certificate=$(aws eks describe-cluster --name $REMOTE_CLUSTER --output text --query cluster.certificateAuthority)
export clusterName=$REMOTE_CLUSTER
export region=$AWS_REGION
Enter fullscreen mode Exit fullscreen mode

A working example for using AwsAuthRefreshable

implicit private val as = ActorSystem()
implicit private val ex = as.dispatcher
val namespace = System.getenv("namespace")
val serverUrl = System.getenv("serverUrl")
val certificate = Base64.getDecoder.decode(System.getenv("certificate"))
val clusterName = System.getenv("clusterName")
val region = Regions.fromName(System.getenv("region"))
val cluster = Cluster(server = serverUrl, certificateAuthority = Some(Right(certificate)), clusterName = Some(clusterName), awsRegion = Some(region))

val context = Context(cluster = cluster, authInfo = AwsAuthRefreshable(cluster = Some(cluster)))

val k8sConfig = Configuration(clusters = Map(clusterName -> cluster), contexts = Map(clusterName -> context)).useContext(context)

val k8s: KubernetesClient = k8sInit(k8sConfig)
listPods(namespace, 0)
listPods(namespace, 5)
listPods(namespace, 11)

k8s.close
Await.result(as.terminate(), 10.seconds)
System.exit(0)

def listPods(namespace: String, minutesSleep: Int): Unit = {
  println(s"Sleeping $minutesSleep minutes...")
  Thread.sleep(minutesSleep * 60 * 1000)
  println(DateTime.now)
  val pods = Await.result(k8s.listInNamespace[PodList](namespace), 10.seconds)
  println(pods.items.map(_.name))
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)