Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

custom Azure Active Directory Authority Host #4210

Merged
merged 4 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/tutorials/azure.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ The following fields are used:
* `aadClientID` and `aadClientSecret` are associated with the Service Principal. This is only used with Service Principal method documented in the next section.
* `useManagedIdentityExtension` - this is set to `true` if you use either AKS Kubelet Identity or AAD Pod Identities methods documented in the next section.
* `userAssignedIdentityID` - this contains the client id from the Managed identitty when using the AAD Pod Identities method documented in the next setion.
* `activeDirectoryAuthorityHost` - this contains the uri to overwrite the default provided AAD Endpoint. This is useful for providing additional support where the endpoint is not available in the default cloud config from the [azure-sdk-for-go](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud#pkg-variables).
* `useWorkloadIdentityExtension` - this is set to `true` if you use Workload Identity method documented in the next section.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really required I guess, but it would be super great if we could add documentation for the cloud field


The Azure DNS provider expects, by default, that the configuration file is at `/etc/kubernetes/azure.json`. This can be overridden with the `--azure-config-file` option when starting ExternalDNS.
Expand Down
4 changes: 2 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,9 +253,9 @@ func main() {
}
p, err = awssd.NewAWSSDProvider(domainFilter, cfg.AWSZoneType, cfg.DryRun, cfg.AWSSDServiceCleanup, cfg.TXTOwnerID, sd.New(awsSession))
case "azure-dns", "azure":
p, err = azure.NewAzureProvider(cfg.AzureConfigFile, domainFilter, zoneNameFilter, zoneIDFilter, cfg.AzureSubscriptionID, cfg.AzureResourceGroup, cfg.AzureUserAssignedIdentityClientID, cfg.DryRun)
p, err = azure.NewAzureProvider(cfg.AzureConfigFile, domainFilter, zoneNameFilter, zoneIDFilter, cfg.AzureSubscriptionID, cfg.AzureResourceGroup, cfg.AzureUserAssignedIdentityClientID, cfg.AzureActiveDirectoryAuthorityHost, cfg.DryRun)
case "azure-private-dns":
p, err = azure.NewAzurePrivateDNSProvider(cfg.AzureConfigFile, domainFilter, zoneIDFilter, cfg.AzureSubscriptionID, cfg.AzureResourceGroup, cfg.AzureUserAssignedIdentityClientID, cfg.DryRun)
p, err = azure.NewAzurePrivateDNSProvider(cfg.AzureConfigFile, domainFilter, zoneIDFilter, cfg.AzureSubscriptionID, cfg.AzureResourceGroup, cfg.AzureUserAssignedIdentityClientID, cfg.AzureActiveDirectoryAuthorityHost, cfg.DryRun)
case "bluecat":
p, err = bluecat.NewBluecatProvider(cfg.BluecatConfigFile, cfg.BluecatDNSConfiguration, cfg.BluecatDNSServerName, cfg.BluecatDNSDeployType, cfg.BluecatDNSView, cfg.BluecatGatewayHost, cfg.BluecatRootZone, cfg.TXTPrefix, cfg.TXTSuffix, domainFilter, zoneIDFilter, cfg.DryRun, cfg.BluecatSkipTLSVerify)
case "vinyldns":
Expand Down
1 change: 1 addition & 0 deletions pkg/apis/externaldns/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ type Config struct {
AzureResourceGroup string
AzureSubscriptionID string
AzureUserAssignedIdentityClientID string
AzureActiveDirectoryAuthorityHost string
BluecatDNSConfiguration string
BluecatConfigFile string
BluecatDNSView string
Expand Down
6 changes: 4 additions & 2 deletions provider/azure/azure.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,16 @@ type AzureProvider struct {
dryRun bool
resourceGroup string
userAssignedIdentityClientID string
activeDirectoryAuthorityHost string
zonesClient ZonesClient
recordSetsClient RecordSetsClient
}

// NewAzureProvider creates a new Azure provider.
//
// Returns the provider or an error if a provider could not be created.
func NewAzureProvider(configFile string, domainFilter endpoint.DomainFilter, zoneNameFilter endpoint.DomainFilter, zoneIDFilter provider.ZoneIDFilter, subscriptionID string, resourceGroup string, userAssignedIdentityClientID string, dryRun bool) (*AzureProvider, error) {
cfg, err := getConfig(configFile, subscriptionID, resourceGroup, userAssignedIdentityClientID)
func NewAzureProvider(configFile string, domainFilter endpoint.DomainFilter, zoneNameFilter endpoint.DomainFilter, zoneIDFilter provider.ZoneIDFilter, subscriptionID string, resourceGroup string, userAssignedIdentityClientID string, activeDirectoryAuthorityHost string, dryRun bool) (*AzureProvider, error) {
cfg, err := getConfig(configFile, subscriptionID, resourceGroup, userAssignedIdentityClientID, activeDirectoryAuthorityHost)
if err != nil {
return nil, fmt.Errorf("failed to read Azure config file '%s': %v", configFile, err)
}
Expand All @@ -90,6 +91,7 @@ func NewAzureProvider(configFile string, domainFilter endpoint.DomainFilter, zon
dryRun: dryRun,
resourceGroup: cfg.ResourceGroup,
userAssignedIdentityClientID: cfg.UserAssignedIdentityID,
activeDirectoryAuthorityHost: cfg.ActiveDirectoryAuthorityHost,
zonesClient: zonesClient,
recordSetsClient: recordSetsClient,
}, nil
Expand Down
6 changes: 4 additions & 2 deletions provider/azure/azure_private_dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,16 @@ type AzurePrivateDNSProvider struct {
dryRun bool
resourceGroup string
userAssignedIdentityClientID string
activeDirectoryAuthorityHost string
zonesClient PrivateZonesClient
recordSetsClient PrivateRecordSetsClient
}

// NewAzurePrivateDNSProvider creates a new Azure Private DNS provider.
//
// Returns the provider or an error if a provider could not be created.
func NewAzurePrivateDNSProvider(configFile string, domainFilter endpoint.DomainFilter, zoneIDFilter provider.ZoneIDFilter, subscriptionID string, resourceGroup string, userAssignedIdentityClientID string, dryRun bool) (*AzurePrivateDNSProvider, error) {
cfg, err := getConfig(configFile, subscriptionID, resourceGroup, userAssignedIdentityClientID)
func NewAzurePrivateDNSProvider(configFile string, domainFilter endpoint.DomainFilter, zoneIDFilter provider.ZoneIDFilter, subscriptionID string, resourceGroup string, userAssignedIdentityClientID string, activeDirectoryAuthorityHost string, dryRun bool) (*AzurePrivateDNSProvider, error) {
cfg, err := getConfig(configFile, subscriptionID, resourceGroup, userAssignedIdentityClientID, activeDirectoryAuthorityHost)
if err != nil {
return nil, fmt.Errorf("failed to read Azure config file '%s': %v", configFile, err)
}
Expand All @@ -83,6 +84,7 @@ func NewAzurePrivateDNSProvider(configFile string, domainFilter endpoint.DomainF
dryRun: dryRun,
resourceGroup: cfg.ResourceGroup,
userAssignedIdentityClientID: cfg.UserAssignedIdentityID,
activeDirectoryAuthorityHost: cfg.ActiveDirectoryAuthorityHost,
zonesClient: zonesClient,
recordSetsClient: recordSetsClient,
}, nil
Expand Down
15 changes: 9 additions & 6 deletions provider/azure/azure_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,20 +222,21 @@ func createMockRecordSetMultiWithTTL(name, recordType string, ttl int64, values
}

// newMockedAzureProvider creates an AzureProvider comprising the mocked clients for zones and recordsets
func newMockedAzureProvider(domainFilter endpoint.DomainFilter, zoneNameFilter endpoint.DomainFilter, zoneIDFilter provider.ZoneIDFilter, dryRun bool, resourceGroup string, userAssignedIdentityClientID string, zones []*dns.Zone, recordSets []*dns.RecordSet) (*AzureProvider, error) {
func newMockedAzureProvider(domainFilter endpoint.DomainFilter, zoneNameFilter endpoint.DomainFilter, zoneIDFilter provider.ZoneIDFilter, dryRun bool, resourceGroup string, userAssignedIdentityClientID string, activeDirectoryAuthorityHost string, zones []*dns.Zone, recordSets []*dns.RecordSet) (*AzureProvider, error) {
zonesClient := newMockZonesClient(zones)
recordSetsClient := newMockRecordSetsClient(recordSets)
return newAzureProvider(domainFilter, zoneNameFilter, zoneIDFilter, dryRun, resourceGroup, userAssignedIdentityClientID, &zonesClient, &recordSetsClient), nil
return newAzureProvider(domainFilter, zoneNameFilter, zoneIDFilter, dryRun, resourceGroup, userAssignedIdentityClientID, activeDirectoryAuthorityHost, &zonesClient, &recordSetsClient), nil
}

func newAzureProvider(domainFilter endpoint.DomainFilter, zoneNameFilter endpoint.DomainFilter, zoneIDFilter provider.ZoneIDFilter, dryRun bool, resourceGroup string, userAssignedIdentityClientID string, zonesClient ZonesClient, recordsClient RecordSetsClient) *AzureProvider {
func newAzureProvider(domainFilter endpoint.DomainFilter, zoneNameFilter endpoint.DomainFilter, zoneIDFilter provider.ZoneIDFilter, dryRun bool, resourceGroup string, userAssignedIdentityClientID string, activeDirectoryAuthorityHost string, zonesClient ZonesClient, recordsClient RecordSetsClient) *AzureProvider {
return &AzureProvider{
domainFilter: domainFilter,
zoneNameFilter: zoneNameFilter,
zoneIDFilter: zoneIDFilter,
dryRun: dryRun,
resourceGroup: resourceGroup,
userAssignedIdentityClientID: userAssignedIdentityClientID,
activeDirectoryAuthorityHost: activeDirectoryAuthorityHost,
zonesClient: zonesClient,
recordSetsClient: recordsClient,
}
Expand All @@ -246,7 +247,7 @@ func validateAzureEndpoints(t *testing.T, endpoints []*endpoint.Endpoint, expect
}

func TestAzureRecord(t *testing.T) {
provider, err := newMockedAzureProvider(endpoint.NewDomainFilter([]string{"example.com"}), endpoint.NewDomainFilter([]string{}), provider.NewZoneIDFilter([]string{""}), true, "k8s", "",
provider, err := newMockedAzureProvider(endpoint.NewDomainFilter([]string{"example.com"}), endpoint.NewDomainFilter([]string{}), provider.NewZoneIDFilter([]string{""}), true, "k8s", "", "",
[]*dns.Zone{
createMockZone("example.com", "/dnszones/example.com"),
},
Expand Down Expand Up @@ -286,7 +287,7 @@ func TestAzureRecord(t *testing.T) {
}

func TestAzureMultiRecord(t *testing.T) {
provider, err := newMockedAzureProvider(endpoint.NewDomainFilter([]string{"example.com"}), endpoint.NewDomainFilter([]string{}), provider.NewZoneIDFilter([]string{""}), true, "k8s", "",
provider, err := newMockedAzureProvider(endpoint.NewDomainFilter([]string{"example.com"}), endpoint.NewDomainFilter([]string{}), provider.NewZoneIDFilter([]string{""}), true, "k8s", "", "",
[]*dns.Zone{
createMockZone("example.com", "/dnszones/example.com"),
},
Expand Down Expand Up @@ -381,6 +382,7 @@ func testAzureApplyChangesInternal(t *testing.T, dryRun bool, client RecordSetsC
dryRun,
"group",
"",
"",
&zonesClient,
client,
)
Expand Down Expand Up @@ -440,7 +442,7 @@ func testAzureApplyChangesInternal(t *testing.T, dryRun bool, client RecordSetsC
}

func TestAzureNameFilter(t *testing.T) {
provider, err := newMockedAzureProvider(endpoint.NewDomainFilter([]string{"nginx.example.com"}), endpoint.NewDomainFilter([]string{"example.com"}), provider.NewZoneIDFilter([]string{""}), true, "k8s", "",
provider, err := newMockedAzureProvider(endpoint.NewDomainFilter([]string{"nginx.example.com"}), endpoint.NewDomainFilter([]string{"example.com"}), provider.NewZoneIDFilter([]string{""}), true, "k8s", "", "",
[]*dns.Zone{
createMockZone("example.com", "/dnszones/example.com"),
},
Expand Down Expand Up @@ -506,6 +508,7 @@ func testAzureApplyChangesInternalZoneName(t *testing.T, dryRun bool, client Rec
dryRun,
"group",
"",
"",
&zonesClient,
client,
)
Expand Down
7 changes: 6 additions & 1 deletion provider/azure/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ type config struct {
UseManagedIdentityExtension bool `json:"useManagedIdentityExtension" yaml:"useManagedIdentityExtension"`
UseWorkloadIdentityExtension bool `json:"useWorkloadIdentityExtension" yaml:"useWorkloadIdentityExtension"`
UserAssignedIdentityID string `json:"userAssignedIdentityID" yaml:"userAssignedIdentityID"`
ActiveDirectoryAuthorityHost string `json:"activeDirectoryAuthorityHost" yaml:"activeDirectoryAuthorityHost"`
}

func getConfig(configFile, subscriptionID, resourceGroup, userAssignedIdentityClientID string) (*config, error) {
func getConfig(configFile, subscriptionID, resourceGroup, userAssignedIdentityClientID, activeDirectoryAuthorityHost string) (*config, error) {
contents, err := os.ReadFile(configFile)
if err != nil {
return nil, fmt.Errorf("failed to read Azure config file '%s': %v", configFile, err)
Expand All @@ -65,6 +66,10 @@ func getConfig(configFile, subscriptionID, resourceGroup, userAssignedIdentityCl
if userAssignedIdentityClientID != "" {
cfg.UserAssignedIdentityID = userAssignedIdentityClientID
}
// If activeDirectoryAuthorityHost is provided explicitly, override existing one in config file
if activeDirectoryAuthorityHost != "" {
cfg.ActiveDirectoryAuthorityHost = activeDirectoryAuthorityHost
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing I thought about: what happens if cloud is set to a non-empty value (e.g. "AZURECHINACLOUD") but activeDirectoryAuthorityHost is also set to some non-empty value. I think we should return an error in that case

return cfg, nil
}

Expand Down
3 changes: 2 additions & 1 deletion provider/azure/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,11 @@ func TestGetCloudConfiguration(t *testing.T) {
func TestOverrideConfiguration(t *testing.T) {
_, filename, _, _ := runtime.Caller(0)
configFile := path.Join(path.Dir(filename), "config_test.json")
cfg, err := getConfig(configFile, "subscription-override", "rg-override", "")
cfg, err := getConfig(configFile, "subscription-override", "rg-override", "", "aad-endpoint-override")
if err != nil {
t.Errorf("got unexpected err %v", err)
}
assert.Equal(t, cfg.SubscriptionID, "subscription-override")
assert.Equal(t, cfg.ResourceGroup, "rg-override")
assert.Equal(t, cfg.ActiveDirectoryAuthorityHost, "aad-endpoint-override")
}
Loading