summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHank McCord <hymccord@gmail.com>2020-04-03 22:02:06 -0400
committerHank McCord <hymccord@gmail.com>2020-04-04 20:30:53 -0400
commitf07b5d57d533a9c9b60fdb6904a50dfe67049531 (patch)
treebd757dc8cce5db4184c64f7fdf758f01f0393421
parent5fb953ff9a5e98b591683ef0272c455e6db833d3 (diff)
downloadletsencrypt-win-simple-f07b5d57d533a9c9b60fdb6904a50dfe67049531.zip
letsencrypt-win-simple-f07b5d57d533a9c9b60fdb6904a50dfe67049531.tar.gz
letsencrypt-win-simple-f07b5d57d533a9c9b60fdb6904a50dfe67049531.tar.bz2
Add support for current azure environments
Currently, the dns validation for azure will produce errors when trying to resolve cross cloud requests. The AzureUSGoverenment specifically forbids cross cloud requests because it's a confidential environment. This will add support for the four current public Azure environments: AzureCloud, AzureChinaCloud, AzureUSGovernment, AzureGermanCloud. Resolves: #1485
-rwxr-xr-xsrc/plugin.validation.dns.azure/Azure.cs30
-rwxr-xr-xsrc/plugin.validation.dns.azure/AzureArguments.cs1
-rwxr-xr-xsrc/plugin.validation.dns.azure/AzureArgumentsProvider.cs3
-rw-r--r--src/plugin.validation.dns.azure/AzureEnvironments.cs25
-rwxr-xr-xsrc/plugin.validation.dns.azure/AzureOptions.cs1
-rwxr-xr-xsrc/plugin.validation.dns.azure/AzureOptionsFactory.cs61
6 files changed, 110 insertions, 11 deletions
diff --git a/src/plugin.validation.dns.azure/Azure.cs b/src/plugin.validation.dns.azure/Azure.cs
index 3ae1af0..c679082 100755
--- a/src/plugin.validation.dns.azure/Azure.cs
+++ b/src/plugin.validation.dns.azure/Azure.cs
@@ -5,6 +5,8 @@ using Microsoft.Rest;
using Microsoft.Rest.Azure.Authentication;
using PKISharp.WACS.Clients.DNS;
using PKISharp.WACS.Services;
+using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@@ -16,17 +18,33 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
{
private DnsManagementClient _azureDnsClient;
private readonly DomainParseService _domainParser;
+ private readonly Uri _resourceManagerEndpoint;
private readonly AzureOptions _options;
public Azure(AzureOptions options,
DomainParseService domainParser,
- LookupClientProvider dnsClient,
- ILogService log,
+ LookupClientProvider dnsClient,
+ ILogService log,
ISettingsService settings)
: base(dnsClient, log, settings)
{
_options = options;
_domainParser = domainParser;
+
+ if (!AzureEnvironments.ResourceManagerUrls.TryGetValue(options.AzureEnvironment, out string endpoint))
+ {
+ // Custom endpoint
+ endpoint = options.AzureEnvironment;
+ }
+ try
+ {
+ _resourceManagerEndpoint = new Uri(endpoint);
+ }
+ catch (Exception ex)
+ {
+ _log.Error(ex, "Could not parse Azure endpoint url. Falling back to default.");
+ _resourceManagerEndpoint = new Uri(AzureEnvironments.ResourceManagerUrls[AzureEnvironments.AzureCloud]);
+ }
}
public override async Task CreateRecord(string recordName, string token)
@@ -68,7 +86,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
if (_options.UseMsi)
{
var azureServiceTokenProvider = new AzureServiceTokenProvider();
- var accessToken = await azureServiceTokenProvider.GetAccessTokenAsync("https://management.azure.com/");
+ var accessToken = await azureServiceTokenProvider.GetAccessTokenAsync(_resourceManagerEndpoint.ToString());
credentials = new TokenCredentials(accessToken);
}
else
@@ -78,8 +96,8 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
_options.ClientId,
_options.Secret.Value);
}
-
- _azureDnsClient = new DnsManagementClient(credentials)
+
+ _azureDnsClient = new DnsManagementClient(_resourceManagerEndpoint, credentials)
{
SubscriptionId = _options.SubscriptionId
};
@@ -123,7 +141,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
}
_log.Error(
- "Can't find hosted zone for {domainName} in resource group {ResourceGroupName}",
+ "Can't find hosted zone for {domainName} in resource group {ResourceGroupName}",
domainName,
_options.ResourceGroupName);
diff --git a/src/plugin.validation.dns.azure/AzureArguments.cs b/src/plugin.validation.dns.azure/AzureArguments.cs
index 9374976..07e6359 100755
--- a/src/plugin.validation.dns.azure/AzureArguments.cs
+++ b/src/plugin.validation.dns.azure/AzureArguments.cs
@@ -2,6 +2,7 @@
{
public class AzureArguments
{
+ public string AzureEnvironment { get; set; }
public bool AzureUseMsi { get; set; }
public string AzureTenantId { get; set; }
public string AzureClientId { get; set; }
diff --git a/src/plugin.validation.dns.azure/AzureArgumentsProvider.cs b/src/plugin.validation.dns.azure/AzureArgumentsProvider.cs
index 6a5edcd..f27f37a 100755
--- a/src/plugin.validation.dns.azure/AzureArgumentsProvider.cs
+++ b/src/plugin.validation.dns.azure/AzureArgumentsProvider.cs
@@ -10,6 +10,9 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins
public override string Condition => "--validationmode dns-01 --validation azure";
public override void Configure(FluentCommandLineParser<AzureArguments> parser)
{
+ parser.Setup(o => o.AzureEnvironment)
+ .As("azureenvironment")
+ .WithDescription("Public Azure service instance endpoint");
parser.Setup(o => o.AzureUseMsi)
.As("azureusemsi")
.WithDescription("Use Managed Service Identity for authentication.");
diff --git a/src/plugin.validation.dns.azure/AzureEnvironments.cs b/src/plugin.validation.dns.azure/AzureEnvironments.cs
new file mode 100644
index 0000000..342e948
--- /dev/null
+++ b/src/plugin.validation.dns.azure/AzureEnvironments.cs
@@ -0,0 +1,25 @@
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+
+namespace PKISharp.WACS.Plugins.ValidationPlugins
+{
+ public static class AzureEnvironments
+ {
+ public const string AzureCloud = "AzureCloud";
+
+ public const string AzureChinaCloud = "AzureChinaCloud";
+
+ public const string AzureUSGovernment = "AzureUSGovernment";
+
+ public const string AzureGermanCloud = "AzureGermanCloud";
+
+ public static IDictionary<string, string> ResourceManagerUrls
+ = new ConcurrentDictionary<string, string>()
+ {
+ [AzureCloud] = "https://management.azure.com",
+ [AzureChinaCloud] = "https://management.chinacloudapi.cn",
+ [AzureUSGovernment] = "https://management.usgovcloudapi.net",
+ [AzureGermanCloud] = "https://management.microsoftazure.de",
+ };
+ }
+}
diff --git a/src/plugin.validation.dns.azure/AzureOptions.cs b/src/plugin.validation.dns.azure/AzureOptions.cs
index a064f7a..95f8cb0 100755
--- a/src/plugin.validation.dns.azure/AzureOptions.cs
+++ b/src/plugin.validation.dns.azure/AzureOptions.cs
@@ -12,6 +12,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
public override string Description => "Create verification records in Azure DNS";
public override string ChallengeType => Constants.Dns01ChallengeType;
+ public string AzureEnvironment { get; set; }
public bool UseMsi { get; set; }
public string ClientId { get; set; }
public string ResourceGroupName { get; set; }
diff --git a/src/plugin.validation.dns.azure/AzureOptionsFactory.cs b/src/plugin.validation.dns.azure/AzureOptionsFactory.cs
index 7a67aa3..6fce15a 100755
--- a/src/plugin.validation.dns.azure/AzureOptionsFactory.cs
+++ b/src/plugin.validation.dns.azure/AzureOptionsFactory.cs
@@ -3,6 +3,9 @@ using PKISharp.WACS.DomainObjects;
using PKISharp.WACS.Plugins.Base.Factories;
using PKISharp.WACS.Services;
using PKISharp.WACS.Services.Serialization;
+using System;
+using System.Collections.Generic;
+using System.Linq;
using System.Threading.Tasks;
namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
@@ -20,13 +23,32 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
{
var az = _arguments.GetArguments<AzureArguments>();
- var useMsi = az.AzureUseMsi || await input.PromptYesNo("Do you want to use a managed service identity?", true);
- var options = new AzureOptions
+ var options = new AzureOptions();
+
+ var environments = new List<Choice<Func<Task>>>(
+ AzureEnvironments.ResourceManagerUrls
+ .OrderBy(kvp => kvp.Key)
+ .Select(kvp =>
+ Choice.Create<Func<Task>>(() =>
+ {
+ options.AzureEnvironment = kvp.Key;
+ return Task.CompletedTask;
+ },
+ description: kvp.Key,
+ @default: kvp.Key == AzureEnvironments.AzureCloud)))
{
- UseMsi = useMsi,
+ Choice.Create<Func<Task>>(async () =>
+ {
+ await InputUrl(input, options);
+ }, "Use a custom resource manager url")
};
-
- if (!useMsi)
+
+ var chosen = await input.ChooseFromMenu("Which Azure environment are you using?", environments);
+ await chosen.Invoke();
+
+ options.UseMsi = az.AzureUseMsi || await input.PromptYesNo("Do you want to use a managed service identity?", true);
+
+ if (!options.UseMsi)
{
// These options are only necessary for client id/secret authentication.
options.TenantId = await _arguments.TryGetArgument(az.AzureTenantId, input, "Directory/tenant id");
@@ -46,6 +68,7 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
var options = new AzureOptions
{
UseMsi = az.AzureUseMsi,
+ AzureEnvironment = _arguments.TryGetRequiredArgument(nameof(az.AzureEnvironment), az.AzureEnvironment),
SubscriptionId = _arguments.TryGetRequiredArgument(nameof(az.AzureSubscriptionId), az.AzureSubscriptionId),
ResourceGroupName = _arguments.TryGetRequiredArgument(nameof(az.AzureResourceGroupName), az.AzureResourceGroupName)
};
@@ -62,5 +85,33 @@ namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns
}
public override bool CanValidate(Target target) => true;
+
+ private async Task InputUrl(IInputService input, AzureOptions options)
+ {
+ string raw;
+ do
+ {
+ raw = await input.RequestString("Url");
+ }
+ while (!ParseUrl(raw, options));
+ }
+
+ private bool ParseUrl(string url, AzureOptions options)
+ {
+ if (string.IsNullOrWhiteSpace(url))
+ {
+ return false;
+ }
+ try
+ {
+ var uri = new Uri(url);
+ options.AzureEnvironment = uri.ToString();
+ return true;
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+ }
}
}