cmd/hub/azure/auth.go (168 lines of code) (raw):

// Copyright (c) 2022 EPAM Systems, Inc. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. package azure import ( "context" "fmt" "log" "os" "strings" storageManagement "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2018-11-01/storage" "github.com/Azure/go-autorest/autorest" "github.com/Azure/go-autorest/autorest/azure" "github.com/Azure/go-autorest/autorest/azure/auth" "github.com/epam/hubctl/cmd/hub/config" "github.com/epam/hubctl/cmd/hub/util" ) const storageKeyHelp = "Please set AZURE_STORAGE_KEY environment variable, or AZURE_SUBSCRIPTION_ID, AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET" var ( defaultSettings map[string]string defaultEnvironment *azure.Environment ) func environment(values map[string]string) (*azure.Environment, error) { if name, exist := values[auth.EnvironmentName]; !exist || name == "" { return &azure.PublicCloud, nil } else { env, err := azure.EnvironmentFromName(name) if err != nil { return nil, err } return &env, nil } } func settings() (map[string]string, *azure.Environment, error) { if defaultSettings != nil && defaultEnvironment != nil { return defaultSettings, defaultEnvironment, nil } var values map[string]string var env *azure.Environment set, err := auth.GetSettingsFromEnvironment() if err != nil { file, err2 := auth.GetSettingsFromFile() if err2 != nil { return nil, nil, fmt.Errorf("Errors retrieving Azure settings: %v", util.Errors2(err, err2)) } values = file.Values env, err = environment(values) if err != nil { return nil, nil, err } } else { values = set.Values _env := set.Environment env = &_env } if config.Trace { log.Printf("Azure settings:\n\t%v", values) } defaultSettings = values defaultEnvironment = env return values, env, nil } func keyvaultResource(env *azure.Environment) string { return env.KeyVaultEndpoint } func serviceManagementResource(env *azure.Environment) string { return env.ServiceManagementEndpoint } func authorizer(resourcePick func(env *azure.Environment) string) (autorest.Authorizer, error) { var err error var errs []error var authz autorest.Authorizer resource := resourcePick(&azure.PublicCloud) _, env, err := settings() if err != nil && env != nil { resource = resourcePick(env) } resource = strings.TrimSuffix(resource, "/") if authLocation := os.Getenv("AZURE_AUTH_LOCATION"); config.AzureCredentialsFile != "" || authLocation != "" { if config.AzureCredentialsFile != "" { os.Setenv("AZURE_AUTH_LOCATION", config.AzureCredentialsFile) } authz, err = auth.NewAuthorizerFromFile(resource) if err != nil { errs = append(errs, err) } } else { authz, err = auth.NewAuthorizerFromCLIWithResource(resource) if err != nil { errs = append(errs, err) authz, err = auth.NewAuthorizerFromEnvironmentWithResource(resource) if err != nil { errs = append(errs, err) authz, err = auth.NewAuthorizerFromCLIWithResource(resource) if err != nil { errs = append(errs, err) } } } } if len(errs) > 0 { err = fmt.Errorf("Unable to create Azure authorizer: %v", util.Errors2(errs...)) } else { err = nil } if err != nil && authz != nil && config.Debug { log.Printf("Errors encountered while creating Azure authorizer: %v", err) } return authz, err } func storageManagementClient() (*storageManagement.AccountsClient, error) { authz, err := authorizer(serviceManagementResource) if err != nil && authz == nil { return nil, err } sets, _, _ := settings() subscriptionId := sets[auth.SubscriptionID] client := storageManagement.NewAccountsClient(subscriptionId) client.Authorizer = authz return &client, nil } func resourceGroup() (string, error) { osEnvVar := "AZURE_RESOURCE_GROUP_NAME" name := os.Getenv(osEnvVar) if name != "" { return name, nil } hardcoded := "hubctl" if config.Verbose { util.WarnOnce("Using hardcoded `%s` Azure resource group; set %s to override", hardcoded, osEnvVar) } return hardcoded, nil } func storageKeyFromApi(account string) (string, error) { mgmt, err := storageManagementClient() if err != nil { return "", err } resourceGroupName, err := resourceGroup() if err != nil { return "", err } ctx, cancel := context.WithTimeout(context.Background(), storageTimeout) defer cancel() resp, err := mgmt.ListKeys(ctx, resourceGroupName, account) if err != nil { return "", fmt.Errorf("Error listing storage account `%s` access keys: %v;\n\t%s", account, err, storageKeyHelp) } if keys := resp.Keys; keys != nil { if len(*keys) > 0 { for _, keyEntry := range *keys { if key := keyEntry.Value; key != nil && *key != "" { return *key, nil } } } } return "", fmt.Errorf("No storage account `%s` access keys found;\n\t%s", account, storageKeyHelp) } func storageKey(account string) (string, error) { vars := []string{"AZURE_STORAGE_ACCESS_KEY", "AZURE_STORAGE_KEY", "ARM_ACCESS_KEY"} for _, v := range vars { key := os.Getenv(v) if key != "" { return key, nil } } return storageKeyFromApi(account) }