Kubernetes
AWS
Route 53
Elastic Load Balancer
Automation

How should I automatically associate a Kubernetes-provisioned elastic load balancer with a Route 53 alias?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

If Kubernetes creates an AWS load balancer for a Service or Ingress, the cleanest way to keep Route 53 in sync is usually external-dns. It watches Kubernetes resources, discovers the cloud load balancer hostname, and updates DNS records automatically. That is much safer than trying to maintain Route 53 aliases by hand after every rollout or replacement.

Why Manual DNS Entries Drift

AWS load balancer hostnames are assigned dynamically. If you create the Route 53 alias manually, you now have two sources of truth:

  • Kubernetes decides which load balancer exists
  • Route 53 decides which hostname your users reach

That works until the load balancer is recreated, the service is replaced, or the cluster is rebuilt. Then DNS drifts away from the real infrastructure.

The better design is to make the DNS name part of the Kubernetes resource and let a controller reconcile the Route 53 record.

Use external-dns on a Service

For a Service of type LoadBalancer, add an annotation that declares the desired public hostname.

yaml
1apiVersion: v1
2kind: Service
3metadata:
4  name: web
5  namespace: prod
6  annotations:
7    external-dns.alpha.kubernetes.io/hostname: app.example.com
8spec:
9  type: LoadBalancer
10  selector:
11    app: web
12  ports:
13    - port: 80
14      targetPort: 8080

external-dns reads that annotation, sees the AWS load balancer created for the service, and upserts the matching Route 53 record.

Or Use It on an Ingress

If the public entry point is really an ingress controller rather than a directly exposed service, annotate the Ingress instead.

yaml
1apiVersion: networking.k8s.io/v1
2kind: Ingress
3metadata:
4  name: web
5  namespace: prod
6  annotations:
7    external-dns.alpha.kubernetes.io/hostname: app.example.com
8spec:
9  ingressClassName: alb
10  rules:
11    - host: app.example.com
12      http:
13        paths:
14          - path: /
15            pathType: Prefix
16            backend:
17              service:
18                name: web
19                port:
20                  number: 80

Choose the resource that actually owns the public hostname. For a shared ingress layer, that is usually the Ingress, not the backend Service.

Deploy external-dns With Route 53 Access

external-dns needs two kinds of permissions:

  • read access to the relevant Kubernetes resources
  • permission to change the Route 53 hosted zone

A typical deployment passes arguments such as these:

yaml
1args:
2  - --source=service
3  - --source=ingress
4  - --provider=aws
5  - --domain-filter=example.com
6  - --policy=upsert-only
7  - --registry=txt
8  - --txt-owner-id=prod-cluster

The TXT registry is important because it helps track ownership and prevents multiple clusters or controllers from fighting over the same DNS records.

Let Terraform Manage the Zone, Not the Dynamic Records

If your platform uses Terraform, a good split of responsibility is:

  • Terraform creates the hosted zone and IAM role
  • Kubernetes plus external-dns manages the application records dynamically

That keeps infrastructure definitions clean while still allowing services to appear and disappear without manual DNS work.

Why Custom Scripts Are Usually Worse

A custom script can watch Kubernetes, look up the AWS load balancer, and call Route 53. But that script now needs:

  • retries
  • reconciliation logic
  • idempotency
  • credentials
  • monitoring

external-dns already solves those problems. In most cases, it is better to use the existing controller than to build a smaller, less battle-tested copy of it.

Common Pitfalls

  • Missing IAM permissions for Route 53 even though external-dns is running fine in the cluster.
  • Annotating the wrong Kubernetes object and expecting the DNS record to follow a different load balancer.
  • Forgetting TXT ownership records and then getting conflicts between clusters or controllers.
  • Expecting the DNS record to appear instantly when Route 53 propagation still takes time.
  • Managing the same record manually while external-dns is also trying to reconcile it.

Summary

  • 'external-dns is usually the right automation tool for mapping Kubernetes-created AWS load balancers into Route 53.'
  • Put the desired hostname in an annotation on the Service or Ingress that owns the public endpoint.
  • Give the controller scoped permission to update the hosted zone.
  • Use TXT ownership records to avoid conflicts and drift.
  • Keep DNS derived from Kubernetes state instead of maintaining aliases by hand.

Course illustration
Course illustration

All Rights Reserved.