mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2025-02-23 07:03:01 +08:00
FEATURE: Enable OIDC support for Azure DNS provider (#3398)
Co-authored-by: PE Team <platformengineers@newday.co.uk> Co-authored-by: Jeffrey Cafferata <jeffrey@jcid.nl>
This commit is contained in:
parent
4f5655e510
commit
15a22ae00a
2 changed files with 133 additions and 14 deletions
|
@ -1,7 +1,56 @@
|
|||
## Configuration
|
||||
|
||||
To use this provider, add an entry to `creds.json` with `TYPE` set to `AZURE_DNS`
|
||||
along with the API credentials.
|
||||
To use this provider, add an entry to `creds.json` with `TYPE` set to `AZURE_DNS`, along with the necessary credentials. The provider supports three authentication methods:
|
||||
|
||||
1. **DefaultAzureCredential (Recommended)**: Simplifies authentication by leveraging Azure's credential chain (e.g., environment variables, managed identities, Azure CLI, etc.).
|
||||
2. **Client ID and Secret**: Provides backward compatibility for users who prefer this method.
|
||||
3. **OIDC (InteractiveBrowserCredential)**: Allows interactive login via the browser for specific scenarios.
|
||||
|
||||
### Example Configurations
|
||||
|
||||
#### **DefaultAzureCredential (Recommended)**
|
||||
|
||||
This method does not require explicit credentials in `creds.json` and leverages Azure's default authentication chain:
|
||||
- Managed Identity (if running in Azure)
|
||||
- Environment variables
|
||||
- Azure CLI credentials
|
||||
|
||||
No additional setup is required in `creds.json`:
|
||||
|
||||
{% code title="creds.json" %}
|
||||
```json
|
||||
{
|
||||
"azuredns_main": {
|
||||
"TYPE": "AZURE_DNS",
|
||||
"SubscriptionID": "AZURE_SUBSCRIPTION_ID",
|
||||
"ResourceGroup": "AZURE_RESOURCE_GROUP"
|
||||
}
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
You can also use environment variables:
|
||||
|
||||
```shell
|
||||
export AZURE_SUBSCRIPTION_ID=XXXXXXXXX
|
||||
export AZURE_RESOURCE_GROUP=YYYYYYYYY
|
||||
```
|
||||
|
||||
{% code title="creds.json" %}
|
||||
```json
|
||||
{
|
||||
"azuredns_main": {
|
||||
"TYPE": "AZURE_DNS",
|
||||
"SubscriptionID": "$AZURE_SUBSCRIPTION_ID",
|
||||
"ResourceGroup": "$AZURE_RESOURCE_GROUP"
|
||||
}
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
#### **Client ID and Secret (Backward Compatibility)**
|
||||
|
||||
To use the client ID and secret-based authentication:
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -45,7 +94,46 @@ export AZURE_CLIENT_SECRET=BBBBBBBBB
|
|||
```
|
||||
{% endcode %}
|
||||
|
||||
NOTE: The ResourceGroup is case sensitive.
|
||||
#### **OIDC (Interactive Browser Authentication)**
|
||||
|
||||
To enable OIDC for interactive login:
|
||||
|
||||
{% code title="creds.json" %}
|
||||
```json
|
||||
{
|
||||
"azuredns_main": {
|
||||
"TYPE": "AZURE_DNS",
|
||||
"SubscriptionID": "AZURE_SUBSCRIPTION_ID",
|
||||
"ResourceGroup": "AZURE_RESOURCE_GROUP",
|
||||
"TenantID": "AZURE_TENANT_ID",
|
||||
"UseOIDC": "true"
|
||||
}
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
+You can also use environment variables:
|
||||
```shell
|
||||
export AZURE_SUBSCRIPTION_ID=XXXXXXXXX
|
||||
export AZURE_RESOURCE_GROUP=YYYYYYYYY
|
||||
export AZURE_TENANT_ID=ZZZZZZZZ
|
||||
export UseOIDC=true
|
||||
```
|
||||
|
||||
{% code title="creds.json" %}
|
||||
```json
|
||||
{
|
||||
"azuredns_main": {
|
||||
"TYPE": "AZURE_DNS",
|
||||
"SubscriptionID": "$AZURE_SUBSCRIPTION_ID",
|
||||
"ResourceGroup": "$AZURE_RESOURCE_GROUP",
|
||||
"TenantID": "$AZURE_TENANT_ID",
|
||||
"UseOIDC": "$UseOIDC"
|
||||
}
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
|
||||
## Metadata
|
||||
This provider does not recognize any special metadata fields unique to Azure DNS.
|
||||
|
|
|
@ -26,24 +26,53 @@ type azurednsProvider struct {
|
|||
subscriptionID *string
|
||||
}
|
||||
|
||||
// Modified `newAzureDNSDsp` to maintain backward compatibility with the new OIDC support.
|
||||
func newAzureDNSDsp(conf map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) {
|
||||
return newAzureDNS(conf, metadata)
|
||||
}
|
||||
|
||||
// Updated function to prioritize DefaultAzureCredential and fallback to OIDC or client-secret-based methods.
|
||||
func newAzureDNS(m map[string]string, _ json.RawMessage) (*azurednsProvider, error) {
|
||||
subID, rg := m["SubscriptionID"], m["ResourceGroup"]
|
||||
clientID, clientSecret, tenantID := m["ClientID"], m["ClientSecret"], m["TenantID"]
|
||||
credential, authErr := aauth.NewClientSecretCredential(tenantID, clientID, clientSecret, nil)
|
||||
if authErr != nil {
|
||||
return nil, authErr
|
||||
useOIDC := m["UseOIDC"] == "true"
|
||||
|
||||
var credential azcore.TokenCredential
|
||||
var authErr error
|
||||
|
||||
// Authentication Logic
|
||||
if useOIDC {
|
||||
// OIDC Authentication with `InteractiveBrowserCredential`
|
||||
oidcCredentialOpts := aauth.InteractiveBrowserCredentialOptions{
|
||||
TenantID: tenantID,
|
||||
}
|
||||
credential, authErr = aauth.NewInteractiveBrowserCredential(&oidcCredentialOpts)
|
||||
if authErr != nil {
|
||||
return nil, fmt.Errorf("failed to create OIDC credential: %w", authErr)
|
||||
}
|
||||
} else if clientID != "" && clientSecret != "" {
|
||||
// Client ID and Secret-based Authentication
|
||||
credential, authErr = aauth.NewClientSecretCredential(tenantID, clientID, clientSecret, nil)
|
||||
if authErr != nil {
|
||||
return nil, fmt.Errorf("failed to create Client Secret credential: %w", authErr)
|
||||
}
|
||||
} else {
|
||||
// Default Azure Credential as the default mechanism
|
||||
credential, authErr = aauth.NewDefaultAzureCredential(nil)
|
||||
if authErr != nil {
|
||||
return nil, fmt.Errorf("failed to create Default Azure credential: %w", authErr)
|
||||
}
|
||||
}
|
||||
zonesClient, zoneErr := adns.NewZonesClient(subID, credential, nil)
|
||||
if zoneErr != nil {
|
||||
return nil, zoneErr
|
||||
|
||||
// Create DNS clients using the selected credential
|
||||
zonesClient, err := adns.NewZonesClient(subID, credential, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create zones client: %w", err)
|
||||
}
|
||||
recordsClient, recordErr := adns.NewRecordSetsClient(subID, credential, nil)
|
||||
if recordErr != nil {
|
||||
return nil, recordErr
|
||||
|
||||
recordsClient, err := adns.NewRecordSetsClient(subID, credential, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create records client: %w", err)
|
||||
}
|
||||
|
||||
api := &azurednsProvider{
|
||||
|
@ -52,10 +81,12 @@ func newAzureDNS(m map[string]string, _ json.RawMessage) (*azurednsProvider, err
|
|||
resourceGroup: to.StringPtr(rg),
|
||||
subscriptionID: to.StringPtr(subID),
|
||||
}
|
||||
err := api.getZones()
|
||||
if err != nil {
|
||||
|
||||
// Initialize zones
|
||||
if err := api.getZones(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return api, nil
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue