azuredns: provide the ability to select authentication methods (#2026)

Co-authored-by: Fernandez Ludovic <ldez@users.noreply.github.com>
This commit is contained in:
pchanvallon 2023-10-05 13:25:44 +02:00 committed by GitHub
parent c2fd4498e5
commit bf8c7abf6d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 198 additions and 54 deletions

View file

@ -307,6 +307,7 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`Credentials:`)
ew.writeln(` - "AZURE_CLIENT_CERTIFICATE_PATH": Client certificate path`)
ew.writeln(` - "AZURE_CLIENT_ID": Client ID`)
ew.writeln(` - "AZURE_CLIENT_SECRET": Client secret`)
ew.writeln(` - "AZURE_RESOURCE_GROUP": DNS zone resource group`)
@ -315,6 +316,8 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "AZURE_AUTH_METHOD": Specify which authentication method to use`)
ew.writeln(` - "AZURE_AUTH_MSI_TIMEOUT": Managed Identity timeout duration`)
ew.writeln(` - "AZURE_ENVIRONMENT": Azure environment, one of: public, usgovernment, and china`)
ew.writeln(` - "AZURE_POLLING_INTERVAL": Time between DNS propagation check`)
ew.writeln(` - "AZURE_PRIVATE_ZONE": Set to true to use Azure Private DNS Zones and not public`)

View file

@ -70,6 +70,7 @@ lego --domains example.com --email your_example@email.com --dns azuredns run
| Environment Variable Name | Description |
|-----------------------|-------------|
| `AZURE_CLIENT_CERTIFICATE_PATH` | Client certificate path |
| `AZURE_CLIENT_ID` | Client ID |
| `AZURE_CLIENT_SECRET` | Client secret |
| `AZURE_RESOURCE_GROUP` | DNS zone resource group |
@ -84,6 +85,8 @@ More information [here]({{< ref "dns#configuration-and-credentials" >}}).
| Environment Variable Name | Description |
|--------------------------------|-------------|
| `AZURE_AUTH_METHOD` | Specify which authentication method to use |
| `AZURE_AUTH_MSI_TIMEOUT` | Managed Identity timeout duration |
| `AZURE_ENVIRONMENT` | Azure environment, one of: public, usgovernment, and china |
| `AZURE_POLLING_INTERVAL` | Time between DNS propagation check |
| `AZURE_PRIVATE_ZONE` | Set to true to use Azure Private DNS Zones and not public |
@ -96,19 +99,59 @@ More information [here]({{< ref "dns#configuration-and-credentials" >}}).
## Description
Azure Credentials are automatically detected in the following locations and prioritized in the following order:
Several authentication methods can be used to authenticate against Azure DNS API.
### Default Azure Credentials (default option)
Default Azure Credentials automatically detects in the following locations and prioritized in the following order:
1. Environment variables for client secret: `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, `AZURE_CLIENT_SECRET`
2. Environment variables for client certificate: `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, `AZURE_CLIENT_CERTIFICATE_PATH`
3. Workload identity for resources hosted in Azure environment (see below)
4. Shared credentials file (defaults to `~/.azure`), used by Azure CLI
4. Shared credentials (defaults to `~/.azure` folder), used by Azure CLI
Link:
- [Azure Authentication](https://learn.microsoft.com/en-us/azure/developer/go/azure-sdk-authentication)
### Environment variables
#### Client secret
The Azure Credentials can be configured using the following environment variables:
* AZURE_CLIENT_ID = "Client ID"
* AZURE_CLIENT_SECRET = "Client secret"
* AZURE_TENANT_ID = "Tenant ID"
This authentication method can be specificaly used by setting the `AZURE_AUTH_METHOD` environment variable to `env`.
#### Client certificate
The Azure Credentials can be configured using the following environment variables:
* AZURE_CLIENT_ID = "Client ID"
* AZURE_CLIENT_CERTIFICATE_PATH = "Client certificate path"
* AZURE_TENANT_ID = "Tenant ID"
This authentication method can be specificaly used by setting the `AZURE_AUTH_METHOD` environment variable to `env`.
### Workload identity
#### Azure Managed Identity
Workload identity allows workloads running Azure Kubernetes Services (AKS) clusters to authenticate as an Azure AD application identity using federated credentials.
This must be configured in kubernetes workload deployment in one hand and on the Azure AD application registration in the other hand.
Here is a summary of the steps to follow to use it :
* create a `ServiceAccount` resource, add following annotations to reference the targeted Azure AD application registration : `azure.workload.identity/client-id` and `azure.workload.identity/tenant-id`.
* on the `Deployment` resource you must reference the previous `ServiceAccount` and add the following label : `azure.workload.identity/use: "true"`.
* create a fedreated credentials of type `Kubernetes accessing Azure resources`, add the cluster issuer URL and add the namespace and name of your kubernetes service account.
Link :
- [Azure AD Workload identity](https://azure.github.io/azure-workload-identity/docs/topics/service-account-labels-and-annotations.html)
This authentication method can be specificaly used by setting the `AZURE_AUTH_METHOD` environment variable to `wli`.
### Azure Managed Identity
#### Azure Managed Identity (with Azure workload)
The Azure Managed Identity service allows linking Azure AD identities to Azure resources, without needing to manually manage client IDs and secrets.
@ -138,6 +181,11 @@ az role assignment create \
--scope "/subscriptions/${AZURE_SUBSCRIPTION_ID}/resourceGroups/${AZURE_RESOURCE_GROUP}/providers/Microsoft.Network/dnszones/${AZURE_DNS_ZONE}/TXT/${AZ_RECORD_SET}"
```
A timeout wrapper is configured for this authentication method.
The duraction can be configured by setting the `AZURE_AUTH_MSI_TIMEOUT`.
The default timeout is 2 seconds.
This authentication method can be specificaly used by setting the `AZURE_AUTH_METHOD` environment variable to `msi`.
#### Azure Managed Identity (with Azure Arc)
The Azure Arc agent provides the ability to use a Managed Identity on resources hosted outside of Azure
@ -146,22 +194,21 @@ The Azure Arc agent provides the ability to use a Managed Identity on resources
While the upstream `azidentity` SDK will try to automatically identify and use the Azure Arc metadata service,
if you get `azuredns: DefaultAzureCredential: failed to acquire a token.` error messages,
you may need to set the environment variables:
* `IMDS_ENDPOINT=http://localhost:40342`
* `IDENTITY_ENDPOINT=http://localhost:40342/metadata/identity/oauth2/token`
* `IMDS_ENDPOINT=http://localhost:40342`
* `IDENTITY_ENDPOINT=http://localhost:40342/metadata/identity/oauth2/token`
#### Workload identity for AKS
A timeout wrapper is configured for this authentication method.
The duraction can be configured by setting the `AZURE_AUTH_MSI_TIMEOUT`.
The default timeout is 2 seconds.
This authentication method can be specificaly used by setting the `AZURE_AUTH_METHOD` environment variable to `msi`.
Workload identity allows workloads running Azure Kubernetes Services (AKS) clusters to authenticate as an Azure AD application identity using federated credentials.
### Azure CLI
This must be configured in kubernetes workload deployment in one hand and on the Azure AD application registration in the other hand.
The Azure CLI is a command-line tool provided by Microsoft to interact with Azure resources.
It provides an easy way to authenticate by simply running `az login` command.
The generated token will be cached by default in the `~/.azure` folder.
Here is a summary of the steps to follow to use it :
* create a `ServiceAccount` resource, add following annotations to reference the targeted Azure AD application registration : `azure.workload.identity/client-id` and `azure.workload.identity/tenant-id`.
* on the `Deployment` resource you must reference the previous `ServiceAccount` and add the following label : `azure.workload.identity/use: "true"`.
* create a fedreated credentials of type `Kubernetes accessing Azure resources`, add the cluster issuer URL and add the namespace and name of your kubernetes service account.
Link :
- [Azure AD Workload identity](https://azure.github.io/azure-workload-identity/docs/topics/service-account-labels-and-annotations.html)
This authentication method can be specificaly used by setting the `AZURE_AUTH_METHOD` environment variable to `cli`.

View file

@ -3,12 +3,15 @@
package azuredns
import (
"context"
"errors"
"fmt"
"strings"
"time"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/platform/config/env"
@ -28,6 +31,9 @@ const (
EnvClientID = envNamespace + "CLIENT_ID"
EnvClientSecret = envNamespace + "CLIENT_SECRET"
EnvAuthMethod = envNamespace + "AUTH_METHOD"
EnvAuthMSITimeout = envNamespace + "AUTH_MSI_TIMEOUT"
EnvTTL = envNamespace + "TTL"
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
@ -46,6 +52,9 @@ type Config struct {
ClientSecret string
TenantID string
AuthMethod string
AuthMSITimeout time.Duration
PropagationTimeout time.Duration
PollingInterval time.Duration
TTL int
@ -94,6 +103,9 @@ func NewDNSProvider() (*DNSProvider, error) {
config.ClientSecret = env.GetOrFile(EnvClientSecret)
config.TenantID = env.GetOrFile(EnvTenantID)
config.AuthMethod = env.GetOrFile(EnvAuthMethod)
config.AuthMSITimeout = env.GetOrDefaultSecond(EnvAuthMSITimeout, 2*time.Second)
return NewDNSProviderConfig(config)
}
@ -103,30 +115,9 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("azuredns: the configuration of the DNS provider is nil")
}
var err error
var credentials azcore.TokenCredential
if config.ClientID != "" && config.ClientSecret != "" && config.TenantID != "" {
options := azidentity.ClientSecretCredentialOptions{
ClientOptions: azcore.ClientOptions{
Cloud: config.Environment,
},
}
credentials, err = azidentity.NewClientSecretCredential(config.TenantID, config.ClientID, config.ClientSecret, &options)
if err != nil {
return nil, fmt.Errorf("azuredns: %w", err)
}
} else {
options := azidentity.DefaultAzureCredentialOptions{
ClientOptions: azcore.ClientOptions{
Cloud: config.Environment,
},
}
credentials, err = azidentity.NewDefaultAzureCredential(&options)
if err != nil {
return nil, fmt.Errorf("azuredns: %w", err)
}
credentials, err := getCredentials(config)
if err != nil {
return nil, fmt.Errorf("azuredns: Unable to retrieve valid credentials: %w", err)
}
if config.SubscriptionID == "" {
@ -153,6 +144,37 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return &DNSProvider{provider: dnsProvider}, nil
}
func getCredentials(config *Config) (azcore.TokenCredential, error) {
clientOptions := azcore.ClientOptions{Cloud: config.Environment}
switch strings.ToLower(config.AuthMethod) {
case "env":
if config.ClientID != "" && config.ClientSecret != "" && config.TenantID != "" {
return azidentity.NewClientSecretCredential(config.TenantID, config.ClientID, config.ClientSecret,
&azidentity.ClientSecretCredentialOptions{ClientOptions: clientOptions})
}
return azidentity.NewEnvironmentCredential(&azidentity.EnvironmentCredentialOptions{ClientOptions: clientOptions})
case "wli":
return azidentity.NewWorkloadIdentityCredential(&azidentity.WorkloadIdentityCredentialOptions{ClientOptions: clientOptions})
case "msi":
cred, err := azidentity.NewManagedIdentityCredential(&azidentity.ManagedIdentityCredentialOptions{ClientOptions: clientOptions})
if err != nil {
return nil, err
}
return &timeoutTokenCredential{cred: cred, timeout: config.AuthMSITimeout}, nil
case "cli":
return azidentity.NewAzureCLICredential(nil)
default:
return azidentity.NewDefaultAzureCredential(&azidentity.DefaultAzureCredentialOptions{ClientOptions: clientOptions})
}
}
// Timeout returns the timeout and interval to use when checking for DNS propagation.
// Adjusting here to cope with spikes in propagation times.
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
@ -169,6 +191,31 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return d.provider.CleanUp(domain, token, keyAuth)
}
// timeoutTokenCredential wraps a TokenCredential to add a timeout.
type timeoutTokenCredential struct {
cred azcore.TokenCredential
timeout time.Duration
}
// GetToken implements the azcore.TokenCredential interface.
func (w *timeoutTokenCredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
if w.timeout <= 0 {
return w.cred.GetToken(ctx, opts)
}
ctxTimeout, cancel := context.WithTimeout(ctx, w.timeout)
defer cancel()
tk, err := w.cred.GetToken(ctxTimeout, opts)
if ce := ctxTimeout.Err(); errors.Is(ce, context.DeadlineExceeded) {
return tk, azidentity.NewCredentialUnavailableError("managed identity timed out")
}
w.timeout = 0
return tk, err
}
func deref[T string | int | int32 | int64](v *T) T {
if v == nil {
var zero T

View file

@ -45,19 +45,59 @@ lego --domains example.com --email your_example@email.com --dns azuredns run
Additional = '''
## Description
Azure Credentials are automatically detected in the following locations and prioritized in the following order:
Several authentication methods can be used to authenticate against Azure DNS API.
### Default Azure Credentials (default option)
Default Azure Credentials automatically detects in the following locations and prioritized in the following order:
1. Environment variables for client secret: `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, `AZURE_CLIENT_SECRET`
2. Environment variables for client certificate: `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, `AZURE_CLIENT_CERTIFICATE_PATH`
3. Workload identity for resources hosted in Azure environment (see below)
4. Shared credentials file (defaults to `~/.azure`), used by Azure CLI
4. Shared credentials (defaults to `~/.azure` folder), used by Azure CLI
Link:
- [Azure Authentication](https://learn.microsoft.com/en-us/azure/developer/go/azure-sdk-authentication)
### Environment variables
#### Client secret
The Azure Credentials can be configured using the following environment variables:
* AZURE_CLIENT_ID = "Client ID"
* AZURE_CLIENT_SECRET = "Client secret"
* AZURE_TENANT_ID = "Tenant ID"
This authentication method can be specificaly used by setting the `AZURE_AUTH_METHOD` environment variable to `env`.
#### Client certificate
The Azure Credentials can be configured using the following environment variables:
* AZURE_CLIENT_ID = "Client ID"
* AZURE_CLIENT_CERTIFICATE_PATH = "Client certificate path"
* AZURE_TENANT_ID = "Tenant ID"
This authentication method can be specificaly used by setting the `AZURE_AUTH_METHOD` environment variable to `env`.
### Workload identity
#### Azure Managed Identity
Workload identity allows workloads running Azure Kubernetes Services (AKS) clusters to authenticate as an Azure AD application identity using federated credentials.
This must be configured in kubernetes workload deployment in one hand and on the Azure AD application registration in the other hand.
Here is a summary of the steps to follow to use it :
* create a `ServiceAccount` resource, add following annotations to reference the targeted Azure AD application registration : `azure.workload.identity/client-id` and `azure.workload.identity/tenant-id`.
* on the `Deployment` resource you must reference the previous `ServiceAccount` and add the following label : `azure.workload.identity/use: "true"`.
* create a fedreated credentials of type `Kubernetes accessing Azure resources`, add the cluster issuer URL and add the namespace and name of your kubernetes service account.
Link :
- [Azure AD Workload identity](https://azure.github.io/azure-workload-identity/docs/topics/service-account-labels-and-annotations.html)
This authentication method can be specificaly used by setting the `AZURE_AUTH_METHOD` environment variable to `wli`.
### Azure Managed Identity
#### Azure Managed Identity (with Azure workload)
The Azure Managed Identity service allows linking Azure AD identities to Azure resources, without needing to manually manage client IDs and secrets.
@ -87,6 +127,11 @@ az role assignment create \
--scope "/subscriptions/${AZURE_SUBSCRIPTION_ID}/resourceGroups/${AZURE_RESOURCE_GROUP}/providers/Microsoft.Network/dnszones/${AZURE_DNS_ZONE}/TXT/${AZ_RECORD_SET}"
```
A timeout wrapper is configured for this authentication method.
The duraction can be configured by setting the `AZURE_AUTH_MSI_TIMEOUT`.
The default timeout is 2 seconds.
This authentication method can be specificaly used by setting the `AZURE_AUTH_METHOD` environment variable to `msi`.
#### Azure Managed Identity (with Azure Arc)
The Azure Arc agent provides the ability to use a Managed Identity on resources hosted outside of Azure
@ -95,22 +140,21 @@ The Azure Arc agent provides the ability to use a Managed Identity on resources
While the upstream `azidentity` SDK will try to automatically identify and use the Azure Arc metadata service,
if you get `azuredns: DefaultAzureCredential: failed to acquire a token.` error messages,
you may need to set the environment variables:
* `IMDS_ENDPOINT=http://localhost:40342`
* `IDENTITY_ENDPOINT=http://localhost:40342/metadata/identity/oauth2/token`
* `IMDS_ENDPOINT=http://localhost:40342`
* `IDENTITY_ENDPOINT=http://localhost:40342/metadata/identity/oauth2/token`
#### Workload identity for AKS
A timeout wrapper is configured for this authentication method.
The duraction can be configured by setting the `AZURE_AUTH_MSI_TIMEOUT`.
The default timeout is 2 seconds.
This authentication method can be specificaly used by setting the `AZURE_AUTH_METHOD` environment variable to `msi`.
Workload identity allows workloads running Azure Kubernetes Services (AKS) clusters to authenticate as an Azure AD application identity using federated credentials.
### Azure CLI
This must be configured in kubernetes workload deployment in one hand and on the Azure AD application registration in the other hand.
The Azure CLI is a command-line tool provided by Microsoft to interact with Azure resources.
It provides an easy way to authenticate by simply running `az login` command.
The generated token will be cached by default in the `~/.azure` folder.
Here is a summary of the steps to follow to use it :
* create a `ServiceAccount` resource, add following annotations to reference the targeted Azure AD application registration : `azure.workload.identity/client-id` and `azure.workload.identity/tenant-id`.
* on the `Deployment` resource you must reference the previous `ServiceAccount` and add the following label : `azure.workload.identity/use: "true"`.
* create a fedreated credentials of type `Kubernetes accessing Azure resources`, add the cluster issuer URL and add the namespace and name of your kubernetes service account.
Link :
- [Azure AD Workload identity](https://azure.github.io/azure-workload-identity/docs/topics/service-account-labels-and-annotations.html)
This authentication method can be specificaly used by setting the `AZURE_AUTH_METHOD` environment variable to `cli`.
'''
@ -119,12 +163,15 @@ Link :
AZURE_CLIENT_ID = "Client ID"
AZURE_CLIENT_SECRET = "Client secret"
AZURE_TENANT_ID = "Tenant ID"
AZURE_CLIENT_CERTIFICATE_PATH = "Client certificate path"
AZURE_SUBSCRIPTION_ID = "DNS zone subscription ID"
AZURE_RESOURCE_GROUP = "DNS zone resource group"
[Configuration.Additional]
AZURE_ENVIRONMENT = "Azure environment, one of: public, usgovernment, and china"
AZURE_PRIVATE_ZONE = "Set to true to use Azure Private DNS Zones and not public"
AZURE_ZONE_NAME = "Zone name to use inside Azure DNS service to add the TXT record in"
AZURE_AUTH_METHOD = "Specify which authentication method to use"
AZURE_AUTH_MSI_TIMEOUT = "Managed Identity timeout duration"
AZURE_TTL = "The TTL of the TXT record used for the DNS challenge"
AZURE_POLLING_INTERVAL = "Time between DNS propagation check"
AZURE_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation"