From c58d25eb90df30171b3aae64927b69a3f6229a63 Mon Sep 17 00:00:00 2001 From: Reto Vogel Date: Sat, 19 Sep 2026 15:44:32 +0200 Subject: [PATCH] Add support for Private DNS zones on Azure (#7227) * Enhance Azure DNS script for private zones support Added support for Azure Private DNS Zones and updated API versions accordingly. * Update README.md * Update Bearer Token description in dns_azure.sh Clarified the usage of the Bearer Token in the script. * Update dns_azure.sh * Update dns_azure.sh * Update README.md * implement optimization based on input from maintainer * Update dns_azure.sh * create reusable function * optimize function usage and make less verbose --------- Co-authored-by: neil Co-authored-by: Mashiro Co-authored-by: MBWhitestone <25477219+MBWhitestone@users.noreply.github.com> Co-authored-by: Pablo Co-authored-by: Claude Sonnet 5 --- dnsapi/dns_azure.sh | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_azure.sh b/dnsapi/dns_azure.sh index 4708e151..0ec2a2b9 100644 --- a/dnsapi/dns_azure.sh +++ b/dnsapi/dns_azure.sh @@ -10,6 +10,7 @@ Options: AZUREDNS_CLIENTSECRET Client Secret. Secret from creating the service principal AZUREDNS_MANAGEDIDENTITY Use Managed Identity. Use Managed Identity assigned to a resource instead of a service principal. "true"/"false" AZUREDNS_BEARERTOKEN Bearer Token. Used instead of service principal credentials or managed identity. Not saved, provide it on every run. Optional. + AZUREDNS_PRIVATEZONE Use Azure Private DNS Zones instead of Public DNS Zones. "true"/"false" ' wiki=https://github.com/acmesh-official/acme.sh/wiki/How-to-use-Azure-DNS @@ -39,6 +40,12 @@ dns_azure_add() { #save subscription id to account conf file. _saveaccountconf_mutable AZUREDNS_SUBSCRIPTIONID "$AZUREDNS_SUBSCRIPTIONID" + AZUREDNS_PRIVATEZONE="${AZUREDNS_PRIVATEZONE:-$(_readaccountconf_mutable AZUREDNS_PRIVATEZONE)}" + if [ -n "$AZUREDNS_PRIVATEZONE" ]; then + #save public/private dns to account conf file. + _saveaccountconf_mutable AZUREDNS_PRIVATEZONE "$AZUREDNS_PRIVATEZONE" + fi + AZUREDNS_MANAGEDIDENTITY="${AZUREDNS_MANAGEDIDENTITY:-$(_readaccountconf_mutable AZUREDNS_MANAGEDIDENTITY)}" if [ "$AZUREDNS_MANAGEDIDENTITY" = true ]; then _info "Using Azure managed identity" @@ -112,7 +119,9 @@ dns_azure_add() { _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" - acmeRecordURI="https://management.azure.com$(printf '%s' "$_domain_id" | sed 's/\\//g')/TXT/$_sub_domain?api-version=2017-09-01" + _azure_set_zone_vars + + acmeRecordURI="https://management.azure.com$(printf '%s' "$_domain_id" | sed 's/\\//g')/TXT/$_sub_domain?api-version=$_azure_api_version" _debug "$acmeRecordURI" # Get existing TXT record _azure_rest GET "$acmeRecordURI" "" "$accesstoken" @@ -138,7 +147,7 @@ dns_azure_add() { fi fi # Add the txtvalue TXT Record - body="{\"properties\":{\"metadata\":{\"acmetscheck\":\"$timestamp\"},\"TTL\":10, \"TXTRecords\":[$values]}}" + body="{\"properties\":{\"metadata\":{\"acmetscheck\":\"$timestamp\"},\"$_azure_ttl_key\":10, \"$_azure_txt_key\":[$values]}}" _azure_rest PUT "$acmeRecordURI" "$body" "$accesstoken" if [ "$_code" = "200" ] || [ "$_code" = '201' ]; then _info "validation value added" @@ -169,6 +178,8 @@ dns_azure_rm() { return 1 fi + AZUREDNS_PRIVATEZONE="${AZUREDNS_PRIVATEZONE:-$(_readaccountconf_mutable AZUREDNS_PRIVATEZONE)}" + AZUREDNS_MANAGEDIDENTITY="${AZUREDNS_MANAGEDIDENTITY:-$(_readaccountconf_mutable AZUREDNS_MANAGEDIDENTITY)}" if [ "$AZUREDNS_MANAGEDIDENTITY" = true ]; then _info "Using Azure managed identity" @@ -227,8 +238,11 @@ dns_azure_rm() { _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" - acmeRecordURI="https://management.azure.com$(printf '%s' "$_domain_id" | sed 's/\\//g')/TXT/$_sub_domain?api-version=2017-09-01" + _azure_set_zone_vars + + acmeRecordURI="https://management.azure.com$(printf '%s' "$_domain_id" | sed 's/\\//g')/TXT/$_sub_domain?api-version=$_azure_api_version" _debug "$acmeRecordURI" + # Get existing TXT record _azure_rest GET "$acmeRecordURI" "" "$accesstoken" timestamp="$(_time)" @@ -252,7 +266,7 @@ dns_azure_rm() { fi else # Remove only txtvalue from the TXT Record - body="{\"properties\":{\"metadata\":{\"acmetscheck\":\"$timestamp\"},\"TTL\":10, \"TXTRecords\":[$values]}}" + body="{\"properties\":{\"metadata\":{\"acmetscheck\":\"$timestamp\"},\"$_azure_ttl_key\":10, \"$_azure_txt_key\":[$values]}}" _azure_rest PUT "$acmeRecordURI" "$body" "$accesstoken" if [ "$_code" = "200" ] || [ "$_code" = '201' ]; then _info "validation value removed" @@ -383,6 +397,21 @@ _azure_getaccess_token() { return 0 } +_azure_set_zone_vars() { + if [ "$AZUREDNS_PRIVATEZONE" = "true" ]; then + _azure_zone_type="privateDnsZones" + _azure_api_version="2024-06-01" + _azure_ttl_key="ttl" + _azure_txt_key="txtRecords" + _debug "Querying private DNS zone" + else + _azure_zone_type="dnszones" + _azure_api_version="2017-09-01" + _azure_ttl_key="TTL" + _azure_txt_key="TXTRecords" + fi +} + _get_root() { domain=$1 subscriptionId=$2 @@ -390,6 +419,8 @@ _get_root() { i=1 p=1 + _azure_set_zone_vars + ## Ref: https://learn.microsoft.com/en-us/rest/api/dns/zones/list?view=rest-dns-2018-05-01&tabs=HTTP ## returns up to 100 zones in one response. Handling more results is not implemented ## (ZoneListResult with continuation token for the next page of results) @@ -398,7 +429,7 @@ _get_root() { ## https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits#azure-dns-limits ## The new limit is 250 Public DNS zones per subscription, while the old limit was only 100 ## - _azure_rest GET "https://management.azure.com/subscriptions/$subscriptionId/providers/Microsoft.Network/dnszones?\$top=500&api-version=2017-09-01" "" "$accesstoken" + _azure_rest GET "https://management.azure.com/subscriptions/$subscriptionId/providers/Microsoft.Network/$_azure_zone_type?\$top=500&api-version=$_azure_api_version" "" "$accesstoken" # Find matching domain name in Json response while true; do h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)