github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/backend/remote-state/azure/backend.go (about)

     1  package azure
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/hashicorp/terraform/backend"
     8  	"github.com/hashicorp/terraform/helper/schema"
     9  )
    10  
    11  // New creates a new backend for Azure remote state.
    12  func New() backend.Backend {
    13  	s := &schema.Backend{
    14  		Schema: map[string]*schema.Schema{
    15  			"storage_account_name": {
    16  				Type:        schema.TypeString,
    17  				Required:    true,
    18  				Description: "The name of the storage account.",
    19  			},
    20  
    21  			"container_name": {
    22  				Type:        schema.TypeString,
    23  				Required:    true,
    24  				Description: "The container name.",
    25  			},
    26  
    27  			"key": {
    28  				Type:        schema.TypeString,
    29  				Required:    true,
    30  				Description: "The blob key.",
    31  			},
    32  
    33  			"environment": {
    34  				Type:        schema.TypeString,
    35  				Optional:    true,
    36  				Description: "The Azure cloud environment.",
    37  				DefaultFunc: schema.EnvDefaultFunc("ARM_ENVIRONMENT", "public"),
    38  			},
    39  
    40  			"access_key": {
    41  				Type:        schema.TypeString,
    42  				Optional:    true,
    43  				Description: "The access key.",
    44  				DefaultFunc: schema.EnvDefaultFunc("ARM_ACCESS_KEY", ""),
    45  			},
    46  
    47  			"sas_token": {
    48  				Type:        schema.TypeString,
    49  				Optional:    true,
    50  				Description: "A SAS Token used to interact with the Blob Storage Account.",
    51  				DefaultFunc: schema.EnvDefaultFunc("ARM_SAS_TOKEN", ""),
    52  			},
    53  
    54  			"resource_group_name": {
    55  				Type:        schema.TypeString,
    56  				Optional:    true,
    57  				Description: "The resource group name.",
    58  			},
    59  
    60  			"client_id": {
    61  				Type:        schema.TypeString,
    62  				Optional:    true,
    63  				Description: "The Client ID.",
    64  				DefaultFunc: schema.EnvDefaultFunc("ARM_CLIENT_ID", ""),
    65  			},
    66  
    67  			"client_secret": {
    68  				Type:        schema.TypeString,
    69  				Optional:    true,
    70  				Description: "The Client Secret.",
    71  				DefaultFunc: schema.EnvDefaultFunc("ARM_CLIENT_SECRET", ""),
    72  			},
    73  
    74  			"subscription_id": {
    75  				Type:        schema.TypeString,
    76  				Optional:    true,
    77  				Description: "The Subscription ID.",
    78  				DefaultFunc: schema.EnvDefaultFunc("ARM_SUBSCRIPTION_ID", ""),
    79  			},
    80  
    81  			"tenant_id": {
    82  				Type:        schema.TypeString,
    83  				Optional:    true,
    84  				Description: "The Tenant ID.",
    85  				DefaultFunc: schema.EnvDefaultFunc("ARM_TENANT_ID", ""),
    86  			},
    87  
    88  			"use_msi": {
    89  				Type:        schema.TypeBool,
    90  				Optional:    true,
    91  				Description: "Should Managed Service Identity be used?.",
    92  				DefaultFunc: schema.EnvDefaultFunc("ARM_USE_MSI", false),
    93  			},
    94  
    95  			"msi_endpoint": {
    96  				Type:        schema.TypeString,
    97  				Optional:    true,
    98  				Description: "The Managed Service Identity Endpoint.",
    99  				DefaultFunc: schema.EnvDefaultFunc("ARM_MSI_ENDPOINT", ""),
   100  			},
   101  
   102  			"endpoint": {
   103  				Type:        schema.TypeString,
   104  				Optional:    true,
   105  				Description: "A custom Endpoint used to access the Azure Resource Manager API's.",
   106  				DefaultFunc: schema.EnvDefaultFunc("ARM_ENDPOINT", ""),
   107  			},
   108  
   109  			// Deprecated fields
   110  			"arm_client_id": {
   111  				Type:        schema.TypeString,
   112  				Optional:    true,
   113  				Description: "The Client ID.",
   114  				Deprecated:  "`arm_client_id` has been replaced by `client_id`",
   115  			},
   116  
   117  			"arm_client_secret": {
   118  				Type:        schema.TypeString,
   119  				Optional:    true,
   120  				Description: "The Client Secret.",
   121  				Deprecated:  "`arm_client_secret` has been replaced by `client_secret`",
   122  			},
   123  
   124  			"arm_subscription_id": {
   125  				Type:        schema.TypeString,
   126  				Optional:    true,
   127  				Description: "The Subscription ID.",
   128  				Deprecated:  "`arm_subscription_id` has been replaced by `subscription_id`",
   129  			},
   130  
   131  			"arm_tenant_id": {
   132  				Type:        schema.TypeString,
   133  				Optional:    true,
   134  				Description: "The Tenant ID.",
   135  				Deprecated:  "`arm_tenant_id` has been replaced by `tenant_id`",
   136  			},
   137  		},
   138  	}
   139  
   140  	result := &Backend{Backend: s}
   141  	result.Backend.ConfigureFunc = result.configure
   142  	return result
   143  }
   144  
   145  type Backend struct {
   146  	*schema.Backend
   147  
   148  	// The fields below are set from configure
   149  	armClient     *ArmClient
   150  	containerName string
   151  	keyName       string
   152  }
   153  
   154  type BackendConfig struct {
   155  	// Required
   156  	StorageAccountName string
   157  
   158  	// Optional
   159  	AccessKey                     string
   160  	ClientID                      string
   161  	ClientSecret                  string
   162  	CustomResourceManagerEndpoint string
   163  	Environment                   string
   164  	MsiEndpoint                   string
   165  	ResourceGroupName             string
   166  	SasToken                      string
   167  	SubscriptionID                string
   168  	TenantID                      string
   169  	UseMsi                        bool
   170  }
   171  
   172  func (b *Backend) configure(ctx context.Context) error {
   173  	if b.containerName != "" {
   174  		return nil
   175  	}
   176  
   177  	// Grab the resource data
   178  	data := schema.FromContextBackendConfig(ctx)
   179  	b.containerName = data.Get("container_name").(string)
   180  	b.keyName = data.Get("key").(string)
   181  
   182  	// support for previously deprecated fields
   183  	clientId := valueFromDeprecatedField(data, "client_id", "arm_client_id")
   184  	clientSecret := valueFromDeprecatedField(data, "client_secret", "arm_client_secret")
   185  	subscriptionId := valueFromDeprecatedField(data, "subscription_id", "arm_subscription_id")
   186  	tenantId := valueFromDeprecatedField(data, "tenant_id", "arm_tenant_id")
   187  
   188  	config := BackendConfig{
   189  		AccessKey:                     data.Get("access_key").(string),
   190  		ClientID:                      clientId,
   191  		ClientSecret:                  clientSecret,
   192  		CustomResourceManagerEndpoint: data.Get("endpoint").(string),
   193  		Environment:                   data.Get("environment").(string),
   194  		MsiEndpoint:                   data.Get("msi_endpoint").(string),
   195  		ResourceGroupName:             data.Get("resource_group_name").(string),
   196  		SasToken:                      data.Get("sas_token").(string),
   197  		StorageAccountName:            data.Get("storage_account_name").(string),
   198  		SubscriptionID:                subscriptionId,
   199  		TenantID:                      tenantId,
   200  		UseMsi:                        data.Get("use_msi").(bool),
   201  	}
   202  
   203  	armClient, err := buildArmClient(config)
   204  	if err != nil {
   205  		return err
   206  	}
   207  
   208  	if config.AccessKey == "" && config.SasToken == "" && config.ResourceGroupName == "" {
   209  		return fmt.Errorf("Either an Access Key / SAS Token or the Resource Group for the Storage Account must be specified")
   210  	}
   211  
   212  	b.armClient = armClient
   213  	return nil
   214  }
   215  
   216  func valueFromDeprecatedField(d *schema.ResourceData, key, deprecatedFieldKey string) string {
   217  	v := d.Get(key).(string)
   218  
   219  	if v == "" {
   220  		v = d.Get(deprecatedFieldKey).(string)
   221  	}
   222  
   223  	return v
   224  }