跨VNET/环境安全访问Azure Container App的最优Terraform配置问询
我是Azure网络新手,在不同资源组、VNET中部署了两个Azure Container App(A和B),希望通过VNET/子网对等连接,用静态自定义名称实现二者安全互访。
当前问题1:自定义CNAME访问失败
完成VNET对等后,通过Terraform配置私有DNS区域,以B的最新修订版FQDN创建CNAME记录。使用FQDN可正常互访,但通过自定义CNAME(如myAppA.internal)访问时,虽nslookup解析正确,但curl请求失败,提示This Container App is stopped or does not exist.。相关Terraform代码如下:
resource "azurerm_subnet" "containerEnv" { name = "${var.name}-containerEnv" resource_group_name = var.resource_group_name virtual_network_name = azurerm_virtual_network.main.name address_prefixes = ["10.0.2.0/23"] service_endpoints = ["Microsoft.Storage"] } resource "azurerm_virtual_network" "main" { name = "${var.name}-vnet" location = var.location resource_group_name = var.resource_group_name address_space = ["10.0.0.0/16"] } resource "azurerm_container_app_environment" "main" { name = var.name location = var.location resource_group_name = var.resource_group_name log_analytics_workspace_id = azurerm_log_analytics_workspace.main.id infrastructure_subnet_id = azurerm_subnet.containerEnv.id } resource "azurerm_private_dns_zone" "main" { name = "${var.name}.internal" resource_group_name = var.resource_group_name } resource "azurerm_private_dns_zone_virtual_network_link" "main" { name = "${var.name}-link" private_dns_zone_name = azurerm_private_dns_zone.main.name resource_group_name = var.resource_group_name virtual_network_id = azurerm_virtual_network.main.id } resource "azurerm_private_dns_zone_virtual_network_link" "networkB" { for_each = var.remote_virtual_network_ids name = "${var.name}-B-link" private_dns_zone_name = azurerm_private_dns_zone.main.name resource_group_name = var.resource_group_name virtual_network_id = each.value } resource "azurerm_private_dns_cname_record" "appA" { name = local.name record = azurerm_container_app.main.latest_revision_fqdn resource_group_name = var.resource_group_name ttl = 300 zone_name = var.dns_zone_name } resource "azurerm_virtual_network_peering" "B" { for_each = var.remote_virtual_network_ids name = "peer-to-remote-B" remote_virtual_network_id = each.value resource_group_name = var.resource_group_name virtual_network_name = azurerm_virtual_network.main.name # TODO Seems to have implications public DNS entries, shelved for now. # peer_complete_virtual_networks_enabled = false # local_subnet_names = [azurerm_subnet.containerEnv.name] # remote_subnet_names = var.remote_subnet_names lifecycle { replace_triggered_by = [azurerm_virtual_network.main] } }
当前问题2:访问控制依赖动态出站IP
目前通过将A的环境出站IP加入B的入站IP白名单实现访问,但该IP可能变更,且无法使用子网连接范围配置。相关Terraform代码如下:
resource "azurerm_container_app" "A" { name = local.name container_app_environment_id = var.container_app_environment_id resource_group_name = var.resource_group_name revision_mode = "Single" (...) ingress { external_enabled = true allow_insecure_connections = false target_port = 1234 traffic_weight { percentage = 100 latest_revision = true } dynamic "ip_security_restriction" { for_each = var.allowed_ip_ranges content { ip_address_range = ip_security_restriction.value action = "Allow" name = "A" } } } template { min_replicas = 1 max_replicas = 1 container { name = local.A image = "registry" cpu = "0.5" memory = "1Gi" } } }
现寻求:
- 无需非静态IP白名单的跨子网/VNET安全通信方案
- 基于Terraform自动化的简洁易懂的双向互访最优配置方案
一、自定义CNAME访问失败的修复
Azure Container App的Ingress会验证请求的Host头,只有匹配其自身FQDN的请求才会被正确路由。直接用CNAME指向修订版FQDN时,请求的Host头是自定义域名(如myAppA.internal),不匹配容器应用的默认FQDN,导致路由失败。
修复步骤(Terraform配置)
- 为容器应用配置自定义域名绑定,将自定义域名关联到容器应用:
resource "azurerm_container_app_custom_hostname_binding" "appA" { name = local.name container_app_id = azurerm_container_app.main.id hostname = "${local.name}.${var.dns_zone_name}" # 对应myAppA.internal ssl_state = "Disabled" # 内部访问可禁用SSL,需加密可配置私有证书 }
- 保留原有的私有DNS CNAME记录,确保解析正确。
配置完成后,请求的Host头会匹配绑定的自定义域名,Ingress即可正确路由到容器应用。
二、跨VNET安全通信(无需静态IP白名单)
利用VNET对等连接的子网信任关系,直接在容器应用的Ingress安全规则中允许对方VNET的子网CIDR,替代动态出站IP白名单。
核心配置要点
- 确保VNET对等连接双向配置完成(双方都创建对等链接,且启用
allow_virtual_network_access) - 在容器应用的Ingress中,添加对方VNET的子网CIDR到IP安全规则
Terraform双向互访配置示例
容器应用A的Ingress安全规则(允许B的VNET子网)
resource "azurerm_container_app" "A" { # 原有配置... ingress { external_enabled = true allow_insecure_connections = false target_port = 1234 traffic_weight { percentage = 100 latest_revision = true } # 允许自身VNET子网 ip_security_restriction { ip_address_range = azurerm_virtual_network.main.address_space[0] # 10.0.0.0/16 action = "Allow" name = "Self-VNET" } # 允许B的VNET子网 dynamic "ip_security_restriction" { for_each = var.remote_vnet_subnet_cidrs content { ip_address_range = ip_security_restriction.value action = "Allow" name = "Remote-VNET-B" } } } # 原有配置... }
容器应用B的Ingress安全规则(允许A的VNET子网)
同理,在B的Terraform配置中添加A的VNET子网CIDR到IP安全规则即可。
完善VNET对等连接配置
确保对等连接启用必要的访问权限:
resource "azurerm_virtual_network_peering" "to_B" { for_each = var.remote_virtual_network_ids name = "peer-to-${each.key}" remote_virtual_network_id = each.value resource_group_name = var.resource_group_name virtual_network_name = azurerm_virtual_network.main.name allow_virtual_network_access = true allow_forwarded_traffic = true allow_gateway_transit = false use_remote_gateways = false lifecycle { replace_triggered_by = [azurerm_virtual_network.main] } }
注意:需在B的资源组中创建反向的VNET对等链接,配置相同的allow_virtual_network_access参数。
三、完整双向互访Terraform配置简化建议
- 用变量统一管理双方VNET的ID和子网CIDR,避免硬编码
- 为双方容器应用分别配置自定义域名绑定和私有DNS记录
- 双向VNET对等连接+子网级IP安全规则,确保通信安全
内容的提问来源于stack exchange,提问作者honest_annie

