mirror of
https://github.com/kubernetes-sigs/external-dns.git
synced 2026-05-04 22:26:11 +02:00
Merge pull request #578 from r7vme/azure_msi_support
Add Azure MSI support
This commit is contained in:
commit
6c05028f89
10
Gopkg.lock
generated
10
Gopkg.lock
generated
@ -24,8 +24,8 @@
|
||||
"autorest/date",
|
||||
"autorest/to"
|
||||
]
|
||||
revision = "58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d"
|
||||
version = "v8.0.0"
|
||||
revision = "aa2a4534ab680e938d933870f58f23f77e0e208e"
|
||||
version = "v10.9.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/PuerkitoBio/purell"
|
||||
@ -136,8 +136,8 @@
|
||||
[[projects]]
|
||||
name = "github.com/dgrijalva/jwt-go"
|
||||
packages = ["."]
|
||||
revision = "d2709f9f1f31ebcda9651b03077758c1f3a0018c"
|
||||
version = "v3.0.0"
|
||||
revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e"
|
||||
version = "v3.2.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/digitalocean/godo"
|
||||
@ -648,6 +648,6 @@
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "d5deea43eb04e9ef3a6ecb3589b91c149e092505f66905baa01c67379776d231"
|
||||
inputs-digest = "8d8869be9b64013c9670a0ba7f6a6eeaf31941fcfbdfc13f0fa57626e767c517"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
||||
@ -10,7 +10,7 @@ ignored = ["github.com/kubernetes/repo-infra/kazel"]
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/Azure/go-autorest"
|
||||
version = "~8.0.0"
|
||||
version = "~10.9.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/alecthomas/kingpin"
|
||||
|
||||
@ -103,6 +103,16 @@ If the Kubernetes cluster is not hosted by Azure Container Services and you stil
|
||||
"resourceGroup": "MyDnsResourceGroup",
|
||||
}
|
||||
```
|
||||
If [Azure Managed Service Identity (MSI)](https://docs.microsoft.com/en-us/azure/active-directory/managed-service-identity/overview) is enabled for virtual machines, then there is no need to create separate service principal. The contents of `azure.json` should be similar to this:
|
||||
```
|
||||
{
|
||||
"tenantId": "AzureAD tenant Id",
|
||||
"subscriptionId": "Id",
|
||||
"resourceGroup": "MyDnsResourceGroup",
|
||||
"useManagedIdentityExtension": true,
|
||||
}
|
||||
```
|
||||
|
||||
If you have all the information necessary: create a file called azure.json containing the json structure above and substitute the values. Otherwise create a service principal as previously shown before creating the Kubernetes secret.
|
||||
|
||||
Then add the secret to the Kubernetes cluster before continuing:
|
||||
|
||||
@ -40,13 +40,14 @@ const (
|
||||
)
|
||||
|
||||
type config struct {
|
||||
Cloud string `json:"cloud" yaml:"cloud"`
|
||||
TenantID string `json:"tenantId" yaml:"tenantId"`
|
||||
SubscriptionID string `json:"subscriptionId" yaml:"subscriptionId"`
|
||||
ResourceGroup string `json:"resourceGroup" yaml:"resourceGroup"`
|
||||
Location string `json:"location" yaml:"location"`
|
||||
ClientID string `json:"aadClientId" yaml:"aadClientId"`
|
||||
ClientSecret string `json:"aadClientSecret" yaml:"aadClientSecret"`
|
||||
Cloud string `json:"cloud" yaml:"cloud"`
|
||||
TenantID string `json:"tenantId" yaml:"tenantId"`
|
||||
SubscriptionID string `json:"subscriptionId" yaml:"subscriptionId"`
|
||||
ResourceGroup string `json:"resourceGroup" yaml:"resourceGroup"`
|
||||
Location string `json:"location" yaml:"location"`
|
||||
ClientID string `json:"aadClientId" yaml:"aadClientId"`
|
||||
ClientSecret string `json:"aadClientSecret" yaml:"aadClientSecret"`
|
||||
UseManagedIdentityExtension bool `json:"useManagedIdentityExtension" yaml:"useManagedIdentityExtension"`
|
||||
}
|
||||
|
||||
// ZonesClient is an interface of dns.ZoneClient that can be stubbed for testing.
|
||||
@ -102,14 +103,9 @@ func NewAzureProvider(configFile string, domainFilter DomainFilter, zoneIDFilter
|
||||
}
|
||||
}
|
||||
|
||||
oauthConfig, err := adal.NewOAuthConfig(environment.ActiveDirectoryEndpoint, cfg.TenantID)
|
||||
token, err := getAccessToken(cfg, environment)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to retrieve OAuth config: %v", err)
|
||||
}
|
||||
|
||||
token, err := adal.NewServicePrincipalToken(*oauthConfig, cfg.ClientID, cfg.ClientSecret, environment.ResourceManagerEndpoint)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create service principal token: %v", err)
|
||||
return nil, fmt.Errorf("failed to get token: %v", err)
|
||||
}
|
||||
|
||||
zonesClient := dns.NewZonesClientWithBaseURI(environment.ResourceManagerEndpoint, cfg.SubscriptionID)
|
||||
@ -128,6 +124,41 @@ func NewAzureProvider(configFile string, domainFilter DomainFilter, zoneIDFilter
|
||||
return provider, nil
|
||||
}
|
||||
|
||||
// getAccessToken retrieves Azure API access token.
|
||||
func getAccessToken(cfg config, environment azure.Environment) (*adal.ServicePrincipalToken, error) {
|
||||
// Try to retrive token with MSI.
|
||||
if cfg.UseManagedIdentityExtension {
|
||||
log.Info("Using managed identity extension to retrieve access token for Azure API.")
|
||||
msiEndpoint, err := adal.GetMSIVMEndpoint()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get the managed service identity endpoint: %v", err)
|
||||
}
|
||||
|
||||
token, err := adal.NewServicePrincipalTokenFromMSI(msiEndpoint, environment.ServiceManagementEndpoint)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create the managed service identity token: %v", err)
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
||||
// Try to retrieve token with service principal credentials.
|
||||
if len(cfg.ClientID) > 0 && len(cfg.ClientSecret) > 0 {
|
||||
log.Info("Using client_id+client_secret to retrieve access token for Azure API.")
|
||||
oauthConfig, err := adal.NewOAuthConfig(environment.ActiveDirectoryEndpoint, cfg.TenantID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to retrieve OAuth config: %v", err)
|
||||
}
|
||||
|
||||
token, err := adal.NewServicePrincipalToken(*oauthConfig, cfg.ClientID, cfg.ClientSecret, environment.ResourceManagerEndpoint)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create service principal token: %v", err)
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("no credentials provided for Azure API")
|
||||
}
|
||||
|
||||
// Records gets the current records.
|
||||
//
|
||||
// Returns the current records or an error if the operation failed.
|
||||
|
||||
@ -21,6 +21,7 @@ import (
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/arm/dns"
|
||||
"github.com/Azure/go-autorest/autorest"
|
||||
"github.com/Azure/go-autorest/autorest/azure"
|
||||
"github.com/Azure/go-autorest/autorest/to"
|
||||
|
||||
"github.com/kubernetes-incubator/external-dns/endpoint"
|
||||
@ -302,3 +303,18 @@ func testAzureApplyChangesInternal(t *testing.T, dryRun bool, client RecordsClie
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAzureGetAccessToken(t *testing.T) {
|
||||
env := azure.PublicCloud
|
||||
cfg := config{
|
||||
ClientID: "",
|
||||
ClientSecret: "",
|
||||
TenantID: "",
|
||||
UseManagedIdentityExtension: false,
|
||||
}
|
||||
|
||||
_, err := getAccessToken(cfg, env)
|
||||
if err == nil {
|
||||
t.Fatalf("expected to fail, but got no error")
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user