feat(azure): add usage of Managed Identities for azuredns provider for acme dns01 challenge

Signed-off-by: gitirabassi <giacomo@tirabassi.eu>
This commit is contained in:
gitirabassi 2020-03-10 14:55:19 +01:00
parent 15d1735688
commit fa034751dc
No known key found for this signature in database
GPG Key ID: 2E88FEA935FC6CFE
8 changed files with 63 additions and 41 deletions

View File

@ -201,11 +201,8 @@ spec:
containing the configuration for Azure DNS
type: object
required:
- clientID
- clientSecretSecretRef
- resourceGroupName
- subscriptionID
- tenantID
properties:
clientID:
type: string

View File

@ -244,11 +244,8 @@ spec:
containing the configuration for Azure DNS
type: object
required:
- clientID
- clientSecretSecretRef
- resourceGroupName
- subscriptionID
- tenantID
properties:
clientID:
type: string

View File

@ -244,11 +244,8 @@ spec:
containing the configuration for Azure DNS
type: object
required:
- clientID
- clientSecretSecretRef
- resourceGroupName
- subscriptionID
- tenantID
properties:
clientID:
type: string

View File

@ -343,13 +343,13 @@ type ACMEIssuerDNS01ProviderRoute53 struct {
// ACMEIssuerDNS01ProviderAzureDNS is a structure containing the
// configuration for Azure DNS
type ACMEIssuerDNS01ProviderAzureDNS struct {
ClientID string `json:"clientID"`
ClientID string `json:"clientID,omitempty"`
ClientSecret cmmeta.SecretKeySelector `json:"clientSecretSecretRef"`
ClientSecret cmmeta.SecretKeySelector `json:"clientSecretSecretRef,omitempty"`
SubscriptionID string `json:"subscriptionID"`
TenantID string `json:"tenantID"`
TenantID string `json:"tenantID,omitempty"`
ResourceGroupName string `json:"resourceGroupName"`

View File

@ -343,13 +343,13 @@ type ACMEIssuerDNS01ProviderRoute53 struct {
// ACMEIssuerDNS01ProviderAzureDNS is a structure containing the
// configuration for Azure DNS
type ACMEIssuerDNS01ProviderAzureDNS struct {
ClientID string `json:"clientID"`
ClientID string `json:"clientID,omitempty"`
ClientSecret cmmeta.SecretKeySelector `json:"clientSecretSecretRef"`
ClientSecret cmmeta.SecretKeySelector `json:"clientSecretSecretRef,omitempty"`
SubscriptionID string `json:"subscriptionID"`
TenantID string `json:"tenantID"`
TenantID string `json:"tenantID,omitempty"`
ResourceGroupName string `json:"resourceGroupName"`

View File

@ -253,16 +253,27 @@ func ValidateACMEChallengeSolverDNS01(p *cmacme.ACMEChallengeSolverDNS01, fldPat
el = append(el, field.Forbidden(fldPath.Child("azuredns"), "may not specify more than one provider type"))
} else {
numProviders++
el = append(el, ValidateSecretKeySelector(&p.AzureDNS.ClientSecret, fldPath.Child("azuredns", "clientSecretSecretRef"))...)
if len(p.AzureDNS.ClientID) == 0 {
el = append(el, field.Required(fldPath.Child("azuredns", "clientID"), ""))
// if ClientID is defined then clientSecret and tenantID must be defined
if len(p.AzureDNS.ClientID) > 0 {
el = append(el, ValidateSecretKeySelector(&p.AzureDNS.ClientSecret, fldPath.Child("azuredns", "clientSecretSecretRef"))...)
if len(p.AzureDNS.TenantID) == 0 {
el = append(el, field.Required(fldPath.Child("azuredns", "tenantID"), ""))
}
}
// if ClientSecret is defined then both ClientID and TenantID must be defined
if &p.AzureDNS.ClientSecret != nil {
if len(p.AzureDNS.ClientID) == 0 {
el = append(el, field.Required(fldPath.Child("azuredns", "clientID"), ""))
}
if len(p.AzureDNS.TenantID) == 0 {
el = append(el, field.Required(fldPath.Child("azuredns", "tenantID"), ""))
}
}
// SubscriptionID must always be defined
if len(p.AzureDNS.SubscriptionID) == 0 {
el = append(el, field.Required(fldPath.Child("azuredns", "subscriptionID"), ""))
}
if len(p.AzureDNS.TenantID) == 0 {
el = append(el, field.Required(fldPath.Child("azuredns", "tenantID"), ""))
}
// ResourceGroupName must always be defined
if len(p.AzureDNS.ResourceGroupName) == 0 {
el = append(el, field.Required(fldPath.Child("azuredns", "resourceGroupName"), ""))
}

View File

@ -48,12 +48,12 @@ func NewDNSProvider(dns01Nameservers []string) (*DNSProvider, error) {
zoneName := ("AZURE_ZONE_NAME")
environment := ("AZURE_ENVIRONMENT")
return NewDNSProviderCredentials(environment, clientID, clientSecret, subscriptionID, tenantID, resourceGroupName, zoneName, dns01Nameservers)
return NewDNSProviderCredentials(environment, clientID, clientSecret, subscriptionID, tenantID, resourceGroupName, zoneName, dns01Nameservers, true)
}
// 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) (*DNSProvider, error) {
func NewDNSProviderCredentials(environment, clientID, clientSecret, subscriptionID, tenantID, resourceGroupName, zoneName string, dns01Nameservers []string, ambient bool) (*DNSProvider, error) {
env := azure.PublicCloud
if environment != "" {
var err error
@ -62,15 +62,31 @@ func NewDNSProviderCredentials(environment, clientID, clientSecret, subscription
return nil, err
}
}
spt := &adal.ServicePrincipalToken{}
if clientID != "" {
klog.Info("azuredns authenticating with clientID and secret key")
oauthConfig, err := adal.NewOAuthConfig(env.ActiveDirectoryEndpoint, tenantID)
if err != nil {
return nil, err
}
spt, err = adal.NewServicePrincipalToken(*oauthConfig, clientID, clientSecret, env.ResourceManagerEndpoint)
if err != nil {
return nil, err
}
} else {
klog.Info("azuredns authenticating with managed identity")
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)
}
oauthConfig, err := adal.NewOAuthConfig(env.ActiveDirectoryEndpoint, tenantID)
if err != nil {
return nil, err
}
spt, err := adal.NewServicePrincipalToken(*oauthConfig, clientID, clientSecret, env.ResourceManagerEndpoint)
if err != nil {
return nil, err
spt, err = adal.NewServicePrincipalTokenFromMSI(msiEndpoint, env.ServiceManagementEndpoint)
if err != nil {
return nil, fmt.Errorf("failed to create the managed service identity token: %v", err)
}
}
rc := dns.NewRecordSetsClientWithBaseURI(env.ResourceManagerEndpoint, subscriptionID)

View File

@ -64,7 +64,7 @@ type dnsProviderConstructors struct {
cloudDNS func(project string, serviceAccount []byte, dns01Nameservers []string, ambient bool) (*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) (*azuredns.DNSProvider, error)
azureDNS func(environment, clientID, clientSecret, subscriptionID, tenantID, resourceGroupName, hostedZoneName string, dns01Nameservers []string, ambient bool) (*azuredns.DNSProvider, error)
acmeDNS func(host string, accountJson []byte, dns01Nameservers []string) (*acmedns.DNSProvider, error)
digitalOcean func(token string, dns01Nameservers []string) (*digitalocean.DNSProvider, error)
}
@ -330,25 +330,29 @@ func (s *Solver) solverForChallenge(ctx context.Context, issuer v1alpha2.Generic
}
case providerConfig.AzureDNS != nil:
dbg.Info("preparing to create AzureDNS provider")
clientSecret, err := s.secretLister.Secrets(resourceNamespace).Get(providerConfig.AzureDNS.ClientSecret.Name)
if err != nil {
return nil, nil, fmt.Errorf("error getting azuredns client secret: %s", err)
}
secret := ""
if providerConfig.AzureDNS.ClientID != "" {
clientSecret, err := s.secretLister.Secrets(resourceNamespace).Get(providerConfig.AzureDNS.ClientSecret.Name)
if err != nil {
return nil, nil, fmt.Errorf("error getting azuredns client secret: %s", err)
}
clientSecretBytes, ok := clientSecret.Data[providerConfig.AzureDNS.ClientSecret.Key]
if !ok {
return nil, nil, fmt.Errorf("error getting azure dns client secret: key '%s' not found in secret", providerConfig.AzureDNS.ClientSecret.Key)
clientSecretBytes, ok := clientSecret.Data[providerConfig.AzureDNS.ClientSecret.Key]
if !ok {
return nil, nil, fmt.Errorf("error getting azure dns client secret: key '%s' not found in secret", providerConfig.AzureDNS.ClientSecret.Key)
}
secret = string(clientSecretBytes)
}
impl, err = s.dnsProviderConstructors.azureDNS(
string(providerConfig.AzureDNS.Environment),
providerConfig.AzureDNS.ClientID,
string(clientSecretBytes),
secret,
providerConfig.AzureDNS.SubscriptionID,
providerConfig.AzureDNS.TenantID,
providerConfig.AzureDNS.ResourceGroupName,
providerConfig.AzureDNS.HostedZoneName,
s.DNS01Nameservers,
canUseAmbientCredentials,
)
if err != nil {
return nil, nil, fmt.Errorf("error instantiating azuredns challenge solver: %s", err)