2017-03-30 16:33:54 +02:00
|
|
|
package azure
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/hashicorp/terraform/backend"
|
|
|
|
"github.com/hashicorp/terraform/helper/schema"
|
|
|
|
)
|
|
|
|
|
2018-11-21 22:06:03 +01:00
|
|
|
// New creates a new backend for Azure remote state.
|
2017-03-30 16:33:54 +02:00
|
|
|
func New() backend.Backend {
|
|
|
|
s := &schema.Backend{
|
|
|
|
Schema: map[string]*schema.Schema{
|
2017-09-04 13:04:11 +02:00
|
|
|
"storage_account_name": {
|
2017-03-30 16:33:54 +02:00
|
|
|
Type: schema.TypeString,
|
|
|
|
Required: true,
|
|
|
|
Description: "The name of the storage account.",
|
|
|
|
},
|
|
|
|
|
2017-09-04 13:04:11 +02:00
|
|
|
"container_name": {
|
2017-03-30 16:33:54 +02:00
|
|
|
Type: schema.TypeString,
|
|
|
|
Required: true,
|
|
|
|
Description: "The container name.",
|
|
|
|
},
|
|
|
|
|
2017-09-04 13:04:11 +02:00
|
|
|
"key": {
|
2017-03-30 16:33:54 +02:00
|
|
|
Type: schema.TypeString,
|
|
|
|
Required: true,
|
|
|
|
Description: "The blob key.",
|
|
|
|
},
|
|
|
|
|
2017-09-04 13:04:11 +02:00
|
|
|
"environment": {
|
2017-03-30 16:33:54 +02:00
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
Description: "The Azure cloud environment.",
|
2018-11-21 22:06:03 +01:00
|
|
|
DefaultFunc: schema.EnvDefaultFunc("ARM_ENVIRONMENT", "public"),
|
2017-03-30 16:33:54 +02:00
|
|
|
},
|
|
|
|
|
2017-09-04 13:04:11 +02:00
|
|
|
"access_key": {
|
2017-03-30 16:33:54 +02:00
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
Description: "The access key.",
|
|
|
|
DefaultFunc: schema.EnvDefaultFunc("ARM_ACCESS_KEY", ""),
|
|
|
|
},
|
|
|
|
|
2018-11-22 18:02:33 +01:00
|
|
|
"sas_token": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
Description: "A SAS Token used to interact with the Blob Storage Account.",
|
|
|
|
DefaultFunc: schema.EnvDefaultFunc("ARM_SAS_TOKEN", ""),
|
|
|
|
},
|
|
|
|
|
2020-06-25 11:50:16 +02:00
|
|
|
"snapshot": {
|
|
|
|
Type: schema.TypeBool,
|
|
|
|
Optional: true,
|
|
|
|
Description: "Enable/Disable automatic blob snapshotting",
|
|
|
|
DefaultFunc: schema.EnvDefaultFunc("ARM_SNAPSHOT", false),
|
|
|
|
},
|
|
|
|
|
2017-09-04 13:04:11 +02:00
|
|
|
"resource_group_name": {
|
2017-03-30 16:33:54 +02:00
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
Description: "The resource group name.",
|
|
|
|
},
|
|
|
|
|
2018-11-26 11:19:43 +01:00
|
|
|
"client_id": {
|
2017-03-30 16:33:54 +02:00
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
Description: "The Client ID.",
|
|
|
|
DefaultFunc: schema.EnvDefaultFunc("ARM_CLIENT_ID", ""),
|
|
|
|
},
|
|
|
|
|
2020-08-07 11:58:33 +02:00
|
|
|
"endpoint": {
|
2017-03-30 16:33:54 +02:00
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
2020-08-07 11:58:33 +02:00
|
|
|
Description: "A custom Endpoint used to access the Azure Resource Manager API's.",
|
|
|
|
DefaultFunc: schema.EnvDefaultFunc("ARM_ENDPOINT", ""),
|
2017-03-30 16:33:54 +02:00
|
|
|
},
|
|
|
|
|
2018-11-26 11:19:43 +01:00
|
|
|
"subscription_id": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
Description: "The Subscription ID.",
|
|
|
|
DefaultFunc: schema.EnvDefaultFunc("ARM_SUBSCRIPTION_ID", ""),
|
|
|
|
},
|
|
|
|
|
|
|
|
"tenant_id": {
|
2017-03-30 16:33:54 +02:00
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
Description: "The Tenant ID.",
|
|
|
|
DefaultFunc: schema.EnvDefaultFunc("ARM_TENANT_ID", ""),
|
|
|
|
},
|
2018-11-21 22:06:03 +01:00
|
|
|
|
2020-08-07 11:58:33 +02:00
|
|
|
// Service Principal (Client Certificate) specific
|
|
|
|
"client_certificate_password": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
Description: "The password associated with the Client Certificate specified in `client_certificate_path`",
|
|
|
|
DefaultFunc: schema.EnvDefaultFunc("ARM_CLIENT_CERTIFICATE_PASSWORD", ""),
|
|
|
|
},
|
|
|
|
"client_certificate_path": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
Description: "The path to the PFX file used as the Client Certificate when authenticating as a Service Principal",
|
|
|
|
DefaultFunc: schema.EnvDefaultFunc("ARM_CLIENT_CERTIFICATE_PATH", ""),
|
|
|
|
},
|
|
|
|
|
|
|
|
// Service Principal (Client Secret) specific
|
|
|
|
"client_secret": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
Description: "The Client Secret.",
|
|
|
|
DefaultFunc: schema.EnvDefaultFunc("ARM_CLIENT_SECRET", ""),
|
|
|
|
},
|
|
|
|
|
|
|
|
// Managed Service Identity specific
|
2018-11-22 16:52:27 +01:00
|
|
|
"use_msi": {
|
|
|
|
Type: schema.TypeBool,
|
|
|
|
Optional: true,
|
|
|
|
Description: "Should Managed Service Identity be used?.",
|
|
|
|
DefaultFunc: schema.EnvDefaultFunc("ARM_USE_MSI", false),
|
|
|
|
},
|
|
|
|
"msi_endpoint": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
Description: "The Managed Service Identity Endpoint.",
|
|
|
|
DefaultFunc: schema.EnvDefaultFunc("ARM_MSI_ENDPOINT", ""),
|
|
|
|
},
|
|
|
|
|
2018-11-26 11:19:43 +01:00
|
|
|
// Deprecated fields
|
|
|
|
"arm_client_id": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
Description: "The Client ID.",
|
|
|
|
Deprecated: "`arm_client_id` has been replaced by `client_id`",
|
|
|
|
},
|
|
|
|
|
|
|
|
"arm_client_secret": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
Description: "The Client Secret.",
|
|
|
|
Deprecated: "`arm_client_secret` has been replaced by `client_secret`",
|
|
|
|
},
|
|
|
|
|
|
|
|
"arm_subscription_id": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
Description: "The Subscription ID.",
|
|
|
|
Deprecated: "`arm_subscription_id` has been replaced by `subscription_id`",
|
|
|
|
},
|
|
|
|
|
|
|
|
"arm_tenant_id": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
Description: "The Tenant ID.",
|
|
|
|
Deprecated: "`arm_tenant_id` has been replaced by `tenant_id`",
|
|
|
|
},
|
2017-03-30 16:33:54 +02:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
result := &Backend{Backend: s}
|
|
|
|
result.Backend.ConfigureFunc = result.configure
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
type Backend struct {
|
|
|
|
*schema.Backend
|
|
|
|
|
|
|
|
// The fields below are set from configure
|
2018-11-21 22:06:03 +01:00
|
|
|
armClient *ArmClient
|
2017-03-30 16:33:54 +02:00
|
|
|
containerName string
|
|
|
|
keyName string
|
2020-05-20 17:29:02 +02:00
|
|
|
accountName string
|
2020-06-25 11:50:16 +02:00
|
|
|
snapshot bool
|
2017-03-30 16:33:54 +02:00
|
|
|
}
|
|
|
|
|
2017-09-04 13:04:43 +02:00
|
|
|
type BackendConfig struct {
|
2018-11-21 22:06:03 +01:00
|
|
|
// Required
|
2017-09-04 13:04:43 +02:00
|
|
|
StorageAccountName string
|
2018-11-21 22:06:03 +01:00
|
|
|
|
|
|
|
// Optional
|
2018-11-26 14:42:16 +01:00
|
|
|
AccessKey string
|
|
|
|
ClientID string
|
2020-08-07 11:58:33 +02:00
|
|
|
ClientCertificatePassword string
|
|
|
|
ClientCertificatePath string
|
2018-11-26 14:42:16 +01:00
|
|
|
ClientSecret string
|
|
|
|
CustomResourceManagerEndpoint string
|
|
|
|
Environment string
|
|
|
|
MsiEndpoint string
|
|
|
|
ResourceGroupName string
|
|
|
|
SasToken string
|
|
|
|
SubscriptionID string
|
|
|
|
TenantID string
|
|
|
|
UseMsi bool
|
2017-09-04 13:04:43 +02:00
|
|
|
}
|
|
|
|
|
2017-03-30 16:33:54 +02:00
|
|
|
func (b *Backend) configure(ctx context.Context) error {
|
|
|
|
if b.containerName != "" {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Grab the resource data
|
|
|
|
data := schema.FromContextBackendConfig(ctx)
|
|
|
|
b.containerName = data.Get("container_name").(string)
|
2020-05-20 17:29:02 +02:00
|
|
|
b.accountName = data.Get("storage_account_name").(string)
|
2017-03-30 16:33:54 +02:00
|
|
|
b.keyName = data.Get("key").(string)
|
2020-06-25 11:50:16 +02:00
|
|
|
b.snapshot = data.Get("snapshot").(bool)
|
2017-03-30 16:33:54 +02:00
|
|
|
|
2018-11-26 11:19:43 +01:00
|
|
|
// support for previously deprecated fields
|
|
|
|
clientId := valueFromDeprecatedField(data, "client_id", "arm_client_id")
|
|
|
|
clientSecret := valueFromDeprecatedField(data, "client_secret", "arm_client_secret")
|
|
|
|
subscriptionId := valueFromDeprecatedField(data, "subscription_id", "arm_subscription_id")
|
|
|
|
tenantId := valueFromDeprecatedField(data, "tenant_id", "arm_tenant_id")
|
|
|
|
|
2017-09-04 13:04:43 +02:00
|
|
|
config := BackendConfig{
|
2018-11-26 14:42:16 +01:00
|
|
|
AccessKey: data.Get("access_key").(string),
|
|
|
|
ClientID: clientId,
|
2020-08-07 11:58:33 +02:00
|
|
|
ClientCertificatePassword: data.Get("client_certificate_password").(string),
|
|
|
|
ClientCertificatePath: data.Get("client_certificate_path").(string),
|
2018-11-26 14:42:16 +01:00
|
|
|
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),
|
|
|
|
SasToken: data.Get("sas_token").(string),
|
|
|
|
StorageAccountName: data.Get("storage_account_name").(string),
|
|
|
|
SubscriptionID: subscriptionId,
|
|
|
|
TenantID: tenantId,
|
|
|
|
UseMsi: data.Get("use_msi").(bool),
|
2017-09-04 13:04:43 +02:00
|
|
|
}
|
|
|
|
|
2018-11-21 22:06:03 +01:00
|
|
|
armClient, err := buildArmClient(config)
|
2017-03-30 16:33:54 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-11-22 18:02:33 +01:00
|
|
|
if config.AccessKey == "" && config.SasToken == "" && config.ResourceGroupName == "" {
|
|
|
|
return fmt.Errorf("Either an Access Key / SAS Token or the Resource Group for the Storage Account must be specified")
|
2017-03-30 16:33:54 +02:00
|
|
|
}
|
|
|
|
|
2018-11-21 22:06:03 +01:00
|
|
|
b.armClient = armClient
|
|
|
|
return nil
|
2017-03-30 16:33:54 +02:00
|
|
|
}
|
2018-11-26 11:19:43 +01:00
|
|
|
|
|
|
|
func valueFromDeprecatedField(d *schema.ResourceData, key, deprecatedFieldKey string) string {
|
|
|
|
v := d.Get(key).(string)
|
|
|
|
|
|
|
|
if v == "" {
|
|
|
|
v = d.Get(deprecatedFieldKey).(string)
|
|
|
|
}
|
|
|
|
|
|
|
|
return v
|
|
|
|
}
|