Skip to content

Commit

Permalink
Refactoring DNS Providers (#618)
Browse files Browse the repository at this point in the history
* Refactoring DNS Providers

* Adding DNS Provider Name property

* Improvement code for .NET 6

* Improve multiple DNS provider
  • Loading branch information
shibayan authored Aug 9, 2023
1 parent 1c11c9e commit 7ab75d7
Show file tree
Hide file tree
Showing 15 changed files with 57 additions and 74 deletions.
10 changes: 5 additions & 5 deletions KeyVault.Acmebot/Functions/SharedActivity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public async Task<IReadOnlyList<string>> GetZones([ActivityTrigger] object input
{
var zones = await _dnsProviders.ListAllZonesAsync();

return zones.Select(x => x.Name).ToArray();
return zones.OrderBy(x => x.DnsProvider.Name).Select(x => x.Name).ToArray();
}
catch
{
Expand Down Expand Up @@ -252,11 +252,11 @@ public async Task Dns01Precondition([ActivityTrigger] IReadOnlyList<string> dnsN
// Challenge の詳細から DNS 向けにレコード名を作成
var acmeDnsRecordName = dnsRecordName.Replace($".{zone.Name}", "", StringComparison.OrdinalIgnoreCase);

await zone.Provider.DeleteTxtRecordAsync(zone, acmeDnsRecordName);
await zone.Provider.CreateTxtRecordAsync(zone, acmeDnsRecordName, lookup.Select(x => x.DnsRecordValue));
await zone.DnsProvider.DeleteTxtRecordAsync(zone, acmeDnsRecordName);
await zone.DnsProvider.CreateTxtRecordAsync(zone, acmeDnsRecordName, lookup.Select(x => x.DnsRecordValue));

// 一番時間のかかる DNS Provider に合わせる
propagationSeconds = Math.Max(propagationSeconds, zone.Provider.PropagationSeconds);
propagationSeconds = Math.Max(propagationSeconds, zone.DnsProvider.PropagationSeconds);
}

return (challengeResults, propagationSeconds);
Expand Down Expand Up @@ -446,7 +446,7 @@ public async Task CleanupDnsChallenge([ActivityTrigger] IReadOnlyList<AcmeChalle
// Challenge の詳細から DNS 向けにレコード名を作成
var acmeDnsRecordName = dnsRecordName.Replace($".{zone.Name}", "", StringComparison.OrdinalIgnoreCase);

await zone.Provider.DeleteTxtRecordAsync(zone, acmeDnsRecordName);
await zone.DnsProvider.DeleteTxtRecordAsync(zone, acmeDnsRecordName);
}
}

Expand Down
5 changes: 1 addition & 4 deletions KeyVault.Acmebot/Internal/CertificateExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,7 @@ public static CertificateItem ToCertificateItem(this KeyVaultCertificateWithPoli

private static string ToHexString(byte[] bytes)
{
if (bytes is null)
{
throw new ArgumentNullException(nameof(bytes));
}
ArgumentNullException.ThrowIfNull(bytes);

var result = new StringBuilder();

Expand Down
4 changes: 2 additions & 2 deletions KeyVault.Acmebot/KeyVault.Acmebot.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AWSSDK.Route53" Version="3.7.200.6" />
<PackageReference Include="AWSSDK.Route53" Version="3.7.201.6" />
<PackageReference Include="Azure.Identity" Version="1.9.0" />
<PackageReference Include="Azure.ResourceManager.Dns" Version="1.0.1" />
<PackageReference Include="Azure.ResourceManager.PrivateDns" Version="1.0.1" />
<PackageReference Include="Azure.Security.KeyVault.Certificates" Version="4.5.1" />
<PackageReference Include="Azure.Security.KeyVault.Keys" Version="4.5.0" />
<PackageReference Include="DnsClient" Version="1.7.0" />
<PackageReference Include="DurableTask.TypedProxy" Version="2.2.2" />
<PackageReference Include="Google.Apis.Dns.v1" Version="1.61.0.3123" />
<PackageReference Include="Google.Apis.Dns.v1" Version="1.61.0.3134" />
<PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.1.0" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.DurableTask" Version="2.10.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="[6.0.*,7.0.0)" />
Expand Down
2 changes: 2 additions & 0 deletions KeyVault.Acmebot/Providers/AzureDnsProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public AzureDnsProvider(AzureDnsOptions options, AzureEnvironment environment, T

private readonly ArmClient _armClient;

public string Name => "Azure DNS";

public int PropagationSeconds => 10;

public async Task<IReadOnlyList<DnsZone>> ListZonesAsync()
Expand Down
2 changes: 2 additions & 0 deletions KeyVault.Acmebot/Providers/AzurePrivateDnsProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public AzurePrivateDnsProvider(AzurePrivateDnsOptions options, AzureEnvironment

private readonly ArmClient _armClient;

public string Name => "Azure Private DNS";

public int PropagationSeconds => 10;

public async Task<IReadOnlyList<DnsZone>> ListZonesAsync()
Expand Down
12 changes: 7 additions & 5 deletions KeyVault.Acmebot/Providers/CloudflareProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public CloudflareProvider(CloudflareOptions options)

private readonly CloudflareDnsClient _cloudflareDnsClient;

public string Name => "Cloudflare";

public int PropagationSeconds => 10;

public async Task<IReadOnlyList<DnsZone>> ListZonesAsync()
Expand Down Expand Up @@ -61,7 +63,7 @@ public CloudflareDnsClient(string apiToken)
{
_httpClient = new HttpClient
{
BaseAddress = new Uri("https://api.cloudflare.com")
BaseAddress = new Uri("https://api.cloudflare.com/client/v4/")
};

_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
Expand Down Expand Up @@ -90,7 +92,7 @@ public async Task<IReadOnlyList<ZoneResult>> ListAllZonesAsync()

public async Task<IReadOnlyList<DnsRecordResult>> GetDnsRecordsAsync(string zone, string name)
{
var response = await _httpClient.GetAsync($"/client/v4/zones/{zone}/dns_records?type=TXT&name={name}&per_page=100");
var response = await _httpClient.GetAsync($"zones/{zone}/dns_records?type=TXT&name={name}&per_page=100");

response.EnsureSuccessStatusCode();

Expand All @@ -101,21 +103,21 @@ public async Task<IReadOnlyList<DnsRecordResult>> GetDnsRecordsAsync(string zone

public async Task CreateDnsRecordAsync(string zone, string name, string content)
{
var response = await _httpClient.PostAsync($"/client/v4/zones/{zone}/dns_records", new { type = "TXT", name, content, ttl = 60 });
var response = await _httpClient.PostAsync($"zones/{zone}/dns_records", new { type = "TXT", name, content, ttl = 60 });

response.EnsureSuccessStatusCode();
}

public async Task DeleteDnsRecordAsync(string zone, string id)
{
var response = await _httpClient.DeleteAsync($"/client/v4/zones/{zone}/dns_records/{id}");
var response = await _httpClient.DeleteAsync($"zones/{zone}/dns_records/{id}");

response.EnsureSuccessStatusCode();
}

private async Task<ApiResult<ZoneResult>> ListZonesAsync(int page)
{
var response = await _httpClient.GetAsync($"/client/v4/zones?page={page}&per_page=50&status=active");
var response = await _httpClient.GetAsync($"zones?page={page}&per_page=50&status=active");

response.EnsureSuccessStatusCode();

Expand Down
4 changes: 3 additions & 1 deletion KeyVault.Acmebot/Providers/CustomDnsProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ public CustomDnsProvider(CustomDnsOptions options)

private readonly HttpClient _httpClient;

public string Name => "Custom DNS";

public int PropagationSeconds { get; }

public async Task<IReadOnlyList<DnsZone>> ListZonesAsync()
Expand Down Expand Up @@ -60,7 +62,7 @@ public async Task DeleteTxtRecordAsync(DnsZone zone, string relativeRecordName)
response.EnsureSuccessStatusCode();
}

public class Zone
private class Zone
{
[JsonProperty("id")]
public string Id { get; set; }
Expand Down
31 changes: 11 additions & 20 deletions KeyVault.Acmebot/Providers/DnsMadeEasyProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public DnsMadeEasyProvider(DnsMadeEasyOptions options)

private readonly DnsMadeEasyClient _client;

public string Name => "DNS Made Easy";

public int PropagationSeconds => 10;

public async Task<IReadOnlyList<DnsZone>> ListZonesAsync()
Expand Down Expand Up @@ -52,7 +54,7 @@ public async Task DeleteTxtRecordAsync(DnsZone zone, string relativeRecordName)
{
var records = await _client.ListRecordsAsync(zone.Id);

var recordsToDelete = records.Where(r => r.Name == relativeRecordName && r.Type == "TXT");
var recordsToDelete = records.Where(x => x.Name == relativeRecordName && x.Type == "TXT");

foreach (var record in recordsToDelete)
{
Expand All @@ -66,7 +68,7 @@ public DnsMadeEasyClient(string apiKey, string secretKey)
{
_httpClient = new HttpClient(new ApiKeyHandler(apiKey, secretKey, new HttpClientHandler()))
{
BaseAddress = new Uri("https://api.dnsmadeeasy.com/V2.0/")
BaseAddress = new Uri("https://api.dnsmadeeasy.com/V2.0/dns/")
};

_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
Expand All @@ -76,7 +78,7 @@ public DnsMadeEasyClient(string apiKey, string secretKey)

public async Task<IReadOnlyList<Domain>> ListZonesAsync()
{
var response = await _httpClient.GetAsync("dns/managed");
var response = await _httpClient.GetAsync("managed");

response.EnsureSuccessStatusCode();

Expand All @@ -87,7 +89,7 @@ public async Task<IReadOnlyList<Domain>> ListZonesAsync()

public async Task<IReadOnlyList<DnsEntry>> ListRecordsAsync(string zoneId)
{
var response = await _httpClient.GetAsync($"dns/managed/{zoneId}/records");
var response = await _httpClient.GetAsync($"managed/{zoneId}/records");

response.EnsureSuccessStatusCode();

Expand All @@ -98,14 +100,14 @@ public async Task<IReadOnlyList<DnsEntry>> ListRecordsAsync(string zoneId)

public async Task DeleteRecordAsync(string zoneId, DnsEntry entry)
{
var response = await _httpClient.DeleteAsync($"dns/managed/{zoneId}/records/{entry.Id}");
var response = await _httpClient.DeleteAsync($"managed/{zoneId}/records/{entry.Id}");

response.EnsureSuccessStatusCode();
}

public async Task AddRecordAsync(string zoneId, DnsEntry entry)
{
var response = await _httpClient.PostAsync($"dns/managed/{zoneId}/records", entry);
var response = await _httpClient.PostAsync($"managed/{zoneId}/records", entry);

response.EnsureSuccessStatusCode();
}
Expand All @@ -120,20 +122,9 @@ private sealed class ApiKeyHandler : DelegatingHandler
public ApiKeyHandler(string apiKey, string secretKey, HttpMessageHandler innerHandler)
: base(innerHandler)
{
if (apiKey is null)
{
throw new ArgumentNullException(nameof(apiKey));
}

if (secretKey is null)
{
throw new ArgumentNullException(nameof(secretKey));
}

if (innerHandler is null)
{
throw new ArgumentNullException(nameof(innerHandler));
}
ArgumentNullException.ThrowIfNull(apiKey);
ArgumentNullException.ThrowIfNull(secretKey);
ArgumentNullException.ThrowIfNull(innerHandler);

if (string.IsNullOrWhiteSpace(apiKey))
{
Expand Down
9 changes: 3 additions & 6 deletions KeyVault.Acmebot/Providers/DnsZone.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public class DnsZone : IEquatable<DnsZone>
{
public DnsZone(IDnsProvider dnsProvider)
{
Provider = dnsProvider;
DnsProvider = dnsProvider;
}

private static readonly IdnMapping s_idnMapping = new();
Expand All @@ -25,7 +25,7 @@ public string Name

public IReadOnlyList<string> NameServers { get; init; }

public IDnsProvider Provider { get; }
public IDnsProvider DnsProvider { get; }

public bool Equals(DnsZone other)
{
Expand All @@ -37,10 +37,7 @@ public bool Equals(DnsZone other)
return Id == other.Id;
}

public override bool Equals(object obj)
{
return Equals(obj as DnsZone);
}
public override bool Equals(object obj) => Equals(obj as DnsZone);

public override int GetHashCode() => Id?.GetHashCode() ?? 0;
}
7 changes: 3 additions & 4 deletions KeyVault.Acmebot/Providers/GandiProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public GandiProvider(GandiOptions options)

private readonly GandiClient _client;

public string Name => "Gandi LiveDNS";

public int PropagationSeconds => 300;

public async Task<IReadOnlyList<DnsZone>> ListZonesAsync()
Expand All @@ -48,10 +50,7 @@ private class GandiClient
{
public GandiClient(string apiKey)
{
if (apiKey is null)
{
throw new ArgumentNullException(nameof(apiKey));
}
ArgumentNullException.ThrowIfNull(apiKey);

_httpClient = new HttpClient
{
Expand Down
38 changes: 11 additions & 27 deletions KeyVault.Acmebot/Providers/GoDaddyProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public GoDaddyProvider(GoDaddyOptions options)

private readonly GoDaddyClient _client;

public string Name => "GoDaddy";

public int PropagationSeconds => 600;

public async Task<IReadOnlyList<DnsZone>> ListZonesAsync()
Expand All @@ -33,18 +35,7 @@ public async Task<IReadOnlyList<DnsZone>> ListZonesAsync()

public Task CreateTxtRecordAsync(DnsZone zone, string relativeRecordName, IEnumerable<string> values)
{
var entries = new List<DnsEntry>();

foreach (var value in values)
{
entries.Add(new DnsEntry
{
Name = relativeRecordName,
Type = "TXT",
TTL = 600,
Data = value
});
}
var entries = values.Select(x => new DnsEntry { Name = relativeRecordName, Type = "TXT", TTL = 600, Data = x }).ToArray();

return _client.AddRecordAsync(zone.Name, entries);
}
Expand All @@ -58,19 +49,12 @@ private class GoDaddyClient
{
public GoDaddyClient(string apiKey, string apiSecret)
{
if (apiKey is null)
{
throw new ArgumentNullException(nameof(apiKey));
}

if (apiSecret is null)
{
throw new ArgumentNullException(nameof(apiSecret));
}
ArgumentNullException.ThrowIfNull(apiKey);
ArgumentNullException.ThrowIfNull(apiSecret);

_httpClient = new HttpClient
{
BaseAddress = new Uri("https://api.godaddy.com")
BaseAddress = new Uri("https://api.godaddy.com/v1/")
};

_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
Expand All @@ -88,7 +72,7 @@ public async Task<IReadOnlyList<ZoneDomain>> ListZonesAsync()

while (true)
{
var response = await _httpClient.GetAsync($"v1/domains?statuses=ACTIVE&includes=nameServers&limit={limit}{marker}");
var response = await _httpClient.GetAsync($"domains?statuses=ACTIVE&includes=nameServers&limit={limit}{marker}");

response.EnsureSuccessStatusCode();

Expand All @@ -109,7 +93,7 @@ public async Task<IReadOnlyList<ZoneDomain>> ListZonesAsync()

public async Task DeleteRecordAsync(string domain, string type, string name)
{
var response = await _httpClient.DeleteAsync($"v1/domains/{domain}/records/{type}/{name}");
var response = await _httpClient.DeleteAsync($"domains/{domain}/records/{type}/{name}");

if (response.StatusCode != HttpStatusCode.NotFound)
{
Expand All @@ -119,13 +103,13 @@ public async Task DeleteRecordAsync(string domain, string type, string name)

public async Task AddRecordAsync(string domain, IReadOnlyList<DnsEntry> entries)
{
var response = await _httpClient.PatchAsync($"v1/domains/{domain}/records", entries);
var response = await _httpClient.PatchAsync($"domains/{domain}/records", entries);

response.EnsureSuccessStatusCode();
}
}

public class ZoneDomain
private class ZoneDomain
{
[JsonProperty("domain")]
public string Domain { get; set; }
Expand All @@ -137,7 +121,7 @@ public class ZoneDomain
public string[] NameServers { get; set; }
}

public class DnsEntry
private class DnsEntry
{
[JsonProperty("data")]
public string Data { get; set; }
Expand Down
2 changes: 2 additions & 0 deletions KeyVault.Acmebot/Providers/GoogleDnsProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ public GoogleDnsProvider(GoogleDnsOptions options)
private readonly DnsService _dnsService;
private readonly JsonCredentialParameters _credsParameters;

public string Name => "Google Cloud DNS";

public int PropagationSeconds => 60;

public async Task<IReadOnlyList<DnsZone>> ListZonesAsync()
Expand Down
1 change: 1 addition & 0 deletions KeyVault.Acmebot/Providers/IDnsProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace KeyVault.Acmebot.Providers;

public interface IDnsProvider
{
string Name { get; }
int PropagationSeconds { get; }
Task<IReadOnlyList<DnsZone>> ListZonesAsync();
Task CreateTxtRecordAsync(DnsZone zone, string relativeRecordName, IEnumerable<string> values);
Expand Down
Loading

0 comments on commit 7ab75d7

Please sign in to comment.