Automate DNS Records Creation With ExternalDNS on AWS Elastic Kubernetes Service
This article will help automate the process of creating and configuring DNS records in Route 53 using ExternalDNS and Ingress on Elastic Kubernetes Service (EKS).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# External DNS policy to allow intract R53
ExternalDnsPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
Description: External DNS controller policy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Sid: PermitR53Listings
Action:
- route53:ListResourceRecordSets
- route53:ListHostedZones
Resource: '*'
- Effect: Allow
Sid: PermitR53Changes
Action:
- route53:ChangeResourceRecordSets
Resource: arn:aws:route53:::hostedzone/*
# I AM Role for External DNS
rExternalDnsRole:
Type: AWS::IAM::Role
Properties:
RoleName: "ExternalDns-Role"
AssumeRolePolicyDocument:
Fn::Sub:
- |
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": arn:aws:iam::<ACCOUNT_NUMBER>:oidc-provider/<OIDC_PROVIDER>
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"<<EKS Cluster Id>>": "system:serviceaccount:kube-system:external-dns"
}
}
}
]
}
- clusterid: !Sub "<<EKS Issuer>>:sub"
providerarn:
Path: /
ManagedPolicyArns:
- !Ref ExternalDnsPolicy
1
2
3
4
5
6
7
8
9
10
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
k8s-addon: external-dns.addons.k8s.io
k8s-app: external-dns
name: external-dns
namespace: kube-system
annotations:
eks.amazonaws.com/role-arn: <<provide IAM Role ARN that created on the above step>>
1
kubectl get sa
1
2
3
NAME SECRETS AGE
default 1 1h
external-dns 1 1h
1
kubectl apply external_dns.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: external-dns
labels:
app.kubernetes.io/name: external-dns
rules:
- apiGroups: [""]
resources: ["services","endpoints","pods","nodes"]
verbs: ["get","watch","list"]
- apiGroups: ["extensions","networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get","watch","list"]
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: external-dns-viewer
namespace: kube-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: external-dns
subjects:
- kind: ServiceAccount
name: external-dns
namespace: kube-system
apiVersion: apps/v1
kind: Deployment
metadata:
name: external-dns
namespace: kube-system
labels:
app: external-dns
spec:
replicas: 1
selector:
matchLabels:
app: external-dns
template:
metadata:
labels:
app: external-dns
spec:
serviceAccountName: external-dns
containers:
- name: external-dns
image: registry.k8s.io/external-dns/external-dns:v0.13.5
args:
- --source=service
- --source=ingress
- --provider=aws
- --aws-zone-type=private
- --registry=txt
- --txt-owner-id=external-dns-addon
- --domain-filter=<< provide host zone id >> # will make ExternalDNS see only the hosted zones matching provided domain
- --policy=upsert-only
env:
- name: AWS_REGION
value: us-east-1
resources:
limits:
cpu: 300m
memory: 400Mi
requests:
cpu: 200m
memory: 200Mi
imagePullPolicy: "Always"
1
kubectl get deployments
1
2
NAME READY UP-TO-DATE AVAILABLE AGE
external-dns 1/1 1 1 15m
1
kubectl logs external-dns-7f34d6d1b-sx4fx
1
2
3
4
5
time="2024-02-15T20:22:02Z" level=info msg="Instantiating new Kubernetes client"
time="2024-02-15T20:22:02Z" level=info msg="Using inCluster-config based on serviceaccount-token"
time="2024-02-15T20:22:02Z" level=info msg="Created Kubernetes client https://10.100.0.1:443"
time="2024-02-15T20:22:09Z" level=info msg="Applying provider record filter for domains: [<yourdomainname>.com. .<yourdomainname>.com.]"
time="2024-02-15T20:22:09Z" level=info msg="All records are already up to date"
- Rules: Define routing rules specifying how traffic is directed based on paths or hosts.
- Backend services: Specify backend services to handle the traffic, including service names and ports.
- Health checks: Implement health checks to ensure the availability and reliability of backend services.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: sample-ingress
annotations:
kubernetes.io/ingress.class: "alb"
alb.ingress.kubernetes.io/scheme: "internet-facing or internal"
alb.ingress.kubernetes.io/certificate-arn: "arn:aws:acm:your-region:your-account-id:certificate/your-acm-cert-arn"
spec:
rules:
- host: "app.external.dns.test.com"
http:
paths:
- path: /*
pathType: Prefix
backend:
service:
name: default-service
port:
number: 80
- path: /products
pathType: Prefix
backend:
service:
name: products-service
port:
number: 80
- path: /accounts
pathType: Prefix
backend:
service:
name: accounts-service
port:
number: 80
- metadata: Specifies the name of the Ingress and includes annotations for AWS-specific settings.
- kubernetes.io/ingress.class: "alb": Specifies the Ingress class to be used, indicating that the Ingress should be managed by the AWS ALB Ingress Controller.
- alb.ingress.kubernetes.io/scheme: "internet-facing" or "internal": Determines whether the ALB should be internet-facing or internal.
Options:- "internet-facing": The ALB is accessible from the internet.
- "internal": The ALB is internal and not accessible from the internet
- alb.ingress.kubernetes.io/certificate-arn: "arn:aws:acm:your-region:your-account-id: certificate/your-acm-cert-arn": Specifies the ARN (Amazon Resource Name) of the ACM (AWS Certificate Manager) certificate to be associated with the ALB.
- spec.rules: Defines routing rules based on the host. The /* rule directs traffic to the default service, while /products and /accounts have specific rules for products and accounts services.
- pathType: Specifies the type of matching for the path.
- backend.service.name and backend. service.port: Specifies the backend services for each rule.
