From c3e73c72a1df1047c2da4a806392a655b6082ad5 Mon Sep 17 00:00:00 2001 From: Tatsuro Shibamura Date: Wed, 7 Dec 2022 15:02:10 +0900 Subject: [PATCH] Added support for Azure Private DNS (Experimental) (#530) * Added support for Azure Private DNS (Experimental) * Update to GA PrivateDns package --- KeyVault.Acmebot/KeyVault.Acmebot.csproj | 1 + KeyVault.Acmebot/Options/AcmebotOptions.cs | 2 + .../Options/AzurePrivateDnsOptions.cs | 6 ++ .../Providers/AzurePrivateDnsProvider.cs | 81 +++++++++++++++++++ KeyVault.Acmebot/Startup.cs | 1 + 5 files changed, 91 insertions(+) create mode 100644 KeyVault.Acmebot/Options/AzurePrivateDnsOptions.cs create mode 100644 KeyVault.Acmebot/Providers/AzurePrivateDnsProvider.cs diff --git a/KeyVault.Acmebot/KeyVault.Acmebot.csproj b/KeyVault.Acmebot/KeyVault.Acmebot.csproj index 1e22168a..f40ea4b3 100644 --- a/KeyVault.Acmebot/KeyVault.Acmebot.csproj +++ b/KeyVault.Acmebot/KeyVault.Acmebot.csproj @@ -7,6 +7,7 @@ + diff --git a/KeyVault.Acmebot/Options/AcmebotOptions.cs b/KeyVault.Acmebot/Options/AcmebotOptions.cs index 0d817d83..3d5e5dfa 100644 --- a/KeyVault.Acmebot/Options/AcmebotOptions.cs +++ b/KeyVault.Acmebot/Options/AcmebotOptions.cs @@ -32,6 +32,8 @@ public class AcmebotOptions // Properties should be in alphabetical order public AzureDnsOptions AzureDns { get; set; } + public AzurePrivateDnsOptions AzurePrivateDns { get; set; } + public CloudflareOptions Cloudflare { get; set; } public CustomDnsOptions CustomDns { get; set; } diff --git a/KeyVault.Acmebot/Options/AzurePrivateDnsOptions.cs b/KeyVault.Acmebot/Options/AzurePrivateDnsOptions.cs new file mode 100644 index 00000000..1b907f4d --- /dev/null +++ b/KeyVault.Acmebot/Options/AzurePrivateDnsOptions.cs @@ -0,0 +1,6 @@ +namespace KeyVault.Acmebot.Options; + +public class AzurePrivateDnsOptions +{ + public string SubscriptionId { get; set; } +} diff --git a/KeyVault.Acmebot/Providers/AzurePrivateDnsProvider.cs b/KeyVault.Acmebot/Providers/AzurePrivateDnsProvider.cs new file mode 100644 index 00000000..9ab0d472 --- /dev/null +++ b/KeyVault.Acmebot/Providers/AzurePrivateDnsProvider.cs @@ -0,0 +1,81 @@ +using System.Collections.Generic; +using System.Net; +using System.Threading.Tasks; + +using Azure; +using Azure.Core; +using Azure.Identity; +using Azure.ResourceManager; +using Azure.ResourceManager.PrivateDns; +using Azure.ResourceManager.PrivateDns.Models; + +using KeyVault.Acmebot.Internal; +using KeyVault.Acmebot.Options; + +namespace KeyVault.Acmebot.Providers; + +internal class AzurePrivateDnsProvider : IDnsProvider +{ + public AzurePrivateDnsProvider(AzurePrivateDnsOptions options, AzureEnvironment environment) + { + var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions + { + AuthorityHost = environment.ActiveDirectory + }); + + _armClient = new ArmClient(credential, options.SubscriptionId, new ArmClientOptions { Environment = environment.ResourceManager }); + } + + private readonly ArmClient _armClient; + + public int PropagationSeconds => 10; + + public async Task> ListZonesAsync() + { + var zones = new List(); + + var subscription = await _armClient.GetDefaultSubscriptionAsync(); + + var result = subscription.GetPrivateDnsZonesAsync(); + + await foreach (var zone in result) + { + zones.Add(new DnsZone(this) { Id = zone.Id, Name = zone.Data.Name }); + } + + return zones; + } + + public Task CreateTxtRecordAsync(DnsZone zone, string relativeRecordName, IEnumerable values) + { + // TXT レコードに値をセットする + var txtRecordData = new PrivateDnsTxtRecordData(); + + foreach (var value in values) + { + txtRecordData.PrivateDnsTxtRecords.Add(new PrivateDnsTxtRecordInfo { Values = { value } }); + } + + var dnsZoneResource = _armClient.GetPrivateDnsZoneResource(new ResourceIdentifier(zone.Id)); + + var dnsTxtRecords = dnsZoneResource.GetPrivateDnsTxtRecords(); + + return dnsTxtRecords.CreateOrUpdateAsync(WaitUntil.Completed, relativeRecordName, txtRecordData); + } + + public async Task DeleteTxtRecordAsync(DnsZone zone, string relativeRecordName) + { + var dnsZoneResource = _armClient.GetPrivateDnsZoneResource(new ResourceIdentifier(zone.Id)); + + try + { + PrivateDnsTxtRecordResource dnsTxtRecordResource = await dnsZoneResource.GetPrivateDnsTxtRecordAsync(relativeRecordName); + + await dnsTxtRecordResource.DeleteAsync(WaitUntil.Completed); + } + catch (RequestFailedException ex) when (ex.Status == (int)HttpStatusCode.NotFound) + { + // ignored + } + } +} diff --git a/KeyVault.Acmebot/Startup.cs b/KeyVault.Acmebot/Startup.cs index 04301ca6..5c5a3efa 100644 --- a/KeyVault.Acmebot/Startup.cs +++ b/KeyVault.Acmebot/Startup.cs @@ -79,6 +79,7 @@ public override void Configure(IFunctionsHostBuilder builder) var dnsProviders = new List(); dnsProviders.TryAdd(options.AzureDns, o => new AzureDnsProvider(o, environment)); + dnsProviders.TryAdd(options.AzurePrivateDns, o => new AzurePrivateDnsProvider(o, environment)); dnsProviders.TryAdd(options.Cloudflare, o => new CloudflareProvider(o)); dnsProviders.TryAdd(options.CustomDns, o => new CustomDnsProvider(o)); dnsProviders.TryAdd(options.DnsMadeEasy, o => new DnsMadeEasyProvider(o));