Skip to content

Create an EKS cluster with EBS CSI driver

An EKS cluster can be created in a number of ways, including AWS console, CLI, Terraform or CloudFormation. The quickest and simplest way to create an EKS cluster is to use eksctl, a CloudFormation wrapper, that will be used in this guide.

Define the environment parameters

The following are the parameters needed for the commands in this guide, which must be set the values that match your environment and needs.

# AWS region you're operating in
export AWS_REGION="eu-central-1"

# autoscaling group minimum number of nodes
ASG_MIN_NODES="2"

# autoscaling group maximum number of nodes
ASG_MAX_NODES="4"

# EKS cluster name
CLUSTER_NAME="my-eks-cluster"

# EKS kubernetes version to deploy
KUBERNETES_VERSION="1.23"

Info

The AWS_REGION variable must be an environment variable (thus the export) to be used by eksctl and aws commands. The other variables can be just shell variables.

Tip

A list of available kubernetes versions for the KUBERNETES_VERSION variable can be obtained running

aws eks describe-addon-versions --query "addons[].addonVersions[].compatibilities[].clusterVersion" | jq 'unique|sort'

Create the EKS cluster

The following command can create an EKS cluster based on the parameters defined above:

eksctl create cluster -m ${ASG_MIN_NODES} -M ${ASG_MAX_NODES} -n ${CLUSTER_NAME} --version ${KUBERNETES_VERSION}

The previous command waits until the cluster is created and also updates the KUBECONFIG file with the details of the new cluster.

Configure the EBS CSI controller

From version 1.23 onwards it is necessary to create the addon for the EBS CSI driver.

aws eks create-addon --cluster-name ${CLUSTER_NAME} --addon-name aws-ebs-csi-driver

EKS pods' service accounts can assume AWS IAM roles to be able to authenticate and interact with the AWS APIs. They are mapped to web identities via an IAM OIDC provider that must be created for the EKS cluster. You will then need to create a proper role for the EBS CSI controller to be able to create and manage EBS volumes.

# define variables for IAM
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
OIDC_URL=$(aws eks describe-cluster --name ${CLUSTER_NAME} --output text --query "cluster.identity.oidc.issuer")
OIDC_ID=$(cut -d/ -f3- <<<$OIDC_URL)
EBS_ROLE="AmazonEKS_EBS_CSI_Driver-${CLUSTER_NAME}"
ROLE_TRUST_POLICY=$(mktemp)
ROLE_PERMISSION_POLICY=$(mktemp)

# prepare the trust policy document
cat > ${ROLE_TRUST_POLICY} <<EOF
{
    "Version": "2012-10-17",
    "Statement": [{
        "Effect": "Allow",
        "Principal": {
            "Federated": "arn:aws:iam::${ACCOUNT_ID}:oidc-provider/${OIDC_ID}"
        },
        "Action": "sts:AssumeRoleWithWebIdentity",
        "Condition": {
            "StringEquals": {
                "${OIDC_ID}:sub": "system:serviceaccount:kube-system:ebs-csi-controller-sa"
            }
        }
    }]
}
EOF

# create the role for the EBS CSI controller with the proper trust policy
aws iam create-role --role-name ${EBS_ROLE} --assume-role-policy-document file://${ROLE_TRUST_POLICY}

# fetch a sample permission policy document
curl -sSfL -o ${ROLE_PERMISSION_POLICY} https://raw.githubusercontent.com/kubernetes-sigs/aws-ebs-csi-driver/master/docs/example-iam-policy.json

# create the permission policy
PERMISSION_POLICY_ARN=$(aws iam create-policy --policy-name ${EBS_ROLE} --policy-document file://${ROLE_PERMISSION_POLICY} --query Policy.Arn --output text)

# attach the policy to the role
aws iam attach-role-policy --policy-arn ${PERMISSION_POLICY_ARN} --role-name ${EBS_ROLE}

# clean up temporary files
rm ${ROLE_TRUST_POLICY}
rm ${ROLE_PERMISSION_POLICY}

Next, you must prepare the OIDC provider (see also AWS documentation). If the EKS cluster has just been created the OIDC provider does not exist yet, otherwise you can run the following command to make sure

aws iam list-open-id-connect-providers | grep $OIDC_ID

If no output is returned, the OIDC provider does not exist and you must create it.

The eksctl does the heavy lifting for you and creates the OIDC provider with the proper configuration for your EKS cluster.

eksctl utils associate-iam-oidc-provider --cluster ${CLUSTER_NAME} --approve

Get rid of the eksctl magic and configure the OIDC provider yourself.

Get the SHA1 fingerprint for validating the OIDC provider certificate:

OIDC_HOST=$(echo $OIDC_ID | cut -d/ -f1)
SHA1_FINGERPRINT=$({echo | openssl s_client -connect ${OIDC_HOST}:443 -servername ${OIDC_HOST} -showcerts | openssl x509 -fingerprint -noout -sha1} 2>/dev/null | cut -d= -f2 | sed s/://g)

Create the OIDC provider:

aws iam create-open-id-connect-provider --url ${OIDC_URL} --thumbprint-list ${SHA1_FINGERPRINT} --client-id-list sts.amazonaws.com

You must then configure the Kubernetes service account to assume the role

# annotate the controller service account with the new role ARN
kubectl -n kube-system annotate serviceaccount ebs-csi-controller-sa eks.amazonaws.com/role-arn=arn:aws:iam::${ACCOUNT_ID}:role/${EBS_ROLE}

# restart ebs-csi-controller pods
kubectl -n kube-system rollout restart deployment ebs-csi-controller

Your EKS cluster is now configured to dynamically allocate EBS volumes. You need to create the proper StorageClass resources for your PersistentVolumeClaims to use, like in this example.


Last update: 2023-01-03 10:57:06