diff --git a/pkg/apis/acme/v1/types_issuer.go b/pkg/apis/acme/v1/types_issuer.go index eb0453942..bd3d2f054 100644 --- a/pkg/apis/acme/v1/types_issuer.go +++ b/pkg/apis/acme/v1/types_issuer.go @@ -495,6 +495,12 @@ type ACMEIssuerDNS01ProviderAzureDNS struct { // +optional Environment AzureDNSEnvironment `json:"environment,omitempty"` + + // +optional + ManagedIdentityClientID string `json:"managedIdentityClientID,omitempty"` + + // +optional + ManagedIdentityResourceID string `json:"managedIdentityResourceID,omitempty"` } // +kubebuilder:validation:Enum=AzurePublicCloud;AzureChinaCloud;AzureGermanCloud;AzureUSGovernmentCloud diff --git a/pkg/issuer/acme/dns/azuredns/azuredns.go b/pkg/issuer/acme/dns/azuredns/azuredns.go index 03e0ab0c9..f543c37d5 100644 --- a/pkg/issuer/acme/dns/azuredns/azuredns.go +++ b/pkg/issuer/acme/dns/azuredns/azuredns.go @@ -39,7 +39,7 @@ type DNSProvider struct { // NewDNSProviderCredentials returns a DNSProvider instance configured for the Azure // DNS service using static credentials from its parameters -func NewDNSProviderCredentials(environment, clientID, clientSecret, subscriptionID, tenantID, resourceGroupName, zoneName string, dns01Nameservers []string, ambient bool) (*DNSProvider, error) { +func NewDNSProviderCredentials(environment, clientID, clientSecret, subscriptionID, tenantID, resourceGroupName, zoneName string, dns01Nameservers []string, ambient bool, managedIdentityClientID string, managedIdentityResourceID string) (*DNSProvider, error) { env := azure.PublicCloud if environment != "" { var err error @@ -49,7 +49,11 @@ func NewDNSProviderCredentials(environment, clientID, clientSecret, subscription } } - spt, err := getAuthorization(env, clientID, clientSecret, subscriptionID, tenantID, ambient) + if managedIdentityClientID != "" && managedIdentityResourceID != "" { + return nil, fmt.Errorf("managedIdentityClientID and managedIdentityResourceID can not be set at the same time") + } + + spt, err := getAuthorization(env, clientID, clientSecret, subscriptionID, tenantID, ambient, managedIdentityClientID, managedIdentityResourceID) if err != nil { return nil, err } @@ -70,7 +74,7 @@ func NewDNSProviderCredentials(environment, clientID, clientSecret, subscription }, nil } -func getAuthorization(env azure.Environment, clientID, clientSecret, subscriptionID, tenantID string, ambient bool) (*adal.ServicePrincipalToken, error) { +func getAuthorization(env azure.Environment, clientID, clientSecret, subscriptionID, tenantID string, ambient bool, managedIdentityClientID string, managedIdentityResourceID string) (*adal.ServicePrincipalToken, error) { if clientID != "" { logf.Log.V(logf.InfoLevel).Info("azuredns authenticating with clientID and secret key") oauthConfig, err := adal.NewOAuthConfig(env.ActiveDirectoryEndpoint, tenantID) @@ -87,12 +91,12 @@ func getAuthorization(env azure.Environment, clientID, clientSecret, subscriptio if !ambient { return nil, fmt.Errorf("ClientID is not set but neither `--cluster-issuer-ambient-credentials` nor `--issuer-ambient-credentials` are set. These are necessary to enable Azure Managed Identities") } - msiEndpoint, err := adal.GetMSIVMEndpoint() - if err != nil { - return nil, fmt.Errorf("failed to get the managed service identity endpoint: %v", err) - } - spt, err := adal.NewServicePrincipalTokenFromMSI(msiEndpoint, env.ServiceManagementEndpoint) + opt := adal.ManagedIdentityOptions{ + ClientID: managedIdentityClientID, + IdentityResourceID: managedIdentityResourceID, + } + spt, err := adal.NewServicePrincipalTokenFromManagedIdentity(env.ServiceManagementEndpoint, &opt) if err != nil { return nil, fmt.Errorf("failed to create the managed service identity token: %v", err) } diff --git a/pkg/issuer/acme/dns/azuredns/azuredns_test.go b/pkg/issuer/acme/dns/azuredns/azuredns_test.go index 4e641a37c..d995c7044 100644 --- a/pkg/issuer/acme/dns/azuredns/azuredns_test.go +++ b/pkg/issuer/acme/dns/azuredns/azuredns_test.go @@ -45,7 +45,7 @@ func TestLiveAzureDnsPresent(t *testing.T) { if !azureLiveTest { t.Skip("skipping live test") } - provider, err := NewDNSProviderCredentials("", azureClientID, azureClientSecret, azuresubscriptionID, azureTenantID, azureResourceGroupName, azureHostedZoneName, util.RecursiveNameservers, false) + provider, err := NewDNSProviderCredentials("", azureClientID, azureClientSecret, azuresubscriptionID, azureTenantID, azureResourceGroupName, azureHostedZoneName, util.RecursiveNameservers, false, "", "") assert.NoError(t, err) err = provider.Present(azureDomain, "_acme-challenge."+azureDomain+".", "123d==") @@ -59,7 +59,7 @@ func TestLiveAzureDnsCleanUp(t *testing.T) { time.Sleep(time.Second * 5) - provider, err := NewDNSProviderCredentials("", azureClientID, azureClientSecret, azuresubscriptionID, azureTenantID, azureResourceGroupName, azureHostedZoneName, util.RecursiveNameservers, false) + provider, err := NewDNSProviderCredentials("", azureClientID, azureClientSecret, azuresubscriptionID, azureTenantID, azureResourceGroupName, azureHostedZoneName, util.RecursiveNameservers, false, "", "") assert.NoError(t, err) err = provider.CleanUp(azureDomain, "_acme-challenge."+azureDomain+".", "123d==") @@ -69,10 +69,10 @@ func TestLiveAzureDnsCleanUp(t *testing.T) { func TestInvalidAzureDns(t *testing.T) { validEnv := []string{"", "AzurePublicCloud", "AzureChinaCloud", "AzureGermanCloud", "AzureUSGovernmentCloud"} for _, env := range validEnv { - _, err := NewDNSProviderCredentials(env, "cid", "secret", "", "", "", "", util.RecursiveNameservers, false) + _, err := NewDNSProviderCredentials(env, "cid", "secret", "", "", "", "", util.RecursiveNameservers, false, "", "") assert.NoError(t, err) } - _, err := NewDNSProviderCredentials("invalid env", "cid", "secret", "", "", "", "", util.RecursiveNameservers, false) + _, err := NewDNSProviderCredentials("invalid env", "cid", "secret", "", "", "", "", util.RecursiveNameservers, false, "", "") assert.Error(t, err) } diff --git a/pkg/issuer/acme/dns/dns.go b/pkg/issuer/acme/dns/dns.go index f92a52c31..c3576552b 100644 --- a/pkg/issuer/acme/dns/dns.go +++ b/pkg/issuer/acme/dns/dns.go @@ -60,7 +60,7 @@ type dnsProviderConstructors struct { cloudDNS func(project string, serviceAccount []byte, dns01Nameservers []string, ambient bool, hostedZoneName string) (*clouddns.DNSProvider, error) cloudFlare func(email, apikey, apiToken string, dns01Nameservers []string) (*cloudflare.DNSProvider, error) route53 func(accessKey, secretKey, hostedZoneID, region, role string, ambient bool, dns01Nameservers []string) (*route53.DNSProvider, error) - azureDNS func(environment, clientID, clientSecret, subscriptionID, tenantID, resourceGroupName, hostedZoneName string, dns01Nameservers []string, ambient bool) (*azuredns.DNSProvider, error) + azureDNS func(environment, clientID, clientSecret, subscriptionID, tenantID, resourceGroupName, hostedZoneName string, dns01Nameservers []string, ambient bool, managedIdentityClientID string, managedIdentityResourceID string) (*azuredns.DNSProvider, error) acmeDNS func(host string, accountJson []byte, dns01Nameservers []string) (*acmedns.DNSProvider, error) digitalOcean func(token string, dns01Nameservers []string) (*digitalocean.DNSProvider, error) } @@ -345,6 +345,8 @@ func (s *Solver) solverForChallenge(ctx context.Context, issuer v1.GenericIssuer providerConfig.AzureDNS.HostedZoneName, s.DNS01Nameservers, canUseAmbientCredentials, + providerConfig.AzureDNS.ManagedIdentityClientID, + providerConfig.AzureDNS.ManagedIdentityResourceID, ) if err != nil { return nil, nil, fmt.Errorf("error instantiating azuredns challenge solver: %s", err) diff --git a/pkg/issuer/acme/dns/util_test.go b/pkg/issuer/acme/dns/util_test.go index 04808ab1b..67cf503a4 100644 --- a/pkg/issuer/acme/dns/util_test.go +++ b/pkg/issuer/acme/dns/util_test.go @@ -143,8 +143,8 @@ func newFakeDNSProviders() *fakeDNSProviders { f.call("route53", accessKey, secretKey, hostedZoneID, region, role, ambient, util.RecursiveNameservers) return nil, nil }, - azureDNS: func(environment, clientID, clientSecret, subscriptionID, tenantID, resourceGroupName, hostedZoneName string, dns01Nameservers []string, ambient bool) (*azuredns.DNSProvider, error) { - f.call("azuredns", clientID, clientSecret, subscriptionID, tenantID, resourceGroupName, hostedZoneName, util.RecursiveNameservers, ambient) + azureDNS: func(environment, clientID, clientSecret, subscriptionID, tenantID, resourceGroupName, hostedZoneName string, dns01Nameservers []string, ambient bool, managedIdentityClientID string, managedIdentityResourceID string) (*azuredns.DNSProvider, error) { + f.call("azuredns", clientID, clientSecret, subscriptionID, tenantID, resourceGroupName, hostedZoneName, util.RecursiveNameservers, ambient, "", "") return nil, nil }, acmeDNS: func(host string, accountJson []byte, dns01Nameservers []string) (*acmedns.DNSProvider, error) {