An Amazon EKS add-on is a cluster service integrated with EKS and supported or managed through it. A platform control plane can install add-ons in its base pipeline so that networking, DNS, storage, and pod identity are available before workloads depend on them. Examples include kube-proxy, vpc-cni, CoreDNS, the EBS and EFS CSI drivers, and the EKS Pod Identity Agent. section 7.4.3
Keep the management boundary explicit. Karpenter can belong in the same base pipeline, but it is not described here as a fully AWS-managed add-on: its deployment uses Helm. The EFS CSI driver illustrates how that boundary can change. It previously required self-managed deployment, upgrades, and monitoring despite substantial AWS support; it is now a fully managed EKS add-on. section 7.4.3
$ cat eks_addons.tf
module "eks_addons" {
source = "aws-ia/eks-blueprints-addons/aws"
version = "1.21.0"
depends_on = [module.eks]
cluster_name = module.eks.cluster_name
cluster_endpoint = module.eks.cluster_endpoint
cluster_version = module.eks.cluster_version
oidc_provider_arn = module.eks.oidc_provider_arn
eks_addons = {
kube-proxy = { most_recent = true } #1
vpc-cni = {
most_recent = true
service_account_role_arn = module.vpc_cni_irsa_role.
➥ iam_role_arn #2
}
coredns = {
most_recent = true
configuration_values = jsonencode({
autoScaling = {
"enabled" = true #3
}
nodeSelector = {
"node.kubernetes.io/role" = "management"
}
tolerations = [ #4
{
key = "dedicated"
operator = "Equal"
value = "management"
effect = "NoSchedule"
}
]
})
}
aws-ebs-csi-driver = {
amost_recent = true
service_account_role_arn = module.ebs_csi_irsa_role.iam_role_arn
configuration_values = jsonencode({
controller = {
nodeSelector = {
"node.kubernetes.io/role" = "management"
}
tolerations = [
{
key = "dedicated"
operator = "Equal"
value = "management"
effect = "NoSchedule"
}
]
}
})
}
aws-efs-csi-driver = {
amost_recent = true
service_account_role_arn = module.efs_csi_irsa_role.iam_role_arn
configuration_values = jsonencode({
controller = {
nodeSelector = {
"node.kubernetes.io/role" = "management"
}
tolerations = [
{
key = "dedicated"
operator = "Equal"
value = "management"
effect = "NoSchedule"
}
]
}
})
}
eks-pod-identity-agent = { most_recent = true }
}
}
module "vpc_cni_irsa_role" { #5
source = "terraform-aws-modules/iam/aws//modules/
➥ iam-role-for-service-accounts-eks"
version = "~> 5.40.0"
role_path = "/PlatformRoles/"
role_name = "${var.cluster_name}-vpc-cni"
attach_vpc_cni_policy = true
vpc_cni_enable_ipv4 = true
oidc_providers = {
main = {
provider_arn = module.eks.oidc_provider_arn
namespace_service_accounts = ["kube-system:aws-node"]
}
}
}
module "ebs_csi_irsa_role" {
source = "terraform-aws-modules/iam/aws//modules/
➥ iam-role-for-service-accounts-eks"
version = "~> 5.40.0"
role_path = "/PlatformRoles/"
role_name = "${var.cluster_name}-ebs-csi-controller-sa"
attach_ebs_csi_policy = true
oidc_providers = {
main = {
provider_arn = module.eks.oidc_provider_arn
namespace_service_accounts = ["kube-system:ebs-csi-controller-sa"]
}
}
}
module "efs_csi_irsa_role" {
source = "terraform-aws-modules/iam/aws//modules/
➥ iam-role-for-service-accounts-eks"
version = "~> 5.40.0"
role_path = "/PlatformRoles/"
role_name = "${var.cluster_name}-efs-csi-controller-sa"
attach_efs_csi_policy = true
oidc_providers = {
main = {
provider_arn = module.eks.oidc_provider_arn
namespace_service_accounts = ["kube-system:efs-csi-controller-sa"]
}
}
}
The Terraform listing shows AWS EKS Blueprints Addons configured after cluster creation. Its visible entries request the most recent compatible versions and pass add-on-specific settings for VPC CNI and CoreDNS. section 7.4.3
For AWS-managed add-ons, the Blueprints module is a focused fit; using it more broadly risks coupling and complexity. Setting `most_recent = true` selects the latest managed add-on version associated with the cluster’s Kubernetes version. Confine that choice to the routinely run vendor-managed pipeline, where it accompanies management-node security patch updates, rather than assuming every pipeline should advance add-on versions. section 7.4.3
Verify function, not just a Running status:
- For EBS storage, create a persistent volume claim, run a pod that writes to it, verify the write, expand the claim, and confirm its new size. section 7.4.6
- For EFS storage, use two pods to check multi-write access to a shared volume. section 7.4.6
- Place test pods where nodes actually exist. When only management nodes are running, node affinity and tolerations let the fixtures run on that dedicated pool. section 7.4.6
#!/usr/bin/env bats
@test "validate dynamic ebs volume claim created" { #1
run bash -c "kubectl describe pv | grep 'test-system/test-ebs-claim'"
[[ "${output}" =~ "Claim" ]]
}
@test "validate claim-test-pod health" { #2
run bash -c "kubectl get all -n test-system | grep 'pod/claim-test-pod'"
[[ "${output}" =~ "Running" ]]
}
@test "validate dynamic ebs pvc write access" { #3
run bash -c "kubectl exec -it -n test-system claim-test-pod
➥ -- cat /data/out.txt"
[[ "${output}" =~ "UTC" ]]
}
These Bats assertions check that an EBS volume claim exists, its test pod is running, and the pod can read data written to the mounted volume—evidence beyond service status alone. section 7.4.6
