Since the my first post about Azure Hybrid DNS, I ran into a few more scenarios that I want to share with you.
In this post, I will go over the scenario in which you can use Azure Private DNS Zones as a sub-domain of your locally hosted DNS Zones.

Table of Contents

  1. Introduction
  2. Goal
  3. Architecture
  4. Setup
    1. Local DNS Zone
    2. AKS Cluster
    3. Azure Private DNS Zone
    4. CoreDNS on AKS
    5. DNS Delegation
  5. Testing
  6. Conclusion

This is a multi part article with the following parts:

Part 1 - Azure Hybrid DNS Architecture
Part 2 - Azure Hybrid DNS Part 2

Introduction

You might be wondering, why would you want to use Azure Private DNS Zones as a sub-domain of your local DNS zones in the first place and I would not object. But during migrations and transformation processes, you don’t always know what will come up.
If its possible for you to use your local DNS zones for automation processes, great, you should not hesitate to use them 😉
However, there are certain scenarios in which you for instance shift workloads to the cloud and the simple management of DNS records is not that easy. There might be ITSM approval processes in place or the service is bought and managed by a provider whom does not let you manage records, what ever the case might be.

Goal

What do we want to achieve?
Simple: you have a local domain - myDomain.com - and you want to use a sub-domain - cloud.myDomain.com - for automation purposes in Azure.

Architecture

There are a few approaches you can take, but the simplest and most elegant is the following:

  • DNS Delegation on your local DNS server for the sub-domain
  • The Azure Private DNS Zone for the sub-domain
  • A CoreDNS Instance running the Azure plugin

Setup

Local DNS Zone

It doesn’t really matter what DNS solution you use, as long as you can set up a DNS delegation. For this demo, I used a Microsoft DNS Server.

DNS Zone myDomain.comDNS Zone myDomain.com

AKS Cluster

CoreDNS will be deployed to an AKS cluster, this one can be deployed using the following az cli commands:

1
2
3
4
5
6
7
8
# create service principal
az ad sp create-for-rbac --skip-assignment --name aksSp

# assign owner permission to subscription
az role assignment create --role "Owner" --assignee-object-id '<sp id>' --scope /subscriptions/<subscriptionId> --assignee-principal-type ServicePrincipal

# create private aks cluster
az aks create --name '<cluster name>' --resource-group '<aks RG>' --node-count 2 --max-pods 110 --kubernetes-version '1.16.7' --enable-vmss --enable-cluster-autoscaler --min-count 2 --max-count 3 --service-principal '<sp>' --client-secret '<secret>' --location westeurope --network-plugin 'kubenet' --node-vm-size 'Standard_D3_v2' --nodepool-name 'default' --pod-cidr '172.40.0.0/20' --vnet-subnet-id $sharedVnet.Subnets.id --node-osdisk-size 100 --service-cidr '172.41.0.0/16' --dns-service-ip '172.41.0.10'

You can deploy an AKS cluster with a public or private facing master API. The example above deploys a public cluster, if you want to deploy it with a private endpoint, add the following parameter:

1
--enable-private-cluster

Do not assign owner permission for subscriptions that are used in production!

Azure Private DNS Zone

The following code lets you create the Azure Private DNS zone and link it to the AKS cluster VNET.

1
2
3
4
5
6
Install-Module -Name Az.PrivateDns -Force
$privDnsZone = New-AzPrivateDnsZone -Name "cloud.myDomain.com" -ResourceGroupName "<resource group name for private dns zone>"

$vnet = Get-AzVirtualNetwork -ResourceGroupName '<aks RG>' -Name '<name of vnet>'

$link = New-AzPrivateDnsVirtualNetworkLink -ZoneName $privDnsZone.name -ResourceGroupName $privDnsZone.ResourceGroupName -Name "<name of link>" -VirtualNetworkId $vnet.id

Azure Private DNS Zone cloud.myDomain.comAzure Private DNS Zone cloud.myDomain.com

CoreDNS on AKS

Now its time to deploy CoreDNS on the AKS cluster. To do this, you can use the deployment down below.

The .yaml file represents the configuration of CoreDNS - it consists of three Kubernetes objects:

  • Service - used to expose the CoreDNS application with an Azure Load Balancer
  • Config Map - the configuration of Core DNS
  • Deployment - deployment of CoreDNS Pods

The .yaml file creates a config map which us used by CoreDNS to connect to Azure with the applied credentials for the specified DNS zone.
You can get more information about the Azure plugin for CoreDNS here.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Config Map:

cloud.mydomain.com {
log
errors
cache 30

azure <resource group bane>:cloud.mydomain.com {
tenant <tenant id>
client <service principal application id>
subscription <subscription id>
secret <service principal secret>
access private
}
}

In addition to the Azure plugin, we use the log, errors and cache plugins as well. This comes in handy for debugging and troubleshooting.

You might want to change the values of the deployment down below. You can use the same service principal for testing, but for production, you should limit the access to the DNS zone only.

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
71
72
73
---
apiVersion: v1
kind: Service
metadata:
name: dnslb
annotations:
service.beta.kubernetes.io/azure-load-balancer-internal: "true"
spec:
type: LoadBalancer
loadBalancerIP: 10.240.0.100
ports:
- port: 53
protocol: UDP
selector:
app: dnsforwarder
---
apiVersion: v1
kind: ConfigMap
metadata:
name: corednsconf
data:
corefile: |
cloud.mydomain.com {
log
errors
cache 30

azure dctest:cloud.mydomain.com {
tenant <tenant id>
client <service principal application id>
subscription <subscription id>
secret <service principal secret>
access private
}
}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: dnsforwarder
labels:
app: dnsforwarder
spec:
replicas: 1
selector:
matchLabels:
app: dnsforwarder
template:
metadata:
labels:
app: dnsforwarder
spec:
containers:
- name: coredns
image: coredns/coredns:1.6.9
command: ["/coredns"]
args: ["-conf", "/root/corefile"]
resources:
limits:
memory: 170Mi
cpu: "100m"
requests:
memory: 100Mi
cpu: "70m"
volumeMounts:
- name: corefile
mountPath: /root/
ports:
- containerPort: 53
volumes:
- name: corefile
configMap:
name: corednsconf

The domain name must be all lower case in the config map! Otherwise the resolution will not work.

Connect to the AKS cluster:

1
2
3
az login
az account set -s <subscriptionId>
az aks get-credentials -n <cluster name> -g <resource group name> --admin

Afterwards, we can use kubectl to manage the cluster:

1
2
kubectl create namespace dns
kubectl apply -f 'C:\temp\coreDNS.yaml' -n dns

You can check the result with:

1
2
3
kubectl get pods -n dns
kubectl get svc -n dns
kubectl get cm -n dns

And it should look like this:

Kubernetes ObjectsKubernetes Objects

DNS Delegation

The last step is to set up the DNS delegation on the local DNS Server:

Add DNS DelegationAdd DNS Delegation

Add name of sub-domainAdd name of sub-domain

Add Server IP (Load Balancer IP)Add Server IP (Load Balancer IP)

Check the created NS recordCheck the created NS record

Testing

When setup is done, we can create a record in the zone:

1
2
3
$RecordSet = New-AzPrivateDnsRecordSet -Name server1 -RecordType A -ResourceGroupName dctest -ZoneName 'cloud.mydomain.com' -Ttl 3600
Add-AzPrivateDnsRecordConfig -RecordSet $RecordSet -Ipv4Address '10.251.10.25'
Set-AzPrivateDnsRecordSet -RecordSet $RecordSet

On the local DNS server, run the following command to check, if the resolution works:

1
Resolve-DnsName -Name 'server1.cloud.mydomain.com'

Check DNS ResolutionCheck DNS Resolution

Check the CoreDNS logs:

1
2
kubectl get pods -n dns
kubectl logs <pod name> -n dns

CoreDNS LogsCoreDNS Logs

Everything looks good 😎

Conclusion

Now you can resolve DNS names managed in a Azure Private DNS Zone from any client in your network, that uses the local DNS server.

I hope you liked the post, you can also checkout my first post about hybrid DNS on Azure here.