diff --git a/azurerm/internal/services/storage/storage_account_network_rules_resource.go b/azurerm/internal/services/storage/storage_account_network_rules_resource.go index 189b7764a49c..509c8df6ebb4 100644 --- a/azurerm/internal/services/storage/storage_account_network_rules_resource.go +++ b/azurerm/internal/services/storage/storage_account_network_rules_resource.go @@ -5,9 +5,6 @@ import ( "strings" "time" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/storage/validate" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/pluginsdk" - "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-01-01/storage" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" @@ -15,6 +12,9 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/locks" + networkValidate "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/storage/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/pluginsdk" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) @@ -93,11 +93,33 @@ func resourceStorageAccountNetworkRules() *schema.Resource { string(storage.DefaultActionDeny), }, false), }, + + "private_link_access": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "endpoint_resource_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: networkValidate.PrivateEndpointID, + }, + + "endpoint_tenant_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.IsUUID, + }, + }, + }, + }, }, } } func resourceStorageAccountNetworkRulesCreateUpdate(d *schema.ResourceData, meta interface{}) error { + tenantId := meta.(*clients.Client).Account.TenantId client := meta.(*clients.Client).Storage.AccountsClient ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() @@ -136,6 +158,7 @@ func resourceStorageAccountNetworkRulesCreateUpdate(d *schema.ResourceData, meta rules.Bypass = expandStorageAccountNetworkRuleBypass(d.Get("bypass").(*schema.Set).List()) rules.IPRules = expandStorageAccountNetworkRuleIpRules(d.Get("ip_rules").(*schema.Set).List()) rules.VirtualNetworkRules = expandStorageAccountNetworkRuleVirtualRules(d.Get("virtual_network_subnet_ids").(*schema.Set).List()) + rules.ResourceAccessRules = expandStorageAccountPrivateLinkAccess(d.Get("private_link_access").([]interface{}), tenantId) opts := storage.AccountUpdateParameters{ AccountPropertiesUpdateParameters: &storage.AccountPropertiesUpdateParameters{ @@ -184,6 +207,9 @@ func resourceStorageAccountNetworkRulesRead(d *schema.ResourceData, meta interfa return fmt.Errorf("Error setting `bypass`: %+v", err) } d.Set("default_action", string(rules.DefaultAction)) + if err := d.Set("private_link_access", flattenStorageAccountPrivateLinkAccess(rules.ResourceAccessRules)); err != nil { + return fmt.Errorf("setting `private_link_access`: %+v", err) + } } return nil diff --git a/azurerm/internal/services/storage/storage_account_network_rules_resource_test.go b/azurerm/internal/services/storage/storage_account_network_rules_resource_test.go index c2666a37e55d..0803a819a2f5 100644 --- a/azurerm/internal/services/storage/storage_account_network_rules_resource_test.go +++ b/azurerm/internal/services/storage/storage_account_network_rules_resource_test.go @@ -66,6 +66,35 @@ func TestAccStorageAccountNetworkRules_update(t *testing.T) { }) } +func TestAccStorageAccountNetworkRules_privateLinkAccess(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_storage_account_network_rules", "test") + r := StorageAccountNetworkRulesResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.disablePrivateLinkAccess(data), + Check: resource.ComposeTestCheckFunc( + check.That("azurerm_storage_account.test").ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.privateLinkAccess(data), + Check: resource.ComposeTestCheckFunc( + check.That("azurerm_storage_account.test").ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.disablePrivateLinkAccess(data), + Check: resource.ComposeTestCheckFunc( + check.That("azurerm_storage_account.test").ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func TestAccStorageAccountNetworkRules_empty(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_storage_account_network_rules", "test") r := StorageAccountNetworkRulesResource{} @@ -236,3 +265,64 @@ resource "azurerm_storage_account_network_rules" "test" { } `, data.RandomInteger, data.Locations.Primary, data.RandomString) } + +func (r StorageAccountNetworkRulesResource) disablePrivateLinkAccess(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_storage_account" "test" { + name = "unlikely23exst2acct%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + account_tier = "Standard" + account_replication_type = "LRS" + + tags = { + environment = "production" + } +} + +resource "azurerm_storage_account_network_rules" "test" { + resource_group_name = azurerm_resource_group.test.name + storage_account_name = azurerm_storage_account.test.name + + default_action = "Deny" + bypass = ["None"] + ip_rules = [] + virtual_network_subnet_ids = [] +} +`, StorageAccountResource{}.networkRulesPrivateEndpointTemplate(data), data.RandomString) +} + +func (r StorageAccountNetworkRulesResource) privateLinkAccess(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_storage_account" "test" { + name = "unlikely23exst2acct%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + account_tier = "Standard" + account_replication_type = "LRS" + + tags = { + environment = "production" + } +} + +resource "azurerm_storage_account_network_rules" "test" { + resource_group_name = azurerm_resource_group.test.name + storage_account_name = azurerm_storage_account.test.name + + default_action = "Deny" + ip_rules = ["127.0.0.1"] + virtual_network_subnet_ids = [azurerm_subnet.test.id] + private_link_access { + endpoint_resource_id = azurerm_private_endpoint.blob.id + } + private_link_access { + endpoint_resource_id = azurerm_private_endpoint.table.id + } +} +`, StorageAccountResource{}.networkRulesPrivateEndpointTemplate(data), data.RandomString) +} diff --git a/azurerm/internal/services/storage/storage_account_resource.go b/azurerm/internal/services/storage/storage_account_resource.go index eae0c0536381..bce67adfc9c5 100644 --- a/azurerm/internal/services/storage/storage_account_resource.go +++ b/azurerm/internal/services/storage/storage_account_resource.go @@ -20,6 +20,7 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/locks" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network" + networkValidate "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/validate" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/storage/migration" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/storage/validate" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" @@ -287,6 +288,27 @@ func resourceStorageAccount() *schema.Resource { string(storage.DefaultActionDeny), }, false), }, + + "private_link_access": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "endpoint_resource_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: networkValidate.PrivateEndpointID, + }, + + "endpoint_tenant_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.IsUUID, + }, + }, + }, + }, }, }, }, @@ -737,6 +759,7 @@ func resourceStorageAccount() *schema.Resource { func resourceStorageAccountCreate(d *schema.ResourceData, meta interface{}) error { envName := meta.(*clients.Client).Account.Environment.Name + tenantId := meta.(*clients.Client).Account.TenantId client := meta.(*clients.Client).Storage.AccountsClient ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() @@ -780,7 +803,7 @@ func resourceStorageAccountCreate(d *schema.ResourceData, meta interface{}) erro Kind: storage.Kind(accountKind), AccountPropertiesCreateParameters: &storage.AccountPropertiesCreateParameters{ EnableHTTPSTrafficOnly: &enableHTTPSTrafficOnly, - NetworkRuleSet: expandStorageAccountNetworkRules(d), + NetworkRuleSet: expandStorageAccountNetworkRules(d, tenantId), IsHnsEnabled: &isHnsEnabled, EnableNfsV3: &nfsV3Enabled, }, @@ -964,6 +987,7 @@ func resourceStorageAccountCreate(d *schema.ResourceData, meta interface{}) erro func resourceStorageAccountUpdate(d *schema.ResourceData, meta interface{}) error { envName := meta.(*clients.Client).Account.Environment.Name + tenantId := meta.(*clients.Client).Account.TenantId client := meta.(*clients.Client).Storage.AccountsClient ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() @@ -1126,12 +1150,12 @@ func resourceStorageAccountUpdate(d *schema.ResourceData, meta interface{}) erro if d.HasChange("network_rules") { opts := storage.AccountUpdateParameters{ AccountPropertiesUpdateParameters: &storage.AccountPropertiesUpdateParameters{ - NetworkRuleSet: expandStorageAccountNetworkRules(d), + NetworkRuleSet: expandStorageAccountNetworkRules(d, tenantId), }, } if _, err := client.Update(ctx, resourceGroupName, storageAccountName, opts); err != nil { - return fmt.Errorf("Error updating Azure Storage Account network_rules %q: %+v", storageAccountName, err) + return fmt.Errorf("updating Azure Storage Account network_rules %q: %+v", storageAccountName, err) } } @@ -1646,7 +1670,7 @@ func expandArmStorageAccountRouting(input []interface{}) *storage.RoutingPrefere } } -func expandStorageAccountNetworkRules(d *schema.ResourceData) *storage.NetworkRuleSet { +func expandStorageAccountNetworkRules(d *schema.ResourceData, tenantId string) *storage.NetworkRuleSet { networkRules := d.Get("network_rules").([]interface{}) if len(networkRules) == 0 { // Default access is enabled when no network rules are set. @@ -1658,6 +1682,7 @@ func expandStorageAccountNetworkRules(d *schema.ResourceData) *storage.NetworkRu IPRules: expandStorageAccountIPRules(networkRule), VirtualNetworkRules: expandStorageAccountVirtualNetworks(networkRule), Bypass: expandStorageAccountBypass(networkRule), + ResourceAccessRules: expandStorageAccountPrivateLinkAccess(networkRule["private_link_access"].([]interface{}), tenantId), } if v := networkRule["default_action"]; v != nil { @@ -1710,6 +1735,25 @@ func expandStorageAccountBypass(networkRule map[string]interface{}) storage.Bypa return storage.Bypass(strings.Join(bypassValues, ", ")) } +func expandStorageAccountPrivateLinkAccess(inputs []interface{}, tenantId string) *[]storage.ResourceAccessRule { + privateLinkAccess := make([]storage.ResourceAccessRule, 0) + if len(inputs) == 0 { + return &privateLinkAccess + } + for _, input := range inputs { + accessRule := input.(map[string]interface{}) + if v := accessRule["endpoint_tenant_id"].(string); v != "" { + tenantId = v + } + privateLinkAccess = append(privateLinkAccess, storage.ResourceAccessRule{ + TenantID: utils.String(tenantId), + ResourceID: utils.String(accessRule["endpoint_resource_id"].(string)), + }) + } + + return &privateLinkAccess +} + func expandBlobProperties(input []interface{}) *storage.BlobServiceProperties { props := storage.BlobServiceProperties{ BlobServicePropertiesProperties: &storage.BlobServicePropertiesProperties{ @@ -2036,6 +2080,7 @@ func flattenStorageAccountNetworkRules(input *storage.NetworkRuleSet) []interfac networkRules["virtual_network_subnet_ids"] = schema.NewSet(schema.HashString, flattenStorageAccountVirtualNetworks(input.VirtualNetworkRules)) networkRules["bypass"] = schema.NewSet(schema.HashString, flattenStorageAccountBypass(input.Bypass)) networkRules["default_action"] = string(input.DefaultAction) + networkRules["private_link_access"] = flattenStorageAccountPrivateLinkAccess(input.ResourceAccessRules) return []interface{}{networkRules} } @@ -2074,6 +2119,31 @@ func flattenStorageAccountVirtualNetworks(input *[]storage.VirtualNetworkRule) [ return virtualNetworks } +func flattenStorageAccountPrivateLinkAccess(inputs *[]storage.ResourceAccessRule) []interface{} { + if inputs == nil || len(*inputs) == 0 { + return []interface{}{} + } + + accessRules := make([]interface{}, 0) + for _, input := range *inputs { + var resourceId, tenantId string + if input.ResourceID != nil { + resourceId = *input.ResourceID + } + + if input.TenantID != nil { + tenantId = *input.TenantID + } + + accessRules = append(accessRules, map[string]interface{}{ + "endpoint_resource_id": resourceId, + "endpoint_tenant_id": tenantId, + }) + } + + return accessRules +} + func flattenBlobProperties(input storage.BlobServiceProperties) []interface{} { if input.BlobServicePropertiesProperties == nil { return []interface{}{} diff --git a/azurerm/internal/services/storage/storage_account_resource_test.go b/azurerm/internal/services/storage/storage_account_resource_test.go index 38a316cff2e7..13d7091cf819 100644 --- a/azurerm/internal/services/storage/storage_account_resource_test.go +++ b/azurerm/internal/services/storage/storage_account_resource_test.go @@ -514,6 +514,35 @@ func TestAccStorageAccount_networkRulesDeleted(t *testing.T) { }) } +func TestAccStorageAccount_privateLinkAccess(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_storage_account", "test") + r := StorageAccountResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.networkRules(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.networkRulesPrivateLinkAccess(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.networkRulesReverted(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func TestAccStorageAccount_blobProperties(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_storage_account", "test") r := StorageAccountResource{} @@ -864,7 +893,7 @@ resource "azurerm_storage_account" "test" { account_replication_type = "LRS" tags = { - %s + %s } } `, data.RandomInteger, data.Locations.Primary, data.RandomString, tags) @@ -1485,31 +1514,115 @@ resource "azurerm_storage_account" "test" { `, data.RandomInteger, data.Locations.Primary, data.RandomString) } -func (r StorageAccountResource) networkRules(data acceptance.TestData) string { +func (r StorageAccountResource) networkRulesTemplate(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { features {} } resource "azurerm_resource_group" "test" { - name = "acctestRG-storage-%d" - location = "%s" + name = "acctestRG-storage-%[1]d" + location = "%[2]s" } resource "azurerm_virtual_network" "test" { - name = "acctestvirtnet%d" + name = "acctestvirtnet%[1]d" address_space = ["10.0.0.0/16"] location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name } resource "azurerm_subnet" "test" { - name = "acctestsubnet%d" + name = "acctestsubnet%[1]d" resource_group_name = azurerm_resource_group.test.name virtual_network_name = azurerm_virtual_network.test.name address_prefix = "10.0.2.0/24" service_endpoints = ["Microsoft.Storage"] } +`, data.RandomInteger, data.Locations.Primary) +} + +func (r StorageAccountResource) networkRulesPrivateEndpointTemplate(data acceptance.TestData) string { + return fmt.Sprintf(` +%[1]s + +resource "azurerm_subnet" "blob_endpoint" { + name = "acctestsnetblobendpoint-%[2]d" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.5.0/24"] + + enforce_private_link_endpoint_network_policies = true +} + +resource "azurerm_subnet" "table_endpoint" { + name = "acctestsnettableendpoint-%[2]d" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.6.0/24"] + + enforce_private_link_endpoint_network_policies = true +} + +resource "azurerm_storage_account" "blob_connection" { + name = "accblobconnacct%[3]s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_storage_account" "table_connection" { + name = "acctableconnacct%[3]s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_private_dns_zone" "blob" { + name = "privatelink.blob.core.windows.net" + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_private_dns_zone" "table" { + name = "privatelink.table.core.windows.net" + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_private_endpoint" "blob" { + name = "acctest-privatelink-blob-%[2]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + subnet_id = azurerm_subnet.blob_endpoint.id + + private_service_connection { + name = "acctest-privatelink-mssc-%[2]d" + private_connection_resource_id = azurerm_storage_account.blob_connection.id + subresource_names = ["blob"] + is_manual_connection = false + } +} + +resource "azurerm_private_endpoint" "table" { + name = "acctest-privatelink-table-%[2]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + subnet_id = azurerm_subnet.table_endpoint.id + + private_service_connection { + name = "acctest-privatelink-mssc-%[2]d" + private_connection_resource_id = azurerm_storage_account.table_connection.id + subresource_names = ["table"] + is_manual_connection = false + } +} +`, r.networkRulesTemplate(data), data.RandomInteger, data.RandomString) +} + +func (r StorageAccountResource) networkRules(data acceptance.TestData) string { + return fmt.Sprintf(` +%s resource "azurerm_storage_account" "test" { name = "unlikely23exst2acct%s" @@ -1528,34 +1641,12 @@ resource "azurerm_storage_account" "test" { environment = "production" } } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomString) +`, r.networkRulesTemplate(data), data.RandomString) } func (r StorageAccountResource) networkRulesUpdate(data acceptance.TestData) string { return fmt.Sprintf(` -provider "azurerm" { - features {} -} - -resource "azurerm_resource_group" "test" { - name = "acctestRG-storage-%d" - location = "%s" -} - -resource "azurerm_virtual_network" "test" { - name = "acctestvirtnet%d" - address_space = ["10.0.0.0/16"] - location = azurerm_resource_group.test.location - resource_group_name = azurerm_resource_group.test.name -} - -resource "azurerm_subnet" "test" { - name = "acctestsubnet%d" - resource_group_name = azurerm_resource_group.test.name - virtual_network_name = azurerm_virtual_network.test.name - address_prefix = "10.0.2.0/24" - service_endpoints = ["Microsoft.Storage"] -} +%s resource "azurerm_storage_account" "test" { name = "unlikely23exst2acct%s" @@ -1574,35 +1665,37 @@ resource "azurerm_storage_account" "test" { environment = "production" } } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomString) +`, r.networkRulesTemplate(data), data.RandomString) } func (r StorageAccountResource) networkRulesReverted(data acceptance.TestData) string { return fmt.Sprintf(` -provider "azurerm" { - features {} -} +%s -resource "azurerm_resource_group" "test" { - name = "acctestRG-storage-%d" - location = "%s" -} +resource "azurerm_storage_account" "test" { + name = "unlikely23exst2acct%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + account_tier = "Standard" + account_replication_type = "LRS" -resource "azurerm_virtual_network" "test" { - name = "acctestvirtnet%d" - address_space = ["10.0.0.0/16"] - location = azurerm_resource_group.test.location - resource_group_name = azurerm_resource_group.test.name -} + network_rules { + default_action = "Allow" + ip_rules = ["127.0.0.1"] + virtual_network_subnet_ids = [azurerm_subnet.test.id] + } -resource "azurerm_subnet" "test" { - name = "acctestsubnet%d" - resource_group_name = azurerm_resource_group.test.name - virtual_network_name = azurerm_virtual_network.test.name - address_prefix = "10.0.2.0/24" - service_endpoints = ["Microsoft.Storage"] + tags = { + environment = "production" + } +} +`, r.networkRulesTemplate(data), data.RandomString) } +func (r StorageAccountResource) networkRulesPrivateLinkAccess(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + resource "azurerm_storage_account" "test" { name = "unlikely23exst2acct%s" resource_group_name = azurerm_resource_group.test.name @@ -1611,16 +1704,22 @@ resource "azurerm_storage_account" "test" { account_replication_type = "LRS" network_rules { - default_action = "Allow" + default_action = "Deny" ip_rules = ["127.0.0.1"] virtual_network_subnet_ids = [azurerm_subnet.test.id] + private_link_access { + endpoint_resource_id = azurerm_private_endpoint.blob.id + } + private_link_access { + endpoint_resource_id = azurerm_private_endpoint.table.id + } } tags = { environment = "production" } } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomString) +`, r.networkRulesPrivateEndpointTemplate(data), data.RandomString) } func (r StorageAccountResource) blobProperties(data acceptance.TestData) string { diff --git a/website/docs/r/storage_account.html.markdown b/website/docs/r/storage_account.html.markdown index 4d2f6eaee7ed..20a481c2206f 100644 --- a/website/docs/r/storage_account.html.markdown +++ b/website/docs/r/storage_account.html.markdown @@ -243,6 +243,8 @@ any combination of `Logging`, `Metrics`, `AzureServices`, or `None`. * `ip_rules` - (Optional) List of public IP or IP ranges in CIDR Format. Only IPV4 addresses are allowed. Private IP address ranges (as defined in [RFC 1918](https://tools.ietf.org/html/rfc1918#section-3)) are not allowed. * `virtual_network_subnet_ids` - (Optional) A list of resource ids for subnets. +* `private_link_access` - (Optional) One or More `private_link_access` block as defined below. + ~> **Note:** If specifying `network_rules`, one of either `ip_rules` or `virtual_network_subnet_ids` must be specified and `default_action` must be set to `Deny`. ~> **NOTE:** Network Rules can be defined either directly on the `azurerm_storage_account` resource, or using the `azurerm_storage_account_network_rules` resource - but the two cannot be used together. If both are used against the same Storage Account, spurious changes will occur. When managing Network Rules using this resource, to change from a `default_action` of `Deny` to `Allow` requires defining, rather than removing, the block. @@ -253,6 +255,14 @@ any combination of `Logging`, `Metrics`, `AzureServices`, or `None`. --- +A `private_link_access` block supports the following: + +* `endpoint_resource_id` - (Required) The resource id of the `azurerm_private_endpoint` of the resource access rule. + +* `endpoint_tenant_id` - (Optional) The tenant id of the `azurerm_private_endpoint` of the resource access rule. Defaults to the current tenant id. + +--- + A `azure_files_authentication` block supports the following: * `directory_type` - (Required) Specifies the directory service used. Possible values are `AADDS` and `AD`. diff --git a/website/docs/r/storage_account_network_rules.html.markdown b/website/docs/r/storage_account_network_rules.html.markdown index 272d45812ffa..50f42a7529e2 100644 --- a/website/docs/r/storage_account_network_rules.html.markdown +++ b/website/docs/r/storage_account_network_rules.html.markdown @@ -88,6 +88,17 @@ The following arguments are supported: -> **NOTE** User has to explicitly set `virtual_network_subnet_ids` to empty slice (`[]`) to remove it. +* `private_link_access` - (Optional) One or More `private_link_access` block as defined below. + +--- + +A `private_link_access` block supports the following: + +* `endpoint_resource_id` - (Required) The resource id of the `azurerm_private_endpoint` of the resource access rule. + +* `endpoint_tenant_id` - (Optional) The tenant id of the `azurerm_private_endpoint` of the resource access rule. Defaults to the current tenant id. + + ## Attributes Reference The following attributes are exported in addition to the arguments listed above: