External DNS - Used for Updating Route53 RecordSets from Kubernetes
Step-01: Introduction
- We need to create IAM Policy, k8s Service Account & IAM Role and associate them together for external-dns pod to add or remove entries in AWS Route53 Hosted Zones.
- Update External-DNS default manifest to support our needs
- Deploy & Verify logs
Step-02: Create IAM Policy
- This IAM policy will allow external-dns pod to add, remove DNS entries (Record Sets in a Hosted Zone) in AWS Route53 service
- Go to Services -> IAM -> Policies -> Create Policy
- Click on JSON Tab and copy paste below JSON
- Click on Visual editor tab to validate
- Click on Review Policy
- Name: AllowExternalDNSUpdates
- Description: Allow access to Route53 Resources for ExternalDNS
- Click on Create Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"route53:ChangeResourceRecordSets"
],
"Resource": [
"arn:aws:route53:::hostedzone/*"
]
},
{
"Effect": "Allow",
"Action": [
"route53:ListHostedZones",
"route53:ListResourceRecordSets"
],
"Resource": [
"*"
]
}
]
}
- Make a note of Policy ARN which we will use in next step
arn:aws:iam::180789647333:policy/AllowExternalDNSUpdates
Step-03: Create IAM Role, k8s Service Account & Associate IAM Policy
- As part of this step, we are going to create a k8s Service Account named
external-dns
and also a AWS IAM role and associate them by annotating role ARN in Service Account.
- In addition, we are also going to associate the AWS IAM Policy
AllowExternalDNSUpdates
to the newly created AWS IAM Role.
Create IAM Role, k8s Service Account & Associate IAM Policy
# Template
eksctl create iamserviceaccount \
--name service_account_name \
--namespace service_account_namespace \
--cluster cluster_name \
--attach-policy-arn IAM_policy_ARN \
--approve \
--override-existing-serviceaccounts
# Replaced name, namespace, cluster, arn
eksctl create iamserviceaccount \
--name external-dns \
--namespace default \
--cluster eksdemo1 \
--attach-policy-arn arn:aws:iam::180789647333:policy/AllowExternalDNSUpdates \
--approve \
--override-existing-serviceaccounts
Verify the Service Account
- Verify external-dns service account, primarily verify annotation related to IAM Role
kubectl get sa external-dns
- Go to Services -> CloudFormation
- Verify the latest CFN Stack created.
- Click on Resources tab
- Click on link in Physical ID field which will take us to IAM Role directly
Verify IAM Role & IAM Policy
- With above step in CFN, we will be landed in IAM Role created for external-dns.
- Verify in Permissions tab we have a policy named AllowExternalDNSUpdates
- Now make a note of that Role ARN, this we need to update in External-DNS k8s manifest
arn:aws:iam::180789647333:role/eksctl-eksdemo1-addon-iamserviceaccount-defa-Role1-1O3H7ZLUED5H4
AWS EKS - Elastic Kubernetes Service - Masterclass
Step-04: Update External DNS Kubernetes manifest
- Original Template you can find in https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/aws.md
- File Location: kube-manifests/01-Deploy-ExternalDNS.yml
Change-1: Line number 9: IAM Role update
- Copy the role-arn you have made a note at the end of step-03 and replace at line no 9.
eks.amazonaws.com/role-arn: arn:aws:iam::411686525067:role/eksctl-demo1-addon-iamserviceaccount-default-Role1-M7IEPRHZYLPB
- We used eksctl to create IAM role and attached the
AllowExternalDNSUpdates
policy
- We didnt use KIAM or Kube2IAM so we don't need these two lines, so commented
#annotations:
#iam.amazonaws.com/role: arn:aws:iam::ACCOUNT-ID:role/IAM-SERVICE-ROLE-NAME
# - --domain-filter=external-dns-test.my-org.com # will make ExternalDNS see only the hosted zones matching provided domain, omit to process all available hosted zones
# - --policy=upsert-only # would prevent ExternalDNS from deleting any records, omit to enable full synchronization
apiVersion: v1
kind: ServiceAccount
metadata:
name: external-dns
# If you're using Amazon EKS with IAM Roles for Service Accounts, specify the following annotation.
# Otherwise, you may safely omit it.
annotations:
# Substitute your account ID and IAM service role name below. #Change-1: Replace with your IAM ARN Role for extern-dns
eks.amazonaws.com/role-arn: arn:aws:iam::180789647333:role/eksctl-eksdemo1-addon-iamserviceaccount-defa-Role1-1QHG9KUCNQB50
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: external-dns
rules:
- apiGroups: [""]
resources: ["services","endpoints","pods"]
verbs: ["get","watch","list"]
- apiGroups: ["extensions"]
resources: ["ingresses"]
verbs: ["get","watch","list"]
- apiGroups: [""]
resources: ["nodes"]
verbs: ["list","watch"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: external-dns-viewer
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: external-dns
subjects:
- kind: ServiceAccount
name: external-dns
namespace: default
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: external-dns
spec:
strategy:
type: Recreate
selector:
matchLabels:
app: external-dns
template:
metadata:
labels:
app: external-dns
# If you're using kiam or kube2iam, specify the following annotation.
# Otherwise, you may safely omit it. #Change-2: Commented line 55 and 56
#annotations:
#iam.amazonaws.com/role: arn:aws:iam::ACCOUNT-ID:role/IAM-SERVICE-ROLE-NAME
spec:
serviceAccountName: external-dns
containers:
- name: external-dns
image: registry.opensource.zalan.do/teapot/external-dns:latest
args:
- --source=service
- --source=ingress
# Change-3: Commented line 65 and 67 - --domain-filter=external-dns-test.my-org.com # will make ExternalDNS see only the hosted zones matching provided domain, omit to process all available hosted zones
- --provider=aws
# Change-3: Commented line 65 and 67 - --policy=upsert-only # would prevent ExternalDNS from deleting any records, omit to enable full synchronization
- --aws-zone-type=public # only look at public hosted zones (valid values are public, private or no value for both)
- --registry=txt
- --txt-owner-id=my-hostedzone-identifier
securityContext:
fsGroup: 65534 # For ExternalDNS to be able to read Kubernetes and AWS token files
Step-05: Deploy ExternalDNS
- Deploy the manifest
# Deploy external DNS
kubectl apply -f kube-manifests/
# Verify Deployment by checking logs
kubectl logs -f $(kubectl get po | egrep -o 'external-dns[A-Za-z0-9-]+')
# List pods (external-dns pod should be in running state)
kubectl get pods
References
- https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/alb-ingress.md
- https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/aws.md