diff --git a/internal/services/datafactory/data_factory_linked_service_azure_blob_storage_resource.go b/internal/services/datafactory/data_factory_linked_service_azure_blob_storage_resource.go index b3d7423bb15e..24d10696d2bc 100644 --- a/internal/services/datafactory/data_factory_linked_service_azure_blob_storage_resource.go +++ b/internal/services/datafactory/data_factory_linked_service_azure_blob_storage_resource.go @@ -2,6 +2,7 @@ package datafactory import ( "fmt" + "regexp" "time" "github.com/Azure/azure-sdk-for-go/services/datafactory/mgmt/2018-06-01/datafactory" // nolint: staticcheck @@ -54,7 +55,20 @@ func resourceDataFactoryLinkedServiceAzureBlobStorage() *pluginsdk.Resource { Optional: true, Sensitive: true, ValidateFunc: validation.StringIsNotEmpty, - ExactlyOneOf: []string{"connection_string", "sas_uri", "service_endpoint"}, + ExactlyOneOf: []string{"connection_string", "connection_string_insecure", "sas_uri", "service_endpoint"}, + }, + + "connection_string_insecure": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringIsNotEmpty, + ExactlyOneOf: []string{"connection_string", "connection_string_insecure", "sas_uri", "service_endpoint"}, + DiffSuppressFunc: func(k, old, new string, d *pluginsdk.ResourceData) bool { + accountKeyRegex := regexp.MustCompile("AccountKey=[^;]+") + + maskedNew := accountKeyRegex.ReplaceAllString(new, "") + return (new == d.Get(k).(string)) && (maskedNew == old) + }, }, "storage_kind": { @@ -73,7 +87,7 @@ func resourceDataFactoryLinkedServiceAzureBlobStorage() *pluginsdk.Resource { Optional: true, Sensitive: true, ValidateFunc: validation.StringIsNotEmpty, - ExactlyOneOf: []string{"connection_string", "sas_uri", "service_endpoint"}, + ExactlyOneOf: []string{"connection_string", "connection_string_insecure", "sas_uri", "service_endpoint"}, }, // TODO for @favoretti: rename this to 'sas_token_linked_key_vault_key' for 3.4.0 @@ -145,7 +159,7 @@ func resourceDataFactoryLinkedServiceAzureBlobStorage() *pluginsdk.Resource { Optional: true, Sensitive: true, ValidateFunc: validation.StringIsNotEmpty, - ExactlyOneOf: []string{"connection_string", "sas_uri", "service_endpoint"}, + ExactlyOneOf: []string{"connection_string", "connection_string_insecure", "sas_uri", "service_endpoint"}, }, "service_principal_id": { @@ -231,6 +245,10 @@ func resourceDataFactoryLinkedServiceBlobStorageCreateUpdate(d *pluginsdk.Resour } } + if v, ok := d.GetOk("connection_string_insecure"); ok { + blobStorageProperties.ConnectionString = v.(string) + } + if v, ok := d.GetOk("sas_uri"); ok { if sasToken, ok := d.GetOk("key_vault_sas_token"); ok { blobStorageProperties.SasURI = utils.String(v.(string)) @@ -347,6 +365,11 @@ func resourceDataFactoryLinkedServiceBlobStorageRead(d *pluginsdk.ResourceData, d.Set("service_endpoint", blobStorage.ServiceEndpoint) d.Set("use_managed_identity", true) } + + // blobStorage.ConnectionString is returned as a String when using `connection_string_insecure` and SecureString when using `connection_string` + if insecureConnectionString, ok := blobStorage.ConnectionString.(string); ok { + d.Set("connection_string_insecure", insecureConnectionString) + } } if properties := blobStorage.AzureBlobStorageLinkedServiceTypeProperties; properties != nil { diff --git a/internal/services/datafactory/data_factory_linked_service_azure_blob_storage_resource_test.go b/internal/services/datafactory/data_factory_linked_service_azure_blob_storage_resource_test.go index 001c5cfe0882..9f9412f953a6 100644 --- a/internal/services/datafactory/data_factory_linked_service_azure_blob_storage_resource_test.go +++ b/internal/services/datafactory/data_factory_linked_service_azure_blob_storage_resource_test.go @@ -130,6 +130,21 @@ func TestAccDataFactoryLinkedServiceAzureBlobStorage_update(t *testing.T) { }) } +func TestAccDataFactoryLinkedServiceAzureBlobStorage_connectionStringInsecure(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_data_factory_linked_service_azure_blob_storage", "test") + r := LinkedServiceAzureBlobStorageResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.connectionStringInsecure(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("connection_string_insecure"), + }) +} + func (t LinkedServiceAzureBlobStorageResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { id, err := parse.LinkedServiceID(state.ID) if err != nil { @@ -423,3 +438,28 @@ resource "azurerm_data_factory_linked_service_azure_blob_storage" "test" { } `, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, tenantID) } + +func (LinkedServiceAzureBlobStorageResource) connectionStringInsecure(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-df-%d" + location = "%s" +} + +resource "azurerm_data_factory" "test" { + name = "acctestdf%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_data_factory_linked_service_azure_blob_storage" "test" { + name = "acctestlsblob%d" + data_factory_id = azurerm_data_factory.test.id + connection_string_insecure = "DefaultEndpointsProtocol=https;AccountName=foo;AccountKey=bar" +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} diff --git a/website/docs/r/data_factory_linked_service_azure_blob_storage.html.markdown b/website/docs/r/data_factory_linked_service_azure_blob_storage.html.markdown index 74549b342f52..2d737fb74f36 100644 --- a/website/docs/r/data_factory_linked_service_azure_blob_storage.html.markdown +++ b/website/docs/r/data_factory_linked_service_azure_blob_storage.html.markdown @@ -114,9 +114,13 @@ The following supported arguments are common across all Azure Data Factory Linke The following supported arguments are specific to Azure Blob Storage Linked Service: -* `connection_string` - (Optional) The connection string. Conflicts with `sas_uri` and `service_endpoint`. +* `connection_string` - (Optional) The connection string. Conflicts with `connection_string_insecure`, `sas_uri` and `service_endpoint`. -* `sas_uri` - (Optional) The SAS URI. Conflicts with `connection_string` and `service_endpoint`. +* `connection_string_insecure` - (Optional) The connection string sent insecurely. Conflicts with `connection_string`, `sas_uri` and `service_endpoint`. + +~> **Note:** `connection_string` uses the Azure [SecureString](https://learn.microsoft.com/en-us/dotnet/api/microsoft.azure.management.datafactory.models.securestring) to encrypt the contents within the REST payload sent to Azure whilst the `connection_string_insecure` is sent as a regular string. Both properties are still sent using SSL/HTTPS. At this time the portal will not decrypt Secure Strings so the `connection_string` property in the portal will show as `******` whilst `connection_string_insecure` will be viewable in the portal. + +* `sas_uri` - (Optional) The SAS URI. Conflicts with `connection_string_insecure`, `connection_string` and `service_endpoint`. * `key_vault_sas_token` - (Optional) A `key_vault_sas_token` block as defined below. Use this argument to store SAS Token in an existing Key Vault. It needs an existing Key Vault Data Factory Linked Service. A `sas_uri` is required. @@ -142,7 +146,7 @@ A `service_principal_linked_key_vault_key` block supports the following: --- -* `service_endpoint` - (Optional) The Service Endpoint. Conflicts with `connection_string` and `sas_uri`. +* `service_endpoint` - (Optional) The Service Endpoint. Conflicts with `connection_string`, `connection_string_insecure` and `sas_uri`. * `use_managed_identity` - (Optional) Whether to use the Data Factory's managed identity to authenticate against the Azure Blob Storage account. Incompatible with `service_principal_id` and `service_principal_key`.