Skip to content

Phase 4 & 5: EKS Add-ons & ACM Certificate

4A - AWS Load Balancer Controller

!!! info "For more details, see: Deploy AWS Load Balancer Controller

# 1. Download and create IAM policy
curl -O https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.14.1/docs/install/iam_policy.json

aws iam create-policy \
  --policy-name AWSLoadBalancerControllerIAMPolicy \
  --policy-document file://iam_policy.json

# 2. Create IRSA (IAM Role for Service Account)
eksctl create iamserviceaccount \
  --cluster=$CLUSTER_NAME \
  --namespace=kube-system \
  --name=aws-load-balancer-controller \
  --attach-policy-arn=arn:aws:iam::$ACCOUNT_ID:policy/AWSLoadBalancerControllerIAMPolicy \
  --role-name aws-load-balancer-controller \
  --override-existing-serviceaccounts \
  --region $REGION \
  --approve

# 3. Install via Helm
helm repo add eks https://aws.github.io/eks-charts
helm repo update eks

helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
  --namespace kube-system \
  --set clusterName="$CLUSTER_NAME" \
  --set region="$REGION" \
  --set vpcId="$VPC_ID" \
  --set serviceAccount.create=false \
  --set serviceAccount.name=aws-load-balancer-controller \
  --version 1.14.0

Verify

kubectl get deploy -n kube-system aws-load-balancer-controller
# NAME                           READY   UP-TO-DATE   AVAILABLE
# aws-load-balancer-controller   2/2     2            2

kubectl get sa -n kube-system aws-load-balancer-controller -o yaml | grep role-arn
# eks.amazonaws.com/role-arn: arn:aws:iam::730335615031:role/aws-load-balancer-controller

4B - EBS CSI Driver

For more details, see: Install EBS CSI Driver

# 1. Create IAM role only (no SA creation yet - addon creates it)
eksctl create iamserviceaccount \
  --name ebs-csi-controller-sa \
  --namespace kube-system \
  --cluster $CLUSTER_NAME \
  --role-name AmazonEKS_EBS_CSI_DriverRole \
  --role-only \
  --attach-policy-arn arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy \
  --approve

ROLE_ARN=$(aws iam get-role --role-name AmazonEKS_EBS_CSI_DriverRole --query "Role.Arn" --output text)

# 2. Install addon
aws eks create-addon \
  --cluster-name $CLUSTER_NAME \
  --addon-name aws-ebs-csi-driver \
  --resolve-conflicts OVERWRITE

SA annotation race condition

The addon creates ebs-csi-controller-sa asynchronously. Wait for it to appear before annotating - polling with kubectl get deploy -n kube-system | grep ebs-csi until 0/2 appears works, then annotate and restart.

# 3. Annotate SA and restart controller
kubectl annotate serviceaccount ebs-csi-controller-sa \
  -n kube-system \
  eks.amazonaws.com/role-arn=$ROLE_ARN --overwrite

kubectl rollout restart deployment ebs-csi-controller -n kube-system
kubectl rollout status deployment ebs-csi-controller -n kube-system
# deployment "ebs-csi-controller" successfully rolled out

Set gp3 as Default StorageClass

kubectl apply -f - <<EOF
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: gp3
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
provisioner: ebs.csi.aws.com
parameters:
  type: gp3
  fsType: ext4
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
EOF

kubectl patch storageclass gp2 \
  -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'

kubectl get sc
# NAME            PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION
# gp2             kubernetes.io/aws-ebs   Delete          WaitForFirstConsumer   false
# gp3 (default)   ebs.csi.aws.com         Delete          WaitForFirstConsumer   true

Phase 5 - ACM Certificate (TLS for Custom Domain)

export CERT_ARN=$(aws acm request-certificate \
  --domain-name retail-microservices.ibtisam-iq.com \
  --validation-method DNS \
  --region us-east-1 \
  --query CertificateArn \
  --output text)
echo $CERT_ARN
# arn:aws:acm:us-east-1:730335615031:certificate/f0afb980-b86d-47cd-beaf-e8494affd00a

Get DNS Validation Record

aws acm describe-certificate \
  --certificate-arn $CERT_ARN \
  --region us-east-1 \
  --query "Certificate.DomainValidationOptions[0].ResourceRecord"
# {
#   "Name":  "_ab1c5499789efdc982a79ac4fa03a4ee.retail-microservices.ibtisam-iq.com.",
#   "Type":  "CNAME",
#   "Value": "_9d76931dd1cbceac5d14293b7463ce92.jkddzztszm.acm-validations.aws."
# }

DNS Validation

I added the CNAME record to the ibtisam-iq.com DNS zone in Cloudflare. ACM polls until the record resolves, then marks the certificate as ISSUED.

# Block until ISSUED (usually ~10-15 min)
aws acm wait certificate-validated --certificate-arn $CERT_ARN --region us-east-1

aws acm describe-certificate --certificate-arn $CERT_ARN --region us-east-1 \
  --query "Certificate.Status"
# "ISSUED"