Skip to content

External DNS Add-on

External DNS add-on is based on the ExternalDNS open source project and allows integration of exposed Kubernetes services and Ingresses with DNS providers, in particular Amazon Route 53.

The add-on provides functionality to configure IAM policies and Kubernetes service accounts for Route 53 integration support based on AWS Tutorial for External DNS.

Usage

import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import * as blueprints from '@aws-quickstart/eks-blueprints';

const app = new cdk.App();

const hostedZoneName = ...

const addOn = new blueprints.addons.ExternalDnsAddOn({
    hostedZoneResources: [hostedZoneName]; // can be multiple
});

const blueprint = blueprints.EksBlueprint.builder()
  .version("auto")
  .addOns(addOn)
  .resourceProvider(hostedZoneName, new blueprints.LookupHostedZoneProvider(hostedZoneName))
  .addOns(addOn)
  .build(app, 'my-stack-name');

To validate that external DNS add-on is running ensure that the add-on deployment is in RUNNING state:

# Assuming add-on is installed in the external-dns namespace.
$ kubectl get po -n external-dns
NAME                           READY   STATUS    RESTARTS   AGE
external-dns-fcf6c9c66-xd8f4   1/1     Running   0          3d3h

Using External DNS

You can now provision external services and ingresses integrating with Route 53. For example to provision an NLB you can use the following service manifest:

apiVersion: v1
kind: Service
metadata:
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: '60'
    service.beta.kubernetes.io/aws-load-balancer-type: nlb
    external-dns.alpha.kubernetes.io/hostname: <MyDomainName>
  name: udp-test1
spec:
  type: LoadBalancer
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    name: your-app

Note the external-dns.alpha.kubernetes.io/hostname annotation for the service name that allows specifying its domain name.

Hosted Zone Providers

In order for external DNS to work, you need to supply one or more hosted zones. Hosted zones are expected to be supplied leveraging resource providers.

To help customers handle common use cases for Route 53 provisioning the framework provides a few convenience providers that can be registered with the EKS Blueprint Stack.

Name look-up and direct import provider: This provider will allow to bind to an existing hosted zone based on its name.

const myDomainName = "";

blueprints.EksBlueprint.builder()
    //  Register hosted zone1 under the name of MyHostedZone1
    .resourceProvider("MyHostedZone1", new blueprints.LookupHostedZoneProvider(myDomainName))
    .addOns(new blueprints.addons.ExternalDnsAddOn({
        hostedZoneResources: ["MyHostedZone1"];
    }))
    .build(...);

If the hosted zone ID is known, then the recommended approach is to use a ImportHostedZoneProvider which bypasses any lookup calls.

const myHostedZoneId = "";
blueprints.EksBlueprint.builder()
    //  Register hosted zone1 under the name of MyHostedZone1
    .resourceProvider("MyHostedZone1",  new blueprints.ImportHostedZoneProvider(myHostedZoneId))
    .addOns(new blueprints.addons.ExternalDnsAddOn({
        hostedZoneResources: ["MyHostedZone1"];
    }))
    .version("auto")
    .build(...);

Delegating Hosted Zone Provider

In many cases, enterprises choose to decouple provisioning of root domains and subdomains. A common pattern is to have a specific DNS account (AWS account) hosting the root domain, while subdomains may be created within individual workload accounts.

This implies cross-account access from child account to the parent DNS account for subdomain delegation.

Prerequisites:

  1. Parent account defines an IAM role with the following managed policies: AmazonRoute53DomainsFullAccess AmazonRoute53ReadOnlyAccess AmazonRoute53AutoNamingFullAccess

  2. Create trust relationship between this role and the child account that is expected to add subdomains. For info see IAM tutorial.

Example:

Let's assume that parent DNS account parentAccountId has domain named myglobal-domain.com. Now when provisioned an EKS Blueprints cluster you would like to use a stage specific name like dev.myglobal-domain.com or test.myglobal-domain.com. In addition to these requirements, you would like to enable tenant specific access to those domains such as my-tenant1.dev.myglobal-domain.com or team specific access team-riker.dev.myglobal-domain.com.

The setup will look the following way:

  1. In the parentAccountId account you create a role for delegation (DomainOperatorRole in this example) and a trust relationship to the child account in which EKS Blueprints will be provisioned. In a general case, the number of child accounts can be large, so each of them will have to be listed in the trust relationship.
  2. In the parentAccountId you create a public hosted zone for myglobal-domain.com. With that the setup that may require separate automation (or a manual process) is complete.
  3. Use the following configuration of the add-on:
blueprints.EksBlueprint.builder()
    //  Register hosted zone1 under the name of MyHostedZone1
    .resourceProvider("MyHostedZone1",  new blueprints.DelegatingHostedZoneProvider({
        parentDomain: 'myglobal-domain.com',
        subdomain: 'dev.myglobal-domain.com', 
        parentAccountId: parentDnsAccountId,
        delegatingRoleName: 'DomainOperatorRole',
        wildcardSubdomain: true
    }))
    .addOns(new blueprints.addons.ExternalDnsAddOn({
        hostedZoneResources: ["MyHostedZone1"];
    }))
    .version("auto")

The parameter wildcardSubdomain above when set to true will also create a CNAME for *.dev.myglobal-domain.com. This is at the moment used for host based routing within EKS (e.g. with NGINX ingress).

Configuration Options

  • namespace: Optional target namespace where add-on will be installed. Changing this value on the operating cluster is not recommended. Set to external-dns by default.
  • version: The add-on is leveraging a Bitnami helm chart. This parameter allows overriding the helm chart version used.
  • hostedZone: Hosted zone provider is a interface that provides one or more hosted zones that the add-on will leverage for the service and ingress configuration.

Functionality

  1. Applies External-DNS configuration for AWS DNS provider. See AWS Tutorial for External DNS for more information.
  2. Supports standard helm configuration options.