ExternalDNS
ExternalDNS is a Kubernetes controller that turns Ingress and Service host names into DNS records. In the Web App Blueprint it runs twice per cluster, once for the public zone and once for the private zone, because those zones live in two different AWS accounts.
What it does
ExternalDNS watches objects with a host name, such as an Ingress for blueprint-api.dev.company.com, finds the load balancer address behind it and creates the matching record in a DNS provider. It marks records it owns with a TXT record so it never overwrites something a person created. With policy: sync it also removes records when the Ingress goes away.
How BuiltForProd uses it
Both releases come from the same external-dns module (chart external-dns 1.21.1, installed into kube-system), with Pod Identity for AWS credentials and txtOwnerId set to the cluster name.
| Unit | Release | Zone | Zone account | Role assumed |
|---|---|---|---|---|
external-dns | external-dns | Public company.com, filtered to dev.company.com | DNS account | acme-route53-cross-account in the DNS account |
external-dns-internal | ext-dns-int | Private internal.company.com | Network account | acme-route53-cross-account in the network account |
The hosted zone id for the public release comes from the acm-certificate unit, which already resolves the zone by name in the DNS account; the internal release uses a wildcard so it can serve any private zone. Cross-account access is two steps: the Pod Identity role in the platform account holds the AWS-published ExternalDNS policy scoped to the zone ARN plus sts:AssumeRole on the cross-account role, and the release is started with --aws-assume-role pointing at it. Neither platform account can write to the zones directly; only those two roles can, and they exist only for validation and ExternalDNS records.
What gets written today: the public release creates blueprint-api.dev.company.com for the API's internet-facing ALB; the internal release creates argocd.dev.internal.company.com for the internal ALB in front of ArgoCD, in the private internal.company.com zone. Any new Ingress with a host under those domains is picked up the same way. The CloudFront record for the front end is not ExternalDNS's job; the frontend-cdn unit writes that alias itself.
Terms you will see
| Term | Meaning |
|---|---|
| Domain filter | The suffix a release is allowed to manage, such as dev.company.com. |
| TXT owner id | The marker ExternalDNS writes to claim a record. |
| Sync policy | Create, update and delete records to match the cluster. |
| Hosted zone | A Route 53 zone; public in the DNS account, private in the network account. |
| Cross-account role | The role in the zone's account that the release assumes. |
Where to read more
- Route 53 for the zones
- AWS Load Balancer Controller for the ALB the records point at
- STS and role assumption for the cross-account step
- Web App Blueprint overview