Skip to content

ExternalDNS for Kubernetes with AWS Route53

External DNS EKS logo Route53

ExternalDNS synchronizes exposed Kubernetes Services, Ingresses, and Gateway API HTTPRoute resources with external DNS providers like AWS Route53.

This guide demonstrates how to configure ExternalDNS on Amazon EKS using EKS Pod Identity to automate Route53 DNS records dynamically.


📺 Video Walkthrough


Step 1. Configure IAM Policy & EKS Pod Identity

external-dns-iam.tf

# 1. Route53 IAM Policy
resource "aws_iam_policy" "external_dns" {
  name        = "ExternalDNSControllerPolicy-${module.eks.cluster_name}"
  description = "Allows ExternalDNS to manage DNS records in Route53"

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = [
          "route53:ChangeResourceRecordSets"
        ]
        Resource = ["arn:aws:route53:::hostedzone/*"]
      },
      {
        Effect = "Allow"
        Action = [
          "route53:ListHostedZones",
          "route53:ListResourceRecordSets",
          "route53:ListTagsForResources"
        ]
        Resource = ["*"]
      }
    ]
  })
}

# 2. IAM Role with Pod Identity Trust
data "aws_iam_policy_document" "pod_id_trust" {
  statement {
    effect = "Allow"
    principals {
      type        = "Service"
      identifiers = ["pods.eks.amazonaws.com"]
    }
    actions = ["sts:AssumeRole", "sts:TagSession"]
  }
}

resource "aws_iam_role" "external_dns" {
  name               = "external-dns-controller-${module.eks.cluster_name}"
  assume_role_policy = data.aws_iam_policy_document.pod_id_trust.json
}

resource "aws_iam_role_policy_attachment" "external_dns" {
  role       = aws_iam_role.external_dns.name
  policy_arn = aws_iam_policy.external_dns.arn
}

# 3. Pod Identity Association
resource "aws_eks_pod_identity_association" "external_dns" {
  cluster_name    = module.eks.cluster_name
  namespace       = "external-dns"
  service_account = "external-dns-controller"
  role_arn        = aws_iam_role.external_dns.arn
}


Step 2. Install ExternalDNS via Helm

external-dns-values.yaml

serviceAccount:
  create: true
  name: external-dns-controller
provider:
  name: aws
sources:
  - ingress
  - gateway-httproute
  - service
domainFilters:
  - vettom.online
txtOwnerId: "eks-demo-cluster"
policy: sync # or "upsert-only"

helm repo add external-dns https://kubernetes-sigs.github.io/external-dns/
helm repo update

helm install external-dns external-dns/external-dns \
  --namespace external-dns \
  --create-namespace \
  --version 1.15.0 \
  -f external-dns-values.yaml

Step 3. Expose an Application and Validate DNS Sync

When deploying an Ingress or HTTPRoute specifying hostnames: ["app.vettom.online"], ExternalDNS automatically creates the A record (alias to the ALB/NLB) and a tracking TXT record in Route53.

# Check ExternalDNS logs
kubectl logs -f -n external-dns -l app.kubernetes.io/name=external-dns

# Verify Route53 DNS propagation
dig +short app.vettom.online