Author : MD TAREQ HASSAN | Updated : 2021/06/24

Domain and DNS Zone

Create App Service Domain

Azure DNS zone:

Alias Record For Public IP Of Application Gateway

Using Azure cli command: Creating Alias Record In Azure DNS Zone

Using Azure Portal

Alias record set in Azure DNS Zone for Public IP of AKS AGIC Application Gateway

Multiple APIs Under Same Domain

Assign domain to AGIC Application Gateway: see previous step

Create deployment and ingress

Deployment and ingress manifest yaml files: Sample - Serving Multiple APIs Under Same Domain

Multiple MVC Apps Under Same Domain

Applications Under Same Domain As Sub-Applications

Relative URLs for MVC Applications

See: Samples - serving multiple MVC applications under same domain

Automate DNS Records With ExternalDNS

cert-manager ACME DNS01

How does ExternalDNS work

ExternalDNS Overview

Prerequisites for ExternalDNS

Login to Azure (PowerShell is being used)

<pre class="highlight"><code><span class="c">#</span><span class="w"> </span><span class="c"># Login to Azure</span><span class="w"> </span><span class="c">#</span><span class="w"> </span><span class="nv">$</span><span class="nn">Env</span><span class="p">:</span><span class="nv">AZ_USERNAME</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"email-here"</span><span class="w"> </span><span class="nv">$</span><span class="nn">Env</span><span class="p">:</span><span class="nv">AZ_PASSWORD</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"pass-here"</span><span class="w">

</span>az login -u $AZ_USERNAME -p $AZ_PASSWORD </code></pre>

Get AKS Credential (PowerShell is being used)

#
# Get AKS cluster credential
#
$Env:RESOURCE_GROUP = "my-poc-rg"
$Env:AKS_CLUSTER_NAME = "my-poc-aks"

az aks get-credentials --resource-group=$RESOURCE_GROUP --name=$AKS_CLUSTER_NAME --overwrite-existing

# Or
az login --use-device-code

Check that Managed Identity is enabled for AKS (if not enabled, then enable it)

#
# Checking that managed identity is enabled for AKS
#
# "clientId": "msi" => indicates that managed identity is enabled
# https://docs.microsoft.com/en-us/azure/aks/use-managed-identity#obtain-and-use-the-system-assigned-managed-identity-for-your-aks-cluster
#
az aks show -g my-poc-rg -n my-poc-aks --query "servicePrincipalProfile"

# To get control plane system-assigned identity's object ID:
# az aks show -g my-poc-rg -n my-poc-aks --query "identity"

#
# If managed identity is not enabled, then enable it
#
# az aks update -g <RGName> -n <AKSName> --enable-managed-identity
#
az aks update -g my-poc-rg -n my-poc-aks --enable-managed-identity

Grant permission (for AKS managed identity) to Azure DNS (PowerShell is being used)

$RESOURCE_GROUP = "my-poc-rg"
$AKS_CLUSTER_NAME = "my-poc-aks"

$DNS_ZONE_DOMAIN = "mypoc.com"
# To check your Azure DNS Zone: az network dns zone list --query "[?name=='$AZ_DNS_DOMAIN']"

#
# Get Scope (will be used to grant permission to Azure DNS)
#
# Format: /subscriptions/<subscription id>/resourceGroups/<resource group name>/providers/Microsoft.Network/dnszones/<zone name>/
#
$DNS_ZONE_SCOPE=$(az network dns zone list --query "[?name=='$DNS_ZONE_DOMAIN'].id" --output tsv)
#echo $DNS_ZONE_SCOPE

#
# Get principalId (objectId) of AKS managed identity
#
$MANAGED_IDENTITY_PRINCIPAL_ID = $(az aks show -g $RESOURCE_GROUP -n $AKS_CLUSTER_NAME --query "identityProfile.kubeletidentity.objectId" --output tsv)
echo $MANAGED_IDENTITY_PRINCIPAL_ID


#
# Assign contributor role to AKS managed identity
#
az role assignment create --assignee "$MANAGED_IDENTITY_PRINCIPAL_ID" --role "DNS Zone Contributor" --scope "$DNS_ZONE_SCOPE"

Create Kubernetes Secret For ExternalDNS

Using PowerShell

#
# Run PowerShell ISE as Admin (otherwise, PowerShell ISE would not be able to create azure.json file)
# Make sure that you are logged in to azure using 'az login'
#

#
# Set required variables
#
$AzureJsonFileLocation = "C:\azure.json"
$ResourceGroupName = "my-poc-rg"

#
# Get tenantId and subscriptionId
#
$TenantId = $(az account show --query "tenantId" --output tsv)
$SubscriptionId = $(az account show --query "id" --output tsv)

#
# JSON representation
#
$jsonRepresentation = @"
{
  "tenantId": "$TenantId",
  "subscriptionId" : "$SubscriptionId",
  "resourceGroup" : "$ResourceGroupName",
  "useManagedIdentityExtension" : true
}
"@

#
# Create azure.json file at specified location ($AzureJsonFileLocation)
#
$jsonRepresentation | Out-File $AzureJsonFileLocation
# For complex object to json => $jsonRepresentation | ConvertTo-Json -depth 100 | Out-File "C:\azure.json"


#
# Now create kubenetes secret base on azure.json
# This secret will be used by ExternalDNS to create DNS records for K8s ingresses in Azure DNS Zones
# Make sure: AKS managed indentity has been granted permission to Azure DNS Zone
#
kubectl create secret generic azure-config-file --from-file=$AzureJsonFileLocation

Using commands

#
# Gather information for `azure.json` file (K8s secret will be created using `azure.json`)
#

# 
# Azure Tenant ID
#
az account show --query "tenantId"

#
# Azure Subscription ID
#
az account show --query "id"

#
# Create `azure.json` file for K8s Secret** (this secret will be used by ExternalDNS to modify Azure DNS Zone records)
# 
# {
#  "tenantId": "01234abc-xyz-abc-abc-xyz",
#  "subscriptionId": "01234abc-xyz-abc-abc-xyz",
#  "resourceGroup": "my-poc-rg",
#  "useManagedIdentityExtension": true
# }
#

# 
# Create K8s secret using azure.json
# 
kubectl create secret generic azure-config-file --from-file=/local/path/to/azure.json

Deploy ExternalDNS

external-dns.yaml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: external-dns
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: external-dns
rules:
- apiGroups: [""]
  resources: ["services","endpoints","pods"]
  verbs: ["get","watch","list"]
- apiGroups: ["extensions","networking.k8s.io"]
  resources: ["ingresses"] 
  verbs: ["get","watch","list"]
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["list"]
---
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
    spec:
      serviceAccountName: external-dns
      containers:
      - name: external-dns
        image: k8s.gcr.io/external-dns/external-dns:v0.8.0
        args:
        - --source=service
        - --source=ingress
        #- --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above.
        - --provider=azure
        #- --azure-resource-group=externaldns # (optional) use the DNS zones from the specific resource group
        volumeMounts:
        - name: azure-config-file
          mountPath: /etc/kubernetes
          readOnly: true
      volumes:
      - name: azure-config-file
        secret:
          secretName: azure-config-file

Testing ExternalDNS With A Simple Ingress

Deploy sample ingresses: Foo and Bar ingresses for testing ExternalDNS

Verify that DNS record for ingress is created

az network dns record-set a list -g my-poc-rg -z mypoc.com

Next