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

Support Azure Stack dynamic environments #85432

Merged
merged 5 commits into from Nov 25, 2019
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/credentialprovider/azure/azure_credentials.go
Expand Up @@ -144,7 +144,7 @@ func (a *acrProvider) loadConfig(rdr io.Reader) error {
klog.Errorf("Failed to load azure credential file: %v", err)
}

a.environment, err = auth.ParseAzureEnvironment(a.config.Cloud)
a.environment, err = auth.ParseAzureEnvironment(a.config.Cloud, a.config.ResourceManagerEndpoint, a.config.IdentitySystem)
if err != nil {
return err
}
Expand Down
44 changes: 37 additions & 7 deletions staging/src/k8s.io/legacy-cloud-providers/azure/auth/azure_auth.go
Expand Up @@ -30,11 +30,14 @@ import (
"k8s.io/klog"
)

const (
// ADFSIdentitySystem is the override value for tenantID on Azure Stack clouds.
ADFSIdentitySystem = "adfs"
)

var (
// ErrorNoAuth indicates that no credentials are provided.
ErrorNoAuth = fmt.Errorf("no credentials provided for Azure cloud provider")
// ADFSIdentitySystem indicates value of tenantId for ADFS on Azure Stack.
ADFSIdentitySystem = "ADFS"
)

// AzureAuthConfig holds auth related part of cloud config
Expand All @@ -59,15 +62,19 @@ type AzureAuthConfig struct {
UserAssignedIdentityID string `json:"userAssignedIdentityID,omitempty" yaml:"userAssignedIdentityID,omitempty"`
// The ID of the Azure Subscription that the cluster is deployed in
SubscriptionID string `json:"subscriptionId,omitempty" yaml:"subscriptionId,omitempty"`
// Identity system value for the deployment. This gets populate for Azure Stack case.
// IdentitySystem indicates the identity provider. Relevant only to hybrid clouds (Azure Stack).
// Allowed values are 'azure_ad' (default), 'adfs'.
IdentitySystem string `json:"identitySystem,omitempty" yaml:"identitySystem,omitempty"`
// ResourceManagerEndpoint is the cloud's resource manager endpoint. If set, cloud provider queries this endpoint
// in order to generate an autorest.Environment instance instead of using one of the pre-defined Environments.
ResourceManagerEndpoint string `json:"resourceManagerEndpoint,omitempty" yaml:"resourceManagerEndpoint,omitempty"`
}

// GetServicePrincipalToken creates a new service principal token based on the configuration
func GetServicePrincipalToken(config *AzureAuthConfig, env *azure.Environment) (*adal.ServicePrincipalToken, error) {
var tenantID string
if strings.EqualFold(config.IdentitySystem, ADFSIdentitySystem) {
tenantID = "adfs"
tenantID = ADFSIdentitySystem
} else {
tenantID = config.TenantID
}
Expand Down Expand Up @@ -125,13 +132,24 @@ func GetServicePrincipalToken(config *AzureAuthConfig, env *azure.Environment) (
return nil, ErrorNoAuth
}

// ParseAzureEnvironment returns azure environment by name
func ParseAzureEnvironment(cloudName string) (*azure.Environment, error) {
// ParseAzureEnvironment returns the azure environment.
// If 'resourceManagerEndpoint' is set, the environment is computed by quering the cloud's resource manager endpoint.
// Otherwise, a pre-defined Environment is looked up by name.
func ParseAzureEnvironment(cloudName, resourceManagerEndpoint, identitySystem string) (*azure.Environment, error) {
var env azure.Environment
var err error
if cloudName == "" {
if resourceManagerEndpoint != "" {
klog.V(4).Infof("Loading environment from resource manager endpoint: %s", resourceManagerEndpoint)
nameOverride := azure.OverrideProperty{Key: azure.EnvironmentName, Value: cloudName}
env, err = azure.EnvironmentFromURL(resourceManagerEndpoint, nameOverride)
if err == nil {
azureStackOverrides(&env, resourceManagerEndpoint, identitySystem)
}
} else if cloudName == "" {
klog.V(4).Info("Using public cloud environment")
env = azure.PublicCloud
} else {
klog.V(4).Infof("Using %s environment", cloudName)
env, err = azure.EnvironmentFromName(cloudName)
}
return &env, err
Expand All @@ -151,3 +169,15 @@ func decodePkcs12(pkcs []byte, password string) (*x509.Certificate, *rsa.Private

return certificate, rsaPrivateKey, nil
}

// azureStackOverrides ensures that the Environment matches what AKSe currently generates for Azure Stack
func azureStackOverrides(env *azure.Environment, resourceManagerEndpoint, identitySystem string) {
env.ManagementPortalURL = strings.Replace(resourceManagerEndpoint, "https://management.", "https://portal.", -1)
env.ServiceManagementEndpoint = env.TokenAudience
env.ResourceManagerVMDNSSuffix = strings.Replace(resourceManagerEndpoint, "https://management.", "cloudapp.", -1)
env.ResourceManagerVMDNSSuffix = strings.TrimSuffix(env.ResourceManagerVMDNSSuffix, "/")
if strings.EqualFold(identitySystem, ADFSIdentitySystem) {
env.ActiveDirectoryEndpoint = strings.TrimSuffix(env.ActiveDirectoryEndpoint, "/")
env.ActiveDirectoryEndpoint = strings.TrimSuffix(env.ActiveDirectoryEndpoint, "adfs")
}
}
2 changes: 1 addition & 1 deletion staging/src/k8s.io/legacy-cloud-providers/azure/azure.go
Expand Up @@ -325,7 +325,7 @@ func (az *Cloud) InitializeCloudFromConfig(config *Config, fromSecret bool) erro
}
}

env, err := auth.ParseAzureEnvironment(config.Cloud)
env, err := auth.ParseAzureEnvironment(config.Cloud, config.ResourceManagerEndpoint, config.IdentitySystem)
if err != nil {
return err
}
Expand Down