backend/azurerm: support for custom resource manager endpoints (#19460)

* backend/azurerm: removing the `arm_` prefix from keys

* removing the deprecated fields test because the deprecation makes it fail

* authentication: support for custom resource manager endpoints

* Adding debug prefixes to the log statements
This commit is contained in:
Tom Harvey 2018-11-26 14:42:16 +01:00 committed by GitHub
parent 26509550e4
commit 6d4f702467
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 128 additions and 47 deletions

View File

@ -32,10 +32,11 @@ type ArmClient struct {
}
func buildArmClient(config BackendConfig) (*ArmClient, error) {
env, err := authentication.DetermineEnvironment(config.Environment)
env, err := buildArmEnvironment(config)
if err != nil {
return nil, err
}
client := ArmClient{
environment: *env,
resourceGroupName: config.ResourceGroupName,
@ -59,6 +60,7 @@ func buildArmClient(config BackendConfig) (*ArmClient, error) {
ClientSecret: config.ClientSecret,
SubscriptionID: config.SubscriptionID,
TenantID: config.TenantID,
CustomResourceManagerEndpoint: config.CustomResourceManagerEndpoint,
Environment: config.Environment,
MsiEndpoint: config.MsiEndpoint,
@ -77,7 +79,7 @@ func buildArmClient(config BackendConfig) (*ArmClient, error) {
return nil, err
}
auth, err := armConfig.GetAuthorizationToken(oauthConfig, env.ResourceManagerEndpoint)
auth, err := armConfig.GetAuthorizationToken(oauthConfig, env.TokenAudience)
if err != nil {
return nil, err
}
@ -93,9 +95,19 @@ func buildArmClient(config BackendConfig) (*ArmClient, error) {
return &client, nil
}
func buildArmEnvironment(config BackendConfig) (*azure.Environment, error) {
if config.CustomResourceManagerEndpoint != "" {
log.Printf("[DEBUG] Loading Environment from Endpoint %q", config.CustomResourceManagerEndpoint)
return authentication.LoadEnvironmentFromUrl(config.CustomResourceManagerEndpoint)
}
log.Printf("[DEBUG] Loading Environment %q", config.Environment)
return authentication.DetermineEnvironment(config.Environment)
}
func (c ArmClient) getBlobClient(ctx context.Context) (*storage.BlobStorageClient, error) {
if c.accessKey != "" {
log.Printf("Building the Blob Client from an Access Token")
log.Printf("[DEBUG] Building the Blob Client from an Access Token")
storageClient, err := storage.NewBasicClientOnSovereignCloud(c.storageAccountName, c.accessKey, c.environment)
if err != nil {
return nil, fmt.Errorf("Error creating storage client for storage account %q: %s", c.storageAccountName, err)
@ -105,7 +117,7 @@ func (c ArmClient) getBlobClient(ctx context.Context) (*storage.BlobStorageClien
}
if c.sasToken != "" {
log.Printf("Building the Blob Client from a SAS Token")
log.Printf("[DEBUG] Building the Blob Client from a SAS Token")
token := strings.TrimPrefix(c.sasToken, "?")
uri, err := url.ParseQuery(token)
if err != nil {
@ -117,7 +129,7 @@ func (c ArmClient) getBlobClient(ctx context.Context) (*storage.BlobStorageClien
return &client, nil
}
log.Printf("Building the Blob Client from an Access Token (using user credentials)")
log.Printf("[DEBUG] Building the Blob Client from an Access Token (using user credentials)")
keys, err := c.storageAccountsClient.ListKeys(ctx, c.resourceGroupName, c.storageAccountName)
if err != nil {
return nil, fmt.Errorf("Error retrieving keys for Storage Account %q: %s", c.storageAccountName, err)

View File

@ -99,6 +99,13 @@ func New() backend.Backend {
DefaultFunc: schema.EnvDefaultFunc("ARM_MSI_ENDPOINT", ""),
},
"endpoint": {
Type: schema.TypeString,
Optional: true,
Description: "A custom Endpoint used to access the Azure Resource Manager API's.",
DefaultFunc: schema.EnvDefaultFunc("ARM_ENDPOINT", ""),
},
// Deprecated fields
"arm_client_id": {
Type: schema.TypeString,
@ -127,8 +134,6 @@ func New() backend.Backend {
Description: "The Tenant ID.",
Deprecated: "`arm_tenant_id` has been replaced by `tenant_id`",
},
// TODO: support for custom resource manager endpoints
},
}
@ -154,6 +159,7 @@ type BackendConfig struct {
AccessKey string
ClientID string
ClientSecret string
CustomResourceManagerEndpoint string
Environment string
MsiEndpoint string
ResourceGroupName string
@ -183,6 +189,7 @@ func (b *Backend) configure(ctx context.Context) error {
AccessKey: data.Get("access_key").(string),
ClientID: clientId,
ClientSecret: clientSecret,
CustomResourceManagerEndpoint: data.Get("endpoint").(string),
Environment: data.Get("environment").(string),
MsiEndpoint: data.Get("msi_endpoint").(string),
ResourceGroupName: data.Get("resource_group_name").(string),

View File

@ -55,6 +55,7 @@ func TestBackendAccessKeyBasic(t *testing.T) {
"key": res.storageKeyName,
"access_key": res.storageAccountAccessKey,
"environment": os.Getenv("ARM_ENVIRONMENT"),
"endpoint": os.Getenv("ARM_ENDPOINT"),
})).(*Backend)
backend.TestBackendStates(t, b)
@ -82,6 +83,7 @@ func TestBackendManagedServiceIdentityBasic(t *testing.T) {
"subscription_id": os.Getenv("ARM_SUBSCRIPTION_ID"),
"tenant_id": os.Getenv("ARM_TENANT_ID"),
"environment": os.Getenv("ARM_ENVIRONMENT"),
"endpoint": os.Getenv("ARM_ENDPOINT"),
})).(*Backend)
backend.TestBackendStates(t, b)
@ -111,6 +113,7 @@ func TestBackendSASTokenBasic(t *testing.T) {
"key": res.storageKeyName,
"sas_token": *sasToken,
"environment": os.Getenv("ARM_ENVIRONMENT"),
"endpoint": os.Getenv("ARM_ENDPOINT"),
})).(*Backend)
backend.TestBackendStates(t, b)
@ -139,6 +142,43 @@ func TestBackendServicePrincipalBasic(t *testing.T) {
"client_id": os.Getenv("ARM_CLIENT_ID"),
"client_secret": os.Getenv("ARM_CLIENT_SECRET"),
"environment": os.Getenv("ARM_ENVIRONMENT"),
"endpoint": os.Getenv("ARM_ENDPOINT"),
})).(*Backend)
backend.TestBackendStates(t, b)
}
func TestBackendServicePrincipalCustomEndpoint(t *testing.T) {
testAccAzureBackend(t)
// this is only applicable for Azure Stack.
endpoint := os.Getenv("ARM_ENDPOINT")
if endpoint == "" {
t.Skip("Skipping as ARM_ENDPOINT isn't configured")
}
rs := acctest.RandString(4)
res := testResourceNames(rs, "testState")
armClient := buildTestClient(t, res)
ctx := context.TODO()
err := armClient.buildTestResources(ctx, &res)
defer armClient.destroyTestResources(ctx, res)
if err != nil {
t.Fatalf("Error creating Test Resources: %q", err)
}
b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
"storage_account_name": res.storageAccountName,
"container_name": res.storageContainerName,
"key": res.storageKeyName,
"resource_group_name": res.resourceGroup,
"subscription_id": os.Getenv("ARM_SUBSCRIPTION_ID"),
"tenant_id": os.Getenv("ARM_TENANT_ID"),
"client_id": os.Getenv("ARM_CLIENT_ID"),
"client_secret": os.Getenv("ARM_CLIENT_SECRET"),
"environment": os.Getenv("ARM_ENVIRONMENT"),
"endpoint": endpoint,
})).(*Backend)
backend.TestBackendStates(t, b)
@ -163,6 +203,7 @@ func TestBackendAccessKeyLocked(t *testing.T) {
"key": res.storageKeyName,
"access_key": res.storageAccountAccessKey,
"environment": os.Getenv("ARM_ENVIRONMENT"),
"endpoint": os.Getenv("ARM_ENDPOINT"),
})).(*Backend)
b2 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
@ -171,6 +212,7 @@ func TestBackendAccessKeyLocked(t *testing.T) {
"key": res.storageKeyName,
"access_key": res.storageAccountAccessKey,
"environment": os.Getenv("ARM_ENVIRONMENT"),
"endpoint": os.Getenv("ARM_ENDPOINT"),
})).(*Backend)
backend.TestBackendStateLocks(t, b1, b2)
@ -200,6 +242,7 @@ func TestBackendServicePrincipalLocked(t *testing.T) {
"client_id": os.Getenv("ARM_CLIENT_ID"),
"client_secret": os.Getenv("ARM_CLIENT_SECRET"),
"environment": os.Getenv("ARM_ENVIRONMENT"),
"endpoint": os.Getenv("ARM_ENDPOINT"),
})).(*Backend)
b2 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
@ -212,6 +255,7 @@ func TestBackendServicePrincipalLocked(t *testing.T) {
"client_id": os.Getenv("ARM_CLIENT_ID"),
"client_secret": os.Getenv("ARM_CLIENT_SECRET"),
"environment": os.Getenv("ARM_ENVIRONMENT"),
"endpoint": os.Getenv("ARM_ENDPOINT"),
})).(*Backend)
backend.TestBackendStateLocks(t, b1, b2)

View File

@ -35,6 +35,7 @@ func TestRemoteClientAccessKeyBasic(t *testing.T) {
"key": res.storageKeyName,
"access_key": res.storageAccountAccessKey,
"environment": os.Getenv("ARM_ENVIRONMENT"),
"endpoint": os.Getenv("ARM_ENDPOINT"),
})).(*Backend)
state, err := b.StateMgr(backend.DefaultStateName)
@ -67,6 +68,7 @@ func TestRemoteClientManagedServiceIdentityBasic(t *testing.T) {
"subscription_id": os.Getenv("ARM_SUBSCRIPTION_ID"),
"tenant_id": os.Getenv("ARM_TENANT_ID"),
"environment": os.Getenv("ARM_ENVIRONMENT"),
"endpoint": os.Getenv("ARM_ENDPOINT"),
})).(*Backend)
state, err := b.StateMgr(backend.DefaultStateName)
@ -101,6 +103,7 @@ func TestRemoteClientSasTokenBasic(t *testing.T) {
"key": res.storageKeyName,
"sas_token": *sasToken,
"environment": os.Getenv("ARM_ENVIRONMENT"),
"endpoint": os.Getenv("ARM_ENDPOINT"),
})).(*Backend)
state, err := b.StateMgr(backend.DefaultStateName)
@ -134,6 +137,7 @@ func TestRemoteClientServicePrincipalBasic(t *testing.T) {
"client_id": os.Getenv("ARM_CLIENT_ID"),
"client_secret": os.Getenv("ARM_CLIENT_SECRET"),
"environment": os.Getenv("ARM_ENVIRONMENT"),
"endpoint": os.Getenv("ARM_ENDPOINT"),
})).(*Backend)
state, err := b.StateMgr(backend.DefaultStateName)
@ -163,6 +167,7 @@ func TestRemoteClientAccessKeyLocks(t *testing.T) {
"key": res.storageKeyName,
"access_key": res.storageAccountAccessKey,
"environment": os.Getenv("ARM_ENVIRONMENT"),
"endpoint": os.Getenv("ARM_ENDPOINT"),
})).(*Backend)
b2 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
@ -171,6 +176,7 @@ func TestRemoteClientAccessKeyLocks(t *testing.T) {
"key": res.storageKeyName,
"access_key": res.storageAccountAccessKey,
"environment": os.Getenv("ARM_ENVIRONMENT"),
"endpoint": os.Getenv("ARM_ENDPOINT"),
})).(*Backend)
s1, err := b1.StateMgr(backend.DefaultStateName)
@ -209,6 +215,7 @@ func TestRemoteClientServicePrincipalLocks(t *testing.T) {
"client_id": os.Getenv("ARM_CLIENT_ID"),
"client_secret": os.Getenv("ARM_CLIENT_SECRET"),
"environment": os.Getenv("ARM_ENVIRONMENT"),
"endpoint": os.Getenv("ARM_ENDPOINT"),
})).(*Backend)
b2 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
@ -221,6 +228,7 @@ func TestRemoteClientServicePrincipalLocks(t *testing.T) {
"client_id": os.Getenv("ARM_CLIENT_ID"),
"client_secret": os.Getenv("ARM_CLIENT_SECRET"),
"environment": os.Getenv("ARM_ENVIRONMENT"),
"endpoint": os.Getenv("ARM_ENDPOINT"),
})).(*Backend)
s1, err := b1.StateMgr(backend.DefaultStateName)

View File

@ -16,7 +16,8 @@ import (
)
const (
sasSignedVersion = "2017-07-29"
// required for Azure Stack
sasSignedVersion = "2015-04-05"
)
// verify that we are doing ACC tests or the Azure tests specifically
@ -45,9 +46,6 @@ func buildTestClient(t *testing.T, res resourceNames) *ArmClient {
msiEnabled := strings.EqualFold(os.Getenv("ARM_USE_MSI"), "true")
environment := os.Getenv("ARM_ENVIRONMENT")
// location isn't used in this method, but is in the other test methods
location := os.Getenv("ARM_LOCATION")
hasCredentials := (clientID != "" && clientSecret != "") || msiEnabled
if !hasCredentials {
t.Fatal("Azure credentials missing or incomplete")
@ -65,15 +63,21 @@ func buildTestClient(t *testing.T, res resourceNames) *ArmClient {
t.Fatalf("Missing ARM_ENVIRONMENT")
}
// location isn't used in this method, but is in the other test methods
location := os.Getenv("ARM_LOCATION")
if location == "" {
t.Fatalf("Missing ARM_LOCATION")
}
// Endpoint is optional (only for Stack)
endpoint := os.Getenv("ARM_ENDPOINT")
armClient, err := buildArmClient(BackendConfig{
SubscriptionID: subscriptionID,
TenantID: tenantID,
ClientID: clientID,
ClientSecret: clientSecret,
CustomResourceManagerEndpoint: endpoint,
Environment: environment,
ResourceGroupName: res.resourceGroup,
StorageAccountName: res.storageAccountName,
@ -99,7 +103,9 @@ func buildSasToken(accountName, accessKey string) (*string, error) {
signedVersion := sasSignedVersion
utcNow := time.Now().UTC()
startDate := utcNow.Format(time.RFC3339)
// account for servers being up to 5 minutes out
startDate := utcNow.Add(time.Minute * -5).Format(time.RFC3339)
endDate := utcNow.Add(time.Hour * 24).Format(time.RFC3339)
sasToken, err := sasStorage.ComputeSASToken(accountName, accessKey, permissions, services, resourceTypes,

View File

@ -152,6 +152,10 @@ The following configuration options are supported:
* `environment` - (Optional) The Azure Environment which should be used. This can also be sourced from the `ARM_ENVIRONMENT` environment variable. Possible values are `public`, `china`, `german`, `stack` and `usgovernment`. Defaults to `public`.
* `endpoint` - (Optional) The Custom Endpoint for Azure Resource Manager. This can also be sourced from the `ARM_ENDPOINT` environment variable.
~> **NOTE:** An `endpoint` should only be configured when using Azure Stack.
---
When authenticating using the Managed Service Identity (MSI) - the following fields are also supported: