Apexドメインに発行された Azure Front Door 証明書の自動更新を行う
はじめに
Apexドメインに発行されたAzure Front Door証明書が180日でドメイン検証が失効し、手動でドメイン検証を行っていませんか。私は行っていました。
SSL証明書の更新漏れを防ぐため、ApexドメインについてもAzure Automationにて更新を行うスクリプトを用意しました。
Apexドメインとは
Apexドメインとは、wwwやmailなどのホスト名(サブドメイン)を含まない、ドメイン名そのもののことを指します。

実は、Apexドメインのみ、Azure Front Doorによるドメインの再検証は自動で行われません。そのため、証明書の有効期限が切れる前に手動、またはスクリプトでドメイン所有権を再検証する必要があります。
Microsoftの公式ドキュメントにも、以下のように記載されています。
Azure Front Door マネージド証明書を使用すると、Azure Front Door によって証明書の自動的なローテーション (更新) が試みられます。 そうする前に、Azure Front Door では、DNS CNAME レコードがまだ Azure Front Door エンドポイントを指しているかどうかを確認します。 apex ドメインには Azure Front Door エンドポイントを指す CNAME レコードがないため、ドメインの所有権が再検証されるまで、マネージド証明書の自動ローテーションは失敗します。
ApexドメインでのCNAMEレコードの制約
RFC 1912で規定されているCNAMEレコードの制約により、ApexドメインではCNAMEレコードを用いたAzure Front Doorへの関連付けは行えません。
そのため、AレコードおよびAAAAレコードを使用して接続することになり、前述のAzure Front Doorのドメイン検証仕様も相まって、証明書の自動ローテーションが行われない原因となっています。
自動化スクリプト
180日ごとに手動で更新するのが面倒な方に向けて、Azure Automationで利用できるPowerShellスクリプトを作成しました。コメントを豊富につけていますので、自由に編集・利用してください。
<#
.SYNOPSIS
Azure Front Door apex ドメインの TXT レコード自動更新とドメイン検証スクリプト
.DESCRIPTION
このスクリプトは、Azure Automation を使用して Azure Front Door の apex ドメイン (カスタムドメイン) の SSL 証明書自動更新に必要な TXT レコードの更新とドメイン検証を自動化します。
apex ドメインでは Azure Front Door マネージド証明書の自動更新がサポートされないため、このスクリプトを定期的に実行することで、証明書の有効期限切れを防ぎます。
.PARAMETER ResourceGroupName
Azure Front Door リソースがデプロイされているリソースグループ名
.PARAMETER FrontDoorName
Azure Front Door プロファイル名
.PARAMETER CustomDomainName
Azure Front Door に設定しているカスタムドメイン名 (例: example.com)
.PARAMETER DnsZoneName
Azure DNS ゾーン名 (例: example.com)
#>
param (
[Parameter(Mandatory = $true, HelpMessage = "Resource Group Name where Front Door is deployed")]
[string]$ResourceGroupName,
[Parameter(Mandatory = $true, HelpMessage = "Azure Front Door Profile Name")]
[string]$FrontDoorName,
[Parameter(Mandatory = $true, HelpMessage = "Custom Domain Name (e.g., example-com)")]
[string]$CustomDomainName,
[Parameter(Mandatory = $true, HelpMessage = "Azure DNS Zone Name (e.g., example.com)")]
[string]$DnsZoneName
)
# 1. Azureへの接続 (マネージドIDを使用)
try {
Write-Verbose -Message "Azureに接続しています..."
Connect-AzAccount -Identity
Write-Verbose -Message "Azureへの接続に成功しました。"
}
catch {
Write-Error -Message "Azureの接続に失敗しました。: $_"
throw
}
# 2. Front Door カスタムドメインの検証用TXTレコード情報を取得
try {
Write-Verbose -Message "Front Door カスタムドメインの状態を取得しています..."
$customDomain = Get-AzFrontDoorCdnCustomDomain -ResourceGroupName $ResourceGroupName -ProfileName $FrontDoorName -CustomDomainName $CustomDomainName
Write-Verbose -Message "Front Door カスタムドメインの状態を取得しました。"
}
catch {
Write-Error -Message "Front Door カスタムドメイン情報の取得に失敗しました。: $_"
throw
}
# 3. 既存のTXTレコードを確認
try {
$dnsAuthRecordName = "_dnsauth"
Write-Verbose -Message "既存の TXT レコード '$dnsAuthRecordName' を確認します..."
$oldTxtRecord = Get-AzDnsRecordSet -ResourceGroupName $ResourceGroupName -ZoneName $DnsZoneName -Name $dnsAuthRecordName -RecordType Txt
$oldValidationToken = $oldTxtRecord.Records[0].Value
Write-Verbose -Message "既存の TXT レコード値 '$oldValidationToken' を確認しました。"
}
catch {
Write-Warning -Message "既存の TXT レコードが見つからないか、確認に失敗しました: $_"
# 既存レコードがない場合は処理を続行
$oldValidationToken = $null
}
# 4. Front Door カスタムドメインの検証用トークンを再生成
try {
Write-Verbose -Message "Front Door カスタムドメインの検証トークンを再生成しています..."
$validationRequest = Send-AzFrontDoorCdnCustomDomainValidationTokenRequest -ResourceGroupName $ResourceGroupName -ProfileName $FrontDoorName -CustomDomainName $CustomDomainName
Write-Verbose -Message "Front Door カスタムドメインの検証トークンを再生成しました。"
}
catch {
Write-Error -Message "Front Door カスタムドメインの検証トークン再生成に失敗しました。: $_"
throw
}
# 5. 再生成後のTXTレコード情報を取得
try {
Write-Verbose -Message "再生成後の TXT レコード情報を取得します..."
$refreshedDomain = Get-AzFrontDoorCdnCustomDomain -ResourceGroupName $ResourceGroupName -ProfileName $FrontDoorName -CustomDomainName $CustomDomainName
$newValidationToken = $refreshedDomain.ValidationProperty.ValidationToken
Write-Verbose -Message "新しい TXT レコード値 '$newValidationToken' を取得しました。"
}
catch {
Write-Error -Message "再生成後の TXT レコード情報取得に失敗しました: $_"
throw
}
# 6. 新しいTXTレコードを作成または更新
try {
Write-Verbose -Message "新しい TXT レコードを作成/更新します..."
$recordSet = New-AzDnsRecordSet -Name $dnsAuthRecordName -RecordType TXT -ZoneName $DnsZoneName -ResourceGroupName $ResourceGroupName -Ttl 3600 -Overwrite
$recordSet.Records.Add((New-AzDnsRecordConfig -Value $newValidationToken))
Set-AzDnsRecordSet -RecordSet $recordSet
Write-Verbose -Message "TXT レコードの作成/更新に成功しました。"
}
catch {
Write-Error -Message "TXT レコードの作成/更新に失敗しました: $_"
throw
}
# 7. Front Door カスタムドメインの検証が完了するまで待機
try {
Write-Verbose -Message "Front Door カスタムドメイン '$CustomDomainName' の検証を待機しています..."
$timeout = New-TimeSpan -Minutes 30
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
while ($stopwatch.Elapsed -lt $timeout) {
$domain = Get-AzFrontDoorCdnCustomDomain -ResourceGroupName $ResourceGroupName -ProfileName $FrontDoorName -CustomDomainName $CustomDomainName
if ($domain.DomainValidationState -eq 'Approved') {
Write-Verbose -Message "Front Door カスタムドメインの検証が完了しました。"
break
}
Write-Verbose -Message "検証状態: $($domain.DomainValidationState)... 30秒待機します。"
Start-Sleep -Seconds 30
}
if ($domain.DomainValidationState -ne 'Approved') {
throw "タイムアウト時間内にドメイン検証が完了しませんでした。"
}
}
catch {
Write-Error -Message "Front Door カスタムドメインの検証待機中にエラーが発生しました: $_"
throw
}
Write-Host "スクリプトは正常に完了しました。"
Discussion