mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-01-05 13:05:17 +00:00
azure: support aad-pod-identity auth when using restic (#2602)
Signed-off-by: Steve Kriss <krisss@vmware.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2017, 2019 the Velero contributors.
|
||||
Copyright 2017, 2019, 2020 the Velero contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -21,42 +21,48 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
storagemgmt "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2018-02-01/storage"
|
||||
"github.com/Azure/go-autorest/autorest"
|
||||
"github.com/Azure/go-autorest/autorest/adal"
|
||||
storagemgmt "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage"
|
||||
"github.com/Azure/go-autorest/autorest/azure"
|
||||
"github.com/Azure/go-autorest/autorest/azure/auth"
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
tenantIDEnvVar = "AZURE_TENANT_ID"
|
||||
subscriptionIDEnvVar = "AZURE_SUBSCRIPTION_ID"
|
||||
clientIDEnvVar = "AZURE_CLIENT_ID"
|
||||
clientSecretEnvVar = "AZURE_CLIENT_SECRET"
|
||||
cloudNameEnvVar = "AZURE_CLOUD_NAME"
|
||||
|
||||
resourceGroupConfigKey = "resourceGroup"
|
||||
|
||||
storageAccountConfigKey = "storageAccount"
|
||||
storageAccountKeyEnvVarConfigKey = "storageAccountKeyEnvVar"
|
||||
subscriptionIdConfigKey = "subscriptionId"
|
||||
subscriptionIDConfigKey = "subscriptionId"
|
||||
)
|
||||
|
||||
// getSubscriptionID gets the subscription ID from the 'config' map if it contains
|
||||
// it, else from the AZURE_SUBSCRIPTION_ID environment variable.
|
||||
func getSubscriptionID(config map[string]string) string {
|
||||
if subscriptionID := config[subscriptionIDConfigKey]; subscriptionID != "" {
|
||||
return subscriptionID
|
||||
}
|
||||
|
||||
return os.Getenv(subscriptionIDEnvVar)
|
||||
}
|
||||
|
||||
func getStorageAccountKey(config map[string]string) (string, *azure.Environment, error) {
|
||||
// load environment vars from $AZURE_CREDENTIALS_FILE, if it exists
|
||||
if err := loadEnv(); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
// 1. Get Azure cloud from AZURE_CLOUD_NAME, if it exists. If the env var does not
|
||||
// Get Azure cloud from AZURE_CLOUD_NAME, if it exists. If the env var does not
|
||||
// exist, parseAzureEnvironment will return azure.PublicCloud.
|
||||
env, err := parseAzureEnvironment(os.Getenv(cloudNameEnvVar))
|
||||
if err != nil {
|
||||
return "", nil, errors.Wrap(err, "unable to parse azure cloud name environment variable")
|
||||
}
|
||||
|
||||
// 2. get storage key from secret using key config[storageAccountKeyEnvVarConfigKey]. If the config does not
|
||||
// Get storage key from secret using key config[storageAccountKeyEnvVarConfigKey]. If the config does not
|
||||
// exist, continue obtaining it using API
|
||||
if secretKeyEnvVar := config[storageAccountKeyEnvVarConfigKey]; secretKeyEnvVar != "" {
|
||||
storageKey := os.Getenv(secretKeyEnvVar)
|
||||
@@ -67,35 +73,33 @@ func getStorageAccountKey(config map[string]string) (string, *azure.Environment,
|
||||
return storageKey, env, nil
|
||||
}
|
||||
|
||||
// 3. we need AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_SUBSCRIPTION_ID
|
||||
envVars, err := getRequiredValues(os.Getenv, tenantIDEnvVar, clientIDEnvVar, clientSecretEnvVar, subscriptionIDEnvVar)
|
||||
if err != nil {
|
||||
return "", nil, errors.Wrap(err, "unable to get all required environment variables")
|
||||
// get subscription ID from object store config or AZURE_SUBSCRIPTION_ID environment variable
|
||||
subscriptionID := getSubscriptionID(config)
|
||||
if subscriptionID == "" {
|
||||
return "", nil, errors.New("azure subscription ID not found in object store's config or in environment variable")
|
||||
}
|
||||
|
||||
// 4. check whether a different subscription ID was set for backups in config["subscriptionId"]
|
||||
subscriptionId := envVars[subscriptionIDEnvVar]
|
||||
if val := config[subscriptionIdConfigKey]; val != "" {
|
||||
subscriptionId = val
|
||||
}
|
||||
|
||||
// 5. we need config["resourceGroup"], config["storageAccount"]
|
||||
// we need config["resourceGroup"], config["storageAccount"]
|
||||
if _, err := getRequiredValues(mapLookup(config), resourceGroupConfigKey, storageAccountConfigKey); err != nil {
|
||||
return "", env, errors.Wrap(err, "unable to get all required config values")
|
||||
}
|
||||
|
||||
// 6. get SPT
|
||||
spt, err := newServicePrincipalToken(envVars[tenantIDEnvVar], envVars[clientIDEnvVar], envVars[clientSecretEnvVar], env)
|
||||
// get authorizer from environment in the following order:
|
||||
// 1. client credentials (AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET)
|
||||
// 2. client certificate (AZURE_CERTIFICATE_PATH, AZURE_CERTIFICATE_PASSWORD)
|
||||
// 3. username and password (AZURE_USERNAME, AZURE_PASSWORD)
|
||||
// 4. MSI (managed service identity)
|
||||
authorizer, err := auth.NewAuthorizerFromEnvironment()
|
||||
if err != nil {
|
||||
return "", env, errors.Wrap(err, "error getting service principal token")
|
||||
return "", nil, errors.Wrap(err, "error getting authorizer from environment")
|
||||
}
|
||||
|
||||
// 7. get storageAccountsClient
|
||||
storageAccountsClient := storagemgmt.NewAccountsClientWithBaseURI(env.ResourceManagerEndpoint, subscriptionId)
|
||||
storageAccountsClient.Authorizer = autorest.NewBearerAuthorizer(spt)
|
||||
// get storageAccountsClient
|
||||
storageAccountsClient := storagemgmt.NewAccountsClientWithBaseURI(env.ResourceManagerEndpoint, subscriptionID)
|
||||
storageAccountsClient.Authorizer = authorizer
|
||||
|
||||
// 8. get storage key
|
||||
res, err := storageAccountsClient.ListKeys(context.TODO(), config[resourceGroupConfigKey], config[storageAccountConfigKey])
|
||||
// get storage key
|
||||
res, err := storageAccountsClient.ListKeys(context.TODO(), config[resourceGroupConfigKey], config[storageAccountConfigKey], storagemgmt.Kerb)
|
||||
if err != nil {
|
||||
return "", env, errors.WithStack(err)
|
||||
}
|
||||
@@ -169,15 +173,6 @@ func parseAzureEnvironment(cloudName string) (*azure.Environment, error) {
|
||||
return &env, errors.WithStack(err)
|
||||
}
|
||||
|
||||
func newServicePrincipalToken(tenantID, clientID, clientSecret string, env *azure.Environment) (*adal.ServicePrincipalToken, error) {
|
||||
oauthConfig, err := adal.NewOAuthConfig(env.ActiveDirectoryEndpoint, tenantID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error getting OAuthConfig")
|
||||
}
|
||||
|
||||
return adal.NewServicePrincipalToken(*oauthConfig, clientID, clientSecret, env.ResourceManagerEndpoint)
|
||||
}
|
||||
|
||||
func getRequiredValues(getValue func(string) string, keys ...string) (map[string]string, error) {
|
||||
missing := []string{}
|
||||
results := map[string]string{}
|
||||
|
||||
Reference in New Issue
Block a user