This guide will walk you through writing a script that will search an Azure Subscription for Front Door Custom Domains that are secured using Azure Managed TLS Certificates, and renew any custom domain validation tokens that are due to expire.
Pre-reqs
- You will need to be using a terminal with
bash
orzsh
- You must have the Azure CLI and
jq
installed - Your user account will need to have the following Azure Roles:
CDN Profile Contributor
Get logged in
First thing you need to do is get your account logged into Azure CLI.
az login
This will open a web browser and ask you to sign-in to your Azure account. Once you’re signed-in follow the instructions to select the Azure Subscription that contains the Front Door profiles that you want to work on.
Locate your Front Door profiles
The below CLI command will query your Azure Subscription for Front Door resources and return a bunch of information about them:
az afd profile list
A lot of the data returned to you in the JSON response is fairly unnecessary. We can simplify the output to just the bits of information we need by piping the JSON into jq
.
az afd profile list |
jq -rc '.[] | { "name": .name, "resourceGroup": .resourceGroup }'
The output will now just be the name of the resources and their associated resource groups.
Now that we have a list of data we can iterate through it makes sense to store this in a bash variable.
The final command looks like this:
AFD_LIST=$(
az afd profile list |
jq -rc '.[] | { "name": .name, "resourceGroup": .resourceGroup }'
)
Check the validation status
Now we want to check each Front Door for any attached ‘Custom Domains’. If there are domains, we want to check their domain validation status to see if they are pending revalidation.
Start by opening a for
loop in bash so we can iterate over the $AFD_LIST
variable:
for AZURE_FRONT_DOOR in $AFD_LIST; do
# ...
Within the for
loop we want to extract the name and resource group of the Front Door into bash variables:
RESOURCE_GROUP=$(echo "$AZURE_FRONT_DOOR" | jq -rc '.resourceGroup')
AFD_NAME=$(echo "$AZURE_FRONT_DOOR" | jq -rc '.name')
Next we want to query each Front Door for attached custom domains, and set that as a variable so we can interrogate it later:
# Grab all the custom domains attached to the Azure Front Door
ALL_CUSTOM_DOMAINS=$(
az afd custom-domain list \
--profile-name "$AFD_NAME" \
--output json \
--resource-group "$RESOURCE_GROUP"
)
Now, it’s possible that not every domain attached to the Front Door is using the Azure Managed TLS Certificates so we will need to query the domains and filter out any that are using customer-managed certificates. The below script passes the variable we defined in the previous step $ALL_CUSTOM_DOMAINS
to jq
which performs the filter for us. Finally, we build a nice JSON object with some basic properties that we can re-use in further steps:
# Create a new list of domains where TLS certificate type is Azure 'managed'
DOMAINS=$(
echo "$ALL_CUSTOM_DOMAINS" |
jq -rc '.[] | select(.tlsSettings.certificateType = "ManagedCertificate") | {
"domain": .hostName,
"id": .id,
"validationProperties": .validationProperties,
"state": .domainValidationState,
"azureDnsZone": .azureDnsZone
}'
)
After the filtering, it may be that there are no domains left for us to process. We can check this by adding a safety check into our script.
if [ -z "$DOMAINS" ]; then
echo " ✅ No domains were found that need revalidating"
else
# ...
In the else
part of the condition is where we will process the remaining domains to determine their status. We can extract the properties from the JSON object we defined earlier and assign them to bash variables whilst we iterate.
for DOMAIN in $(echo "$DOMAINS" | jq -c); do
DOMAIN_NAME=$(echo "$DOMAIN" | jq -rc '.domain')
RESOURCE_ID=$(echo "$DOMAIN" | jq -rc '.id')
STATE=$(echo "$DOMAIN" | jq -rc '.state')
DOMAIN_VALIDATION_EXPIRY=$(echo "$DOMAIN" | jq -rc '.validationProperties.expirationDate')
DOMAIN_TOKEN=$(echo "$DOMAIN" | jq -rc '.validationProperties.validationToken')
DOMAIN_DNS_ZONE_ID=$(echo "$DOMAIN" | jq -rc '.azureDnsZone.id')
# ...
The next thing to check is the status of the domain name. The $STATE
variable will be "Pending"
if it’s a newly added domain that has yet to be validated, or "PendingRevalidation"
if the domain was previously validated, but is due for revalidation. Let’s add that into the script.
if [ "$STATE" == "Pending" ] || [ "$STATE" == "PendingRevalidation" ]; then
# ...
If the domain is either one of these state, we ought to regenerate the validation token. We can also do that programatically too.
az afd custom-domain regenerate-validation-token \
--ids "$RESOURCE_ID" \
--output json
This is an asynchronous task, so the token will not be provided to us straight away. It’s best to re-query the Front Door profile to get the latest token from Azure.
NEW_TOKEN=$(
az afd custom-domain show \
--ids "$RESOURCE_ID" \
--output json \
--only-show-errors | jq -rc '.validationProperties.validationToken'
)
Now that we have the new token, we can simply print the associated domain name, with it’s new token to the screen.
echo "$DOMAIN_NAME: $NEW_TOKEN"
Now we just need to close out the bash loops and conditions.
fi
done
fi
# linefeed for optics
echo
done
Finishing up
Now that you have a list of domain names and their associated tokens, you will need to update the domain validation TXT DNS Record for your domain name with the value of the token.
Typically this will be in the following format
Type: TXT
Value: <Your token here>
Name: _dnsauth.
You can either make this change yourself, or ask your hosting supplier to do it for you. Either way, once this validation token has been updated in DNS, Azure Front Door will typically pick it up within 24 hours and provision you a new TLS Certificate!
Final words
If you also happen to have your DNS Zones for the domains in Azure, you should take a look at the GitHub Repo I put together for Department for Education which allows you to launch a scheduled task using Container Instances which will run this entire script programatically, as well as update the DNS records for you too!