azurerm_linux_function_app Creation of storage file share failed – check if the storage account is accessible – azurerm_private_endpoint

huangapple go评论76阅读模式
英文:

azurerm_linux_function_app Creation of storage file share failed - check if the storage account is accessible - azurerm_private_endpoint

问题

尝试让 azurerm_linux_function_appazurerm_storage_account_network_rulesazurerm_private_endpoint 协同工作。

Terraform v1.3.7
 darwin_arm64 
+ 提供者 registry.terraform.io/hashicorp/azurerm v3.38.0

这是我正在尝试的配置。

provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "func_rg" {
  name     = "func"
  location = "eastus"
}

# 创建网络 VNET
resource "azurerm_virtual_network" "func" {
  name                = "func_vnet"
  address_space       = ["10.0.0.0/16"]
  resource_group_name = azurerm_resource_group.func_rg.name
  location            = azurerm_resource_group.func_rg.location
}

# 为终结点创建子网
resource "azurerm_subnet" "endpoint_subnet" {
  name                                      = "endpoint_subnet"
  address_prefixes                          = ["10.0.0.0/24"]
  virtual_network_name                      = azurerm_virtual_network.func.name
  resource_group_name                       = azurerm_resource_group.func_rg.name
  private_endpoint_network_policies_enabled = true
}

# 为函数创建子网
resource "azurerm_subnet" "func_subnet" {
  name                 = "func_subnet"
  resource_group_name  = azurerm_resource_group.func_rg.name
  virtual_network_name = azurerm_virtual_network.func.name
  address_prefixes     = ["10.0.1.0/24"]
  service_endpoints    = ["Microsoft.Storage"]

  delegation {
    name = "delegation"

    service_delegation {
      name = "Microsoft.Web/serverFarms"
    }
  }
}

# 为子网创建 NSG
resource "azurerm_network_security_group" "func" {
  name                = "func_nsg"
  location            = azurerm_resource_group.func_rg.location
  resource_group_name = azurerm_resource_group.func_rg.name
}

# 将 NSG 与函数子网关联
resource "azurerm_subnet_network_security_group_association" "func" {
  subnet_id                 = azurerm_subnet.func_subnet.id
  network_security_group_id = azurerm_network_security_group.func.id
}

# 将 NSG 与终结点子网关联
resource "azurerm_subnet_network_security_group_association" "endpoint" {
  subnet_id                 = azurerm_subnet.endpoint_subnet.id
  network_security_group_id = azurerm_network_security_group.func.id
}

# 创建 Blob Private DNS 区域
resource "azurerm_private_dns_zone" "blob_dns_zone" {
  name                = "privatelink.blob.core.windows.net"
  resource_group_name = azurerm_resource_group.func_rg.name
}

# 创建文件 Private DNS 区域
resource "azurerm_private_dns_zone" "file_dns_zone" {
  name                = "privatelink.file.core.windows.net"
  resource_group_name = azurerm_resource_group.func_rg.name
}

# 创建表 Private DNS 区域
resource "azurerm_private_dns_zone" "table_dns_zone" {
  name                = "privatelink.table.core.windows.net"
  resource_group_name = azurerm_resource_group.func_rg.name
}

# 创建队列 Private DNS 区域
resource "azurerm_private_dns_zone" "queue_dns_zone" {
  name                = "privatelink.queue.core.windows.net"
  resource_group_name = azurerm_resource_group.func_rg.name
}

# 创建 Blob Private DNS 区域网络链接
resource "azurerm_private_dns_zone_virtual_network_link" "blob_vnl" {
  name                  = "blob_vnl"
  resource_group_name   = azurerm_resource_group.func_rg.name
  private_dns_zone_name = azurerm_private_dns_zone.blob_dns_zone.name
  virtual_network_id    = azurerm_virtual_network.func.id
}

# 创建文件 Private DNS 区域网络链接
resource "azurerm_private_dns_zone_virtual_network_link" "file_vnl" {
  name                  = "file_vnl"
  resource_group_name   = azurerm_resource_group.func_rg.name
  private_dns_zone_name = azurerm_private_dns_zone.file_dns_zone.name
  virtual_network_id    = azurerm_virtual_network.func.id
}

# 创建表 Private DNS 区域网络链接
resource "azurerm_private_dns_zone_virtual_network_link" "table_vnl" {
  name                  = "table_vnl"
  resource_group_name   = azurerm_resource_group.func_rg.name
  private_dns_zone_name = azurerm_private_dns_zone.table_dns_zone.name
  virtual_network_id    = azurerm_virtual_network.func.id
}

# 创建队列 Private DNS 区域网络链接
resource "azurerm_private_dns_zone_virtual_network_link" "queue_vnl" {
  name                  = "queue_vnl"
  resource_group_name   = azurerm_resource_group.func_rg.name
  private_dns_zone_name = azurerm_private_dns_zone.queue_dns_zone.name
  virtual_network_id    = azurerm_virtual_network.func.id
}

resource "azurerm_storage_account" "func" {
  name                     = "rdtestfuncsa"
  resource_group_name      = azurerm_resource_group.func_rg.name
  location                 = azurerm_resource_group.func_rg.location
  account_tier             = "Standard"
  account_replication_type = "LRS"
}

resource "azurerm_storage_account_network_rules" "func" {
  storage_account_id = azurerm_storage_account.func.id

  default_action             = "Deny"
  ip_rules                   = ["***.***.***.***"]
  virtual_network_subnet_ids = [azurerm_subnet.func_subnet.id]
  bypass                     = ["Metrics", "Logging", "AzureServices"]
}

resource "azurerm_storage_container" "func" {
  name                 = "func-sc"
  storage_account_name = azurerm_storage_account.func.name
  container_access_type = "private"
}

# 创建私有终结点
resource "azurerm_private_endpoint" "file_endpoint" {
  name                = "rdtest_file_pe"
  resource_group_name = azurerm_resource_group.func_rg.name
  location            = azurerm_resource_group.func_rg.location
  subnet_id           = azurerm_subnet.endpoint_subnet.id
  private_service_connection {
    name                           = "rdtest_file_psc"
    private_connection_resource_id = azurerm_storage_account.func.id
    is_manual_connection           = false
    subresource_names              = ["file"]
  }
}

resource "azurerm_private_endpoint" "blob_endpoint" {
  name                = "rdtest_blob_pe"
  resource_group_name = azurerm_resource_group.func_rg.name
  location            = azurerm_resource_group.func_rg.location
  subnet_id           = azurerm_subnet.endpoint_subnet.id
  private_service_connection {
    name                           = "rdtest_blob_psc

<details>
<summary>英文:</summary>

Trying to get `azurerm_linux_function_app` to work with `azurerm_storage_account_network_rules` and  `azurerm_private_endpoint`.

Terraform v1.3.7
on darwin_arm64

  • provider registry.terraform.io/hashicorp/azurerm v3.38.0

This is what I&#39;m trying.

provider "azurerm" {
features {}
}

resource "azurerm_resource_group" "func_rg" {
name = "func"
location = "eastus"
}

Create the network VNET

resource "azurerm_virtual_network" "func" {
name = "func_vnet"
address_space = ["10.0.0.0/16"]
resource_group_name = azurerm_resource_group.func_rg.name
location = azurerm_resource_group.func_rg.location
}

Create a subnet for endpoint

resource "azurerm_subnet" "endpoint_subnet" {
name = "endpoint_subnet"
address_prefixes = ["10.0.0.0/24"]
virtual_network_name = azurerm_virtual_network.func.name
resource_group_name = azurerm_resource_group.func_rg.name
private_endpoint_network_policies_enabled = true
}

Create subnet for functions

resource "azurerm_subnet" "func_subnet" {
name = "func_subnet"
resource_group_name = azurerm_resource_group.func_rg.name
virtual_network_name = azurerm_virtual_network.func.name
address_prefixes = ["10.0.1.0/24"]
service_endpoints = ["Microsoft.Storage"]

delegation {
name = "delegation"

service_delegation {
name = &quot;Microsoft.Web/serverFarms&quot;
}

}
}

Create nsg for subnets

resource "azurerm_network_security_group" "func" {
name = "func_nsg"
location = azurerm_resource_group.func_rg.location
resource_group_name = azurerm_resource_group.func_rg.name
}

Associate nsg with func subnet

resource "azurerm_subnet_network_security_group_association" "func" {
subnet_id = azurerm_subnet.func_subnet.id
network_security_group_id = azurerm_network_security_group.func.id
}

Associate nsg with endpoint subnet

resource "azurerm_subnet_network_security_group_association" "endpoint" {
subnet_id = azurerm_subnet.endpoint_subnet.id
network_security_group_id = azurerm_network_security_group.func.id
}

Create blob Private DNS Zone

resource "azurerm_private_dns_zone" "blob_dns_zone" {
name = "privatelink.blob.core.windows.net"
resource_group_name = azurerm_resource_group.func_rg.name
}

Create file Private DNS Zone

resource "azurerm_private_dns_zone" "file_dns_zone" {
name = "privatelink.file.core.windows.net"
resource_group_name = azurerm_resource_group.func_rg.name
}

Create table Private DNS Zone

resource "azurerm_private_dns_zone" "table_dns_zone" {
name = "privatelink.table.core.windows.net"
resource_group_name = azurerm_resource_group.func_rg.name
}

Create queue Private DNS Zone

resource "azurerm_private_dns_zone" "queue_dns_zone" {
name = "privatelink.queue.core.windows.net"
resource_group_name = azurerm_resource_group.func_rg.name
}

Create blob Private DNS Zone Network Link

resource "azurerm_private_dns_zone_virtual_network_link" "blob_vnl" {
name = "blob_vnl"
resource_group_name = azurerm_resource_group.func_rg.name
private_dns_zone_name = azurerm_private_dns_zone.blob_dns_zone.name
virtual_network_id = azurerm_virtual_network.func.id
}

Create file Private DNS Zone Network Link

resource "azurerm_private_dns_zone_virtual_network_link" "file_vnl" {
name = "file_vnl"
resource_group_name = azurerm_resource_group.func_rg.name
private_dns_zone_name = azurerm_private_dns_zone.file_dns_zone.name
virtual_network_id = azurerm_virtual_network.func.id
}

Create table Private DNS Zone Network Link

resource "azurerm_private_dns_zone_virtual_network_link" "table_vnl" {
name = "table_vnl"
resource_group_name = azurerm_resource_group.func_rg.name
private_dns_zone_name = azurerm_private_dns_zone.table_dns_zone.name
virtual_network_id = azurerm_virtual_network.func.id
}

Create queue Private DNS Zone Network Link

resource "azurerm_private_dns_zone_virtual_network_link" "queue_vnl" {
name = "queue_vnl"
resource_group_name = azurerm_resource_group.func_rg.name
private_dns_zone_name = azurerm_private_dns_zone.queue_dns_zone.name
virtual_network_id = azurerm_virtual_network.func.id
}

resource "azurerm_storage_account" "func" {
name = "rdtestfuncsa"
resource_group_name = azurerm_resource_group.func_rg.name
location = azurerm_resource_group.func_rg.location
account_tier = "Standard"
account_replication_type = "LRS"
}

resource "azurerm_storage_account_network_rules" "func" {
storage_account_id = azurerm_storage_account.func.id

default_action = "Deny"
ip_rules = ["..."]
virtual_network_subnet_ids = [azurerm_subnet.func_subnet.id]
bypass = ["Metrics", "Logging", "AzureServices"]
}

resource "azurerm_storage_container" "func" {
name = "func-sc"
storage_account_name = azurerm_storage_account.func.name
container_access_type = "private"
}

Create Private Endpints

resource "azurerm_private_endpoint" "file_endpoint" {
name = "rdtest_file_pe"
resource_group_name = azurerm_resource_group.func_rg.name
location = azurerm_resource_group.func_rg.location
subnet_id = azurerm_subnet.endpoint_subnet.id
private_service_connection {
name = "rdtest_file_psc"
private_connection_resource_id = azurerm_storage_account.func.id
is_manual_connection = false
subresource_names = ["file"]
}
}

resource "azurerm_private_endpoint" "blob_endpoint" {
name = "rdtest_blob_pe"
resource_group_name = azurerm_resource_group.func_rg.name
location = azurerm_resource_group.func_rg.location
subnet_id = azurerm_subnet.endpoint_subnet.id
private_service_connection {
name = "rdtest_blob_psc"
private_connection_resource_id = azurerm_storage_account.func.id
is_manual_connection = false
subresource_names = ["blob"]
}
}

resource "azurerm_private_endpoint" "table_endpoint" {
name = "rdtest_table_pe"
resource_group_name = azurerm_resource_group.func_rg.name
location = azurerm_resource_group.func_rg.location
subnet_id = azurerm_subnet.endpoint_subnet.id
private_service_connection {
name = "rdtest_table_psc"
private_connection_resource_id = azurerm_storage_account.func.id
is_manual_connection = false
subresource_names = ["table"]
}
}

resource "azurerm_private_endpoint" "queue_endpoint" {
name = "rdtest_queue_pe"
resource_group_name = azurerm_resource_group.func_rg.name
location = azurerm_resource_group.func_rg.location
subnet_id = azurerm_subnet.endpoint_subnet.id
private_service_connection {
name = "rdtest_queue_psc"
private_connection_resource_id = azurerm_storage_account.func.id
is_manual_connection = false
subresource_names = ["queue"]
}
}

Create DNS A Records

resource "azurerm_private_dns_a_record" "blob_dns_a" {
name = "rdfunctestblobdns"
zone_name = azurerm_private_dns_zone.blob_dns_zone.name
resource_group_name = azurerm_resource_group.func_rg.name
ttl = 300
records = [azurerm_private_endpoint.blob_endpoint.private_service_connection.0.private_ip_address]
}

resource "azurerm_private_dns_a_record" "file_dns_a" {
name = "filedns"
zone_name = azurerm_private_dns_zone.file_dns_zone.name
resource_group_name = azurerm_resource_group.func_rg.name
ttl = 300
records = [azurerm_private_endpoint.file_endpoint.private_service_connection.0.private_ip_address]
}

resource "azurerm_private_dns_a_record" "table_dns_a" {
name = "tabledns"
zone_name = azurerm_private_dns_zone.table_dns_zone.name
resource_group_name = azurerm_resource_group.func_rg.name
ttl = 300
records = [azurerm_private_endpoint.table_endpoint.private_service_connection.0.private_ip_address]
}

resource "azurerm_private_dns_a_record" "queue_dns_a" {
name = "queuedns"
zone_name = azurerm_private_dns_zone.queue_dns_zone.name
resource_group_name = azurerm_resource_group.func_rg.name
ttl = 300
records = [azurerm_private_endpoint.queue_endpoint.private_service_connection.0.private_ip_address]
}

resource "azurerm_service_plan" "func" {
name = "func_sp"
resource_group_name = azurerm_resource_group.func_rg.name
location = azurerm_resource_group.func_rg.location
os_type = "Linux"
sku_name = "EP1"
}

resource "azurerm_linux_function_app" "func" {
name = "rd-test-func"
resource_group_name = azurerm_resource_group.func_rg.name
location = azurerm_resource_group.func_rg.location
virtual_network_subnet_id = azurerm_subnet.func_subnet.id
storage_account_name = azurerm_storage_account.func.name
storage_account_access_key = azurerm_storage_account.func.primary_access_key
service_plan_id = azurerm_service_plan.func.id
site_config {
application_stack {
node_version = 16
}
}
}

I get this error from that config

│ Error: creating Linux Function App: (Site Name "rd-test-func" / Resource Group "func"): web.AppsClient#CreateOrUpdate: Failure sending request: StatusCode=400 -- Original Error: Code="BadRequest" Message="Creation of storage file share failed with: 'The remote server returned an error: (403) Forbidden.'. Please check if the storage account is accessible." Details=[{"Message":"Creation of storage file share failed with: 'The remote server returned an error: (403) Forbidden.'. Please check if the storage account is accessible."},{"Code":"BadRequest"},{"ErrorEntity":{"Code":"BadRequest","ExtendedCode":"99022","Message":"Creation of storage file share failed with: 'The remote server returned an error: (403) Forbidden.'. Please check if the storage account is accessible.","MessageTemplate":"Creation of storage file share failed with: '{0}'. Please check if the storage account is accessible.","Parameters":["The remote server returned an error: (403) Forbidden."]}}]

│ with azurerm_linux_function_app.func,
│ on main.tf line 236, in resource "azurerm_linux_function_app" "func":
│ 236: resource "azurerm_linux_function_app" "func" {

│ creating Linux Function App: (Site Name "rd-test-func" / Resource Group "func"): web.AppsClient#CreateOrUpdate: Failure sending request: StatusCode=400 -- Original Error: Code="BadRequest" Message="Creation of storage
│ file share failed with: 'The remote server returned an error: (403) Forbidden.'. Please check if the storage account is accessible." Details=[{"Message":"Creation of storage file share failed with: 'The remote server
│ returned an error: (403) Forbidden.'. Please check if the storage account is accessible."},{"Code":"BadRequest"},{"ErrorEntity":{"Code":"BadRequest","ExtendedCode":"99022","Message":"Creation of storage file share
│ failed with: 'The remote server returned an error: (403) Forbidden.'. Please check if the storage account is accessible.","MessageTemplate":"Creation of storage file share failed with: '{0}'. Please check if the
│ storage account is accessible.","Parameters":["The remote server returned an error: (403) Forbidden."]}}]

If I take out the `azurerm_storage_account_network_rules`, which I need for compliance, the config will deploy, but publishing the function fails on syncing triggers.

func azure functionapp publish rd-test-func
Getting site publishing info...
Uploading package...
Uploading 1.35 KB [###############################################################################]
Upload completed successfully.
Deployment completed successfully.
Syncing triggers...
Syncing triggers...
Syncing triggers...
Syncing triggers...
Syncing triggers...
Syncing triggers...
Error calling sync triggers (BadRequest).

If I remove `virtual_network_subnet_id  = azurerm_subnet.func_subnet.id` from `azurerm_linux_function_app` as well the function will publish, but I need the function app connecting over the private endpoint or with network rules.
Anyone know how to get this to work?
</details>
# 答案1
**得分**: 1
`azurerm_service_plan`需要使用`sku_name = "B1"`或更高版本才能与`azurerm_storage_account_network_rules`的VNet集成正常工作。以下内容适用于B1、S1和P1v2。
```json
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "func_rg" {
name     = "func"
location = "eastus"
}
resource "azurerm_virtual_network" "func" {
name                = "func_vnet"
address_space       = ["10.0.0.0/16"]
resource_group_name = azurerm_resource_group.func_rg.name
location            = azurerm_resource_group.func_rg.location
}
resource "azurerm_subnet" "func_subnet" {
name                 = "func_subnet"
resource_group_name  = azurerm_resource_group.func_rg.name
virtual_network_name = azurerm_virtual_network.func.name
address_prefixes     = ["10.0.1.0/24"]
service_endpoints    = ["Microsoft.Storage"]
delegation {
name = "delegation"
service_delegation {
name = "Microsoft.Web/serverFarms"
}
}
}
resource "azurerm_storage_account" "func" {
name                     = "rdtestfuncsa"
resource_group_name      = azurerm_resource_group.func_rg.name
location                 = azurerm_resource_group.func_rg.location
account_tier             = "Standard"
account_replication_type = "LRS"
}
resource "azurerm_storage_account_network_rules" "func" {
storage_account_id = azurerm_storage_account.func.id
default_action             = "Deny"
ip_rules                   = ["***.***.***.***"]
virtual_network_subnet_ids = [azurerm_subnet.func_subnet.id]
bypass                     = ["Metrics", "Logging", "AzureServices"]
}
resource "azurerm_service_plan" "func" {
name                = "func_sp"
resource_group_name = azurerm_resource_group.func_rg.name
location            = azurerm_resource_group.func_rg.location
os_type             = "Linux"
sku_name            = "B1"
}
resource "azurerm_linux_function_app" "func" {
name                       = "rd-test-func"
resource_group_name        = azurerm_resource_group.func_rg.name
location                   = azurerm_resource_group.func_rg.location
virtual_network_subnet_id  = azurerm_subnet.func_subnet.id
storage_account_name       = azurerm_storage_account.func.name
storage_account_access_key = azurerm_storage_account.func.primary_access_key
service_plan_id            = azurerm_service_plan.func.id
site_config {
application_stack {
node_version = 16
}
}
}
英文:

Turns out azurerm_service_plan needs sku_name = &quot;B1&quot; or better for the vnet integration with azurerm_storage_account_network_rules to work. The following worked with B1, S1 and P1v2.

provider &quot;azurerm&quot; {
features {}
}
resource &quot;azurerm_resource_group&quot; &quot;func_rg&quot; {
name     = &quot;func&quot;
location = &quot;eastus&quot;
}
resource &quot;azurerm_virtual_network&quot; &quot;func&quot; {
name                = &quot;func_vnet&quot;
address_space       = [&quot;10.0.0.0/16&quot;]
resource_group_name = azurerm_resource_group.func_rg.name
location            = azurerm_resource_group.func_rg.location
}
resource &quot;azurerm_subnet&quot; &quot;func_subnet&quot; {
name                 = &quot;func_subnet&quot;
resource_group_name  = azurerm_resource_group.func_rg.name
virtual_network_name = azurerm_virtual_network.func.name
address_prefixes     = [&quot;10.0.1.0/24&quot;]
service_endpoints    = [&quot;Microsoft.Storage&quot;]
delegation {
name = &quot;delegation&quot;
service_delegation {
name = &quot;Microsoft.Web/serverFarms&quot;
}
}
}
resource &quot;azurerm_storage_account&quot; &quot;func&quot; {
name                     = &quot;rdtestfuncsa&quot;
resource_group_name      = azurerm_resource_group.func_rg.name
location                 = azurerm_resource_group.func_rg.location
account_tier             = &quot;Standard&quot;
account_replication_type = &quot;LRS&quot;
}
resource &quot;azurerm_storage_account_network_rules&quot; &quot;func&quot; {
storage_account_id = azurerm_storage_account.func.id
default_action             = &quot;Deny&quot;
ip_rules                   = [&quot;***.***.***.***&quot;]
virtual_network_subnet_ids = [azurerm_subnet.func_subnet.id]
bypass                     = [&quot;Metrics&quot;, &quot;Logging&quot;, &quot;AzureServices&quot;]
}
resource &quot;azurerm_service_plan&quot; &quot;func&quot; {
name                = &quot;func_sp&quot;
resource_group_name = azurerm_resource_group.func_rg.name
location            = azurerm_resource_group.func_rg.location
os_type             = &quot;Linux&quot;
sku_name            = &quot;B1&quot;
}
resource &quot;azurerm_linux_function_app&quot; &quot;func&quot; {
name                       = &quot;rd-test-func&quot;
resource_group_name        = azurerm_resource_group.func_rg.name
location                   = azurerm_resource_group.func_rg.location
virtual_network_subnet_id  = azurerm_subnet.func_subnet.id
storage_account_name       = azurerm_storage_account.func.name
storage_account_access_key = azurerm_storage_account.func.primary_access_key
service_plan_id            = azurerm_service_plan.func.id
site_config {
application_stack {
node_version = 16
}
}
}

答案2

得分: 0

以下内容应该有效。

您需要预先创建一个用于函数内容的共享,可以自己命名。然后将以下内容添加为应用设置,以配置函数。

有关这些设置以及为什么需要它们的更多信息,请参阅https://learn.microsoft.com/en-us/azure/azure-functions/functions-app-settings#website_contentshare

应用设置

WEBSITE_CONTENTAZUREFILECONNECTIONSTRING = azurerm_storage_account.func.primary_connection_string
AzureWebJobsStorage = azurerm_storage_account.func.primary_connection_string
WEBSITE_CONTENTSHARE = {预先创建的共享名称}
英文:

the following should work.

You'll need to pre-create a share for the functions content you can name this whatever you want. Then add the following as app setting, to the functions configuration.

More info in these settings and why you'll need them https://learn.microsoft.com/en-us/azure/azure-functions/functions-app-settings#website_contentshare

app_settings

WEBSITE_CONTENTAZUREFILECONNECTIONSTRING = azurerm_storage_account.func.primary_connection_string    
AzureWebJobsStorage                      = azurerm_storage_account.func.primary_connection_string
WEBSITE_CONTENTSHARE                     = {name of pre-created share}

huangapple
  • 本文由 发表于 2023年1月9日 06:40:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/75051784.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定