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 }