你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

大规模专用链接和 DNS 集成

本文介绍如何在中心辐射型网络架构中,将具有 Azure 专用 DNS 区域的平台即服务(PaaS)解决方案与 Azure 专用链接集成。

介绍

许多客户使用中心辐射型网络体系结构在 Azure 中构建其网络基础结构,其中:

  • 网络共享服务(例如网络虚拟设备(NVA)、ExpressRoute/VPN 网关或 DNS 服务器)部署在 中心 虚拟网络中。
  • 分支虚拟网络通过虚拟网络对等互连使用共享服务

在中心辐射型网络体系结构中,应用程序所有者通常拥有 Azure 订阅,其中包括连接到中心虚拟网络的虚拟网络(分支)。 在此体系结构中,他们可以部署虚拟机,并通过 ExpressRoute 或 VPN 与其他虚拟网络或本地网络建立专用连接。

中心 NVA(如 Azure 防火墙)提供 Internet 出站连接。 此外,该设备与中心内或中心附近的其他服务(例如 Azure 防火墙 DNS 代理)结合使用,通常用于自定义 DNS 转发。

许多应用程序团队使用 Azure IaaS 和 PaaS 资源的组合来构建其解决方案。 某些 Azure PaaS 服务(例如 Azure SQL 托管实例)可以在客户虚拟网络中部署。 因此,流量在 Azure 网络中保持私密性,可从本地完全路由。

但是,某些 Azure PaaS 服务(例如 Azure 存储或 Azure Cosmos DB)无法部署在客户的虚拟网络中,并且可通过其公共终结点进行访问。 在某些情况下,此配置会导致与用户的安全策略发生冲突。 企业流量可能不允许通过公共终结点部署或访问公司资源(例如 SQL 数据库)。

专用链接 支持通过专用终结点访问 Azure 服务列表 ,但要求在相应的 专用 DNS 区域中注册这些专用终结点记录。

本文介绍了应用程序团队如何在仅可通过专用终结点访问的订阅中部署 Azure PaaS 服务。

本文还介绍了应用程序团队如何确保服务自动与专用 DNS 区域集成。 它们通过 Azure 专用 DNS 实现自动化,无需在 DNS 中手动创建或删除记录。

专用 DNS 区域通常集中托管在部署中心虚拟网络的同一 Azure 订阅中。 这种中央托管做法由 跨界 DNS 名称解析 和其他中央 DNS 解析需求(如 Windows Server Active Directory)驱动。 在大多数情况下,只有网络和标识管理员有权管理区域中的 DNS 记录。

应用程序团队有权在自己的订阅中创建 Azure 资源。 它们在中央网络连接订阅中没有任何权限,包括管理专用 DNS 区域中的 DNS 记录。 此访问限制意味着,在使用专用终结点部署 Azure PaaS 服务时,他们无法 创建所需的 DNS 记录

下图显示了通过 Azure 专用 DNS 为专用链接资源提供中央 DNS 解析和名称解析的企业环境的典型高级体系结构:

包含中央 DNS 解析和名称解析的专用链接资源高层架构示意图。

在上图中,必须突出显示这一点:

  • 本地 DNS 服务器为每个专用终结点公共 DNS 区域配置条件转发器,指向中心虚拟网络中托管的 DNS 专用解析程序。

  • 中心虚拟网络中托管的 DNS 专用解析程序使用 Azure 提供的 DNS(168.63.129.16)作为转发器。

  • 中心虚拟网络必须链接到 Azure 服务的专用 DNS 区域名称,如 privatelink.blob.core.windows.net图中所示。

  • 所有 Azure 虚拟网络都使用中心虚拟网络中托管的 DNS 专用解析程序。

  • DNS 专用解析程序对客户的公司域(如 Active Directory 域名)不具有权威性,因为它只是转发器。 DNS 专用解析程序应具有客户公司域的出站终结点转发器,指向本地 DNS 服务器(172.16.1.10 和 172.16.1.11)或部署在 Azure 中对此类区域具有权威性的 DNS 服务器。

注释

可以将 DNS 专用解析程序与 ExpressRoute 网关一起部署在中心虚拟网络中。 但是,必须确保允许解析公共 FQDN,并通过 DNS 转发规则集规则向目标 DNS 服务器回复有效响应。 某些 Azure 服务依赖于解析公共 DNS 名称来发挥功能。 有关详细信息,请参阅 DNS 转发规则集规则

虽然上图描绘了单个中心辐射型体系结构,但客户可能需要跨多个区域扩展其 Azure 占用空间,以解决复原能力、邻近性或数据驻留要求。 在多个方案中,必须通过多个专用终结点访问启用同一专用链接的 PaaS 实例。

下图显示了一个典型的高级体系结构,适用于在中心(每个区域部署有中央 DNS 解析)的企业环境,其中专用链接资源的名称解析是通过 Azure 专用 DNS 完成的。

包含多个区域中专用链接资源的中央 DNS 解析和名称解析的高级体系结构示意图。

应部署与 PaaS 实例关联的多个区域专用终结点,每个区域中都有一个客户端。 为每个区域启用专用链接和专用 DNS 区域。 使用具有内置灾难恢复功能的 PaaS 服务(例如异地冗余存储帐户和 SQL 数据库故障转移组)时,必须在多个区域中具有专用终结点。

此方案要求在每个区域中手动维护和更新专用链接 DNS 记录集,因为目前没有这些记录的自动化生命周期管理。

对于其他用例,可以部署一个全球性的单一专用终结点,通过将路由从相关区域添加到单一区域的单一专用终结点,使所有客户端都可以访问。

若要从本地网络到 privatelink 专用 DNS 区域和专用终结点实现解析和连接,请在 DNS 基础结构中预配适当的 DNS 配置,例如条件转发器。

应用程序团队在其订阅中创建任何所需的 Azure PaaS 资源必须满足的两个条件:

  • 中心网络或中心平台团队必须确保应用程序团队只能通过专用终结点部署和访问 Azure PaaS 服务。

  • 中心网络或中心平台团队必须确保在创建专用终结点时,设置如何处理相应的记录。 设置相应的记录,以便在与所创建服务匹配的集中式专用 DNS 区域中自动创建这些记录。

  • DNS 记录必须遵循专用终结点的生命周期,以便在删除专用终结点时自动删除这些记录。

注释

根据 DNS 解析,如果需要在 Azure 防火墙和 Azure 防火墙策略的网络规则中使用 FQDN,请启用 Azure 防火墙 DNS 代理,以便在网络规则中使用 FQDN。 然后,分支虚拟网络必须将其 DNS 的设置从自定义 DNS 服务器更改为 Azure 防火墙 DNS 代理。 网络规则中的 FQDN 允许使用任何 TCP 或 UDP 协议(包括 NTP、SSH 和 RDP)筛选出站流量。 更改分支虚拟网络的 DNS 设置后,必须重启该虚拟网络中的所有 VM。

以下部分介绍了应用程序团队如何使用 Azure Policy 启用这些条件。 此示例使用 Azure 存储作为应用程序团队需要部署的 Azure 服务。 但相同的原则适用于 支持专用链接的大多数 Azure 服务

平台团队配置要求

平台团队配置要求包括创建专用 DNS 区域、设置策略定义、部署策略和设置策略分配。

创建专用 DNS 区域

在中央连接订阅中为支持的专用链接服务创建专用 DNS 区域。 有关详细信息,请参阅 Azure 专用终结点 DNS 配置

在这种情况下, 包含 Blob 的存储帐户 就是示例。 它转换为在连接订阅中创建 privatelink.blob.core.windows.net 专用 DNS 区域。

显示连接订阅中的专用 DNS 区域的屏幕截图。

创建策略定义

除了专用 DNS 区域,还需要 创建一组自定义 Azure Policy 定义。 这些定义强制使用专用终结点,并在创建的 DNS 区域中自动创建 DNS 记录:

  1. PaaS 服务策略的 Deny 公共终结点。

    此策略可防止用户使用公共终结点创建 Azure PaaS 服务。

    显示所选所有网络选项的公共终结点的屏幕截图。

    如果用户在创建资源时未选择专用终结点,则会收到错误消息。

    显示从选取公共终结点产生的错误消息的屏幕截图。

    显示选取公共终结点时完整错误详细信息的屏幕截图。

    PaaS 服务之间的确切策略规则可能有所不同。 对于 Azure 存储帐户, networkAcls.defaultAction 属性定义是否允许来自公用网络的请求。 在这种情况下,如果属性 networkAcls.defaultAction 不是Deny,则设置一个条件来拒绝创建 Microsoft.Storage/storageAccounts 资源类型。 以下策略定义显示了行为:

    {
      "mode": "All",
      "policyRule": {
        "if": {
          "allOf": [
            {
              "field": "type",
              "equals": "Microsoft.Storage/storageAccounts"
            },
            {
              "field": "Microsoft.Storage/storageAccounts/networkAcls.defaultAction",
              "notEquals": "Deny"
            }
          ]
        },
        "then": {
          "effect": "Deny"
        }
      }
    }
    
  2. Deny 能够创建带有 privatelink 前缀策略的专用 DNS 区域。

    将集中式 DNS 体系结构与平台团队管理的订阅中托管的条件转发器和专用 DNS 区域配合使用。 有必要防止应用程序团队所有者创建自己的 Private Link 专用 DNS 区域,并将服务关联到其订阅。

    确保当应用程序团队创建专用终结点时,在 Azure 门户中将Integrate with private DNS zone选项设置为No

    显示 Azure 门户中“与专用 DNS 区域集成”选项设置为“否”的屏幕截图。

    如果选择 Yes,Azure Policy 将阻止创建专用终结点。 在策略定义中,如果区域具有privatelink前缀,则拒绝创建 Microsoft.Network/privateDnsZones 资源类型的能力。 以下策略定义显示 privatelink 前缀:

    {
      "description": "This policy restricts creation of private DNS zones with the `privatelink` prefix",
      "displayName": "Deny-PrivateDNSZone-PrivateLink",
      "mode": "All",
      "parameters": null,
      "policyRule": {
        "if": {
          "allOf": [
            {
              "field": "type",
              "equals": "Microsoft.Network/privateDnsZones"
            },
            {
              "field": "name",
              "contains": "privatelink."
            }
          ]
        },
        "then": {
          "effect": "Deny"
        }
      }
    }
    
  3. DeployIfNotExists 策略,用于在中央专用 DNS 区域中自动创建所需的 DNS 记录。

    以下策略示例展示了两种识别在专用终结点上创建的 privateDNSZoneGroup 的方法。

    第一个策略依赖于 groupId,而第二个策略使用 privateLinkServiceIdgroupID。 当与另一个资源发生冲突或碰撞时,请使用第二个策略groupId

    例如, groupIdSQL 用于 Azure Cosmos DB 和 Azure Synapse Analytics。 如果两种资源类型均已部署,并且已分配第一个策略以在专用终结点条目上创建 privateDNSZoneGroup,则会进行创建并将其映射到 Azure Cosmos DB 或 Azure Synapse Analytics 的错误专用 DNS 区域。 然后,由于第一个策略在其策略规则中查找的冲突 groupId,它可能会在各个区域之间切换。

    有关私有链接资源的列表groupId,请参阅 “什么是私有终结点?”中的子资源列。

小提示

不断添加、删除和更新 Azure Policy 内置定义。 应使用内置策略,而不是管理自己的策略(如果可用)。 使用 AzPolicyAdvertizer 查找现有内置策略,这些策略具有名称“xxx...以使用专用 DNS 区域”。 此外,Azure 登陆区域(ALZ)具有策略计划, 将 Azure PaaS 服务配置为使用专用 DNS 区域,其中包含定期更新的内置策略。 如果内置策略不适用于你的情况,请考虑按照 Azure Policy GitHub 存储库上的内置策略建议流程,在azure-policy反馈站点 Azure 治理社区上创建一个想法。

仅适用于 groupId 的 DeployIfNotExists 策略

如果创建具有服务特定 groupId 的专用终结点资源,则会触发此策略。 groupId 是从此专用终结点应连接到的远程资源(服务)获取的组的 ID。 然后,它会在专用终结点内触发一个 privateDNSZoneGroup 的部署,从而将专用终结点与专用 DNS 区域关联起来。 在此示例中,适用于 Azure 存储 blob 的 groupIdblob。 有关其他 Azure 服务的详细信息groupId,请参阅 Azure 专用终结点 DNS 配置中的子资源列。 当策略找到 groupId 专用终结点时,它会在专用终结点中部署一个 privateDNSZoneGroup ,并将其链接到指定为参数的专用 DNS 区域资源 ID。 在此示例中,专用 DNS 区域资源 ID 为:

/subscriptions/<subscription-id>/resourceGroups/<resourceGroupName>/providers/Microsoft.Network/privateDnsZones/privatelink.blob.core.windows.net

以下代码示例显示了策略定义:

{
  "mode": "Indexed",
  "policyRule": {
    "if": {
      "allOf": [
        {
          "field": "type",
          "equals": "Microsoft.Network/privateEndpoints"
        },
        {
          "count": {
            "field": "Microsoft.Network/privateEndpoints/privateLinkServiceConnections[*].groupIds[*]",
            "where": {
              "field": "Microsoft.Network/privateEndpoints/privateLinkServiceConnections[*].groupIds[*]",
              "equals": "blob"
            }
          },
          "greaterOrEquals": 1
        }
      ]
    },
    "then": {
      "effect": "deployIfNotExists",
      "details": {
        "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups",
        "roleDefinitionIds": [
          "/providers/Microsoft.Authorization/roleDefinitions/4d97b98b-1d4f-4787-a291-c67834d212e7"
        ],           
        "deployment": {
          "properties": {
            "mode": "incremental",
            "template": {
              "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
              "contentVersion": "1.0.0.0",
              "parameters": {
                "privateDnsZoneId": {
                  "type": "string"
                },
                "privateEndpointName": {
                  "type": "string"
                },
                "___location": {
                  "type": "string"
                }
              },
              "resources": [
                {
                  "name": "[concat(parameters('privateEndpointName'), '/deployedByPolicy')]",
                  "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups",
                  "apiVersion": "2020-03-01",
                  "___location": "[parameters('___location')]",
                  "properties": {
                    "privateDnsZoneConfigs": [
                      {
                        "name": "storageBlob-privateDnsZone",
                        "properties": {
                          "privateDnsZoneId": "[parameters('privateDnsZoneId')]"
                        }
                      }
                    ]
                  }
                }
              ]
            },
            "parameters": {
              "privateDnsZoneId": {
                "value": "[parameters('privateDnsZoneId')]"
              },
              "privateEndpointName": {
                "value": "[field('name')]"
              },
              "___location": {
                "value": "[field('___location')]"
              }
            }
          }
        }
      }
    }
  },
  "parameters": {
    "privateDnsZoneId": {
      "type": "String",
      "metadata": {
        "displayName": "privateDnsZoneId",
        "strongType": "Microsoft.Network/privateDnsZones"
      }
    }
  }
}

适用于 groupId 和 privateLinkServiceId 的 DeployIfNotExists 策略

如果创建具有服务特定 groupIdprivateLinkServiceId 的专用终结点资源,则会触发此策略。 groupId 是从此专用终结点应连接到的远程资源(服务)获取的组的 ID。 privateLinkServiceId 是此专用终结点应连接的远程资源(服务)的资源 ID。 然后,在专用终结点中触发一个 privateDNSZoneGroup 部署,将专用终结点与专用 DNS 区域关联起来。

在此示例中,groupId 对于 Azure Cosmos DB(SQL)是 SQL,且 privateLinkServiceId 必须包含 Microsoft.DocumentDb/databaseAccounts。 有关其他 Azure 服务的详细信息groupIdprivateLinkServiceId,请参阅 Azure 专用终结点 DNS 配置中的子资源列。 当策略在专用终结点中找到 groupIdprivateLinkServiceId 时,它会在专用终结点中部署一个 privateDNSZoneGroup 。 它链接到指定为参数的专用 DNS 区域资源 ID。 以下策略定义显示了专用 DNS 区域资源 ID:

/subscriptions/<subscription-id>/resourceGroups/<resourceGroupName>/providers/Microsoft.Network/privateDnsZones/privatelink.documents.azure.com

以下代码示例显示了策略定义:

{
  "mode": "Indexed",
  "policyRule": {
    "if": {
     "allOf": [
       {
         "field": "type",
         "equals": "Microsoft.Network/privateEndpoints"
       },
       {
         "count": {
           "field": "Microsoft.Network/privateEndpoints/privateLinkServiceConnections[*]",
           "where": {
             "allOf": [
               {
                 "field": "Microsoft.Network/privateEndpoints/privateLinkServiceConnections[*].privateLinkServiceId",
                 "contains": "Microsoft.DocumentDb/databaseAccounts"
               },
               {
                 "field": "Microsoft.Network/privateEndpoints/privateLinkServiceConnections[*].groupIds[*]",
                 "equals": "[parameters('privateEndpointGroupId')]"
               }
             ]
           }
         },
         "greaterOrEquals": 1
       }
     ]
   },
    "then": {
      "effect": "[parameters('effect')]",
      "details": {
        "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups",
        "roleDefinitionIds": [
          "/providers/Microsoft.Authorization/roleDefinitions/4d97b98b-1d4f-4787-a291-c67834d212e7"
        ],           
        "deployment": {
          "properties": {
            "mode": "incremental",
            "template": {
              "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
              "contentVersion": "1.0.0.0",
              "parameters": {
                "privateDnsZoneId": {
                  "type": "string"
                },
                "privateEndpointName": {
                  "type": "string"
                },
                "___location": {
                  "type": "string"
                }
              },
              "resources": [
                {
                  "name": "[concat(parameters('privateEndpointName'), '/deployedByPolicy')]",
                  "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups",
                  "apiVersion": "2020-03-01",
                  "___location": "[parameters('___location')]",
                  "properties": {
                    "privateDnsZoneConfigs": [
                      {
                        "name": "cosmosDB-privateDnsZone",
                        "properties": {
                          "privateDnsZoneId": "[parameters('privateDnsZoneId')]"
                        }
                      }
                    ]
                  }
                }
              ]
            },
            "parameters": {
              "privateDnsZoneId": {
                "value": "[parameters('privateDnsZoneId')]"
              },
              "privateEndpointName": {
                "value": "[field('name')]"
              },
              "___location": {
                "value": "[field('___location')]"
              }
            }
          }
        }
      }
    }
  },
  "parameters": {
     "privateDnsZoneId": {
       "type": "String",
       "metadata": {
         "displayName": "Private Dns Zone Id",
         "description": "The private DNS zone to deploy in a new private DNS zone group and link to the private endpoint",
         "strongType": "Microsoft.Network/privateDnsZones"
       }
     },
     "privateEndpointGroupId": {
       "type": "String",
       "metadata": {
         "displayName": "Private Endpoint Group Id",
         "description": "A group Id for the private endpoint"
       }
     },
     "effect": {
       "type": "String",
       "metadata": {
         "displayName": "Effect",
         "description": "Enable or disable the execution of the policy"
       },
       "allowedValues": [
         "DeployIfNotExists",
         "Disabled"
       ],
       "defaultValue": "DeployIfNotExists"
     }
  }
}

策略分配

部署策略定义后,在所需的管理组层次结构范围内 分配策略。 确保策略分配面向 Azure 订阅,应用程序团队会使用这些订阅以独占方式部署具有专用终结点访问权限的 PaaS 服务。

重要

除了分配策略中定义的 roleDefinition 之外,还需将专用 DNS 区域参与者角色分配给通过策略分配DeployIfNotExists创建的托管身份。 应在托管专用 DNS 区域的订阅和资源组中分配此角色。 托管标识在专用 DNS 区域中创建和管理专用终结点 DNS 记录。 此配置是必需的,因为专用终结点位于应用程序所有者 Azure 订阅中,而专用 DNS 区域位于其他订阅中,例如中央连接订阅。

平台团队完成配置后:

  • 应用程序团队的 Azure 订阅已准备就绪,团队可以创建具有专用终结点访问权限的 Azure PaaS 服务。

  • 团队必须确保专用终结点的 DNS 记录会自动注册到相应的专用 DNS 区域,并在删除专用终结点后删除 DNS 记录。

应用程序所有者部署 Azure PaaS 服务

在平台团队部署平台基础结构组件(专用 DNS 区域和策略)后,应用程序所有者在尝试将 Azure PaaS 服务部署到 Azure 订阅时执行以下步骤。 这些步骤与通过 Azure 门户或其他客户端(例如 PowerShell 或 CLI)执行其活动是相同的,因为 Azure 策略管理其订阅。

  1. 通过 Azure 门户创建存储帐户。 在“ 基本信息 ”选项卡中,选择所需的设置,提供存储帐户的名称,然后选择“ 下一步”。

    显示用于在 Azure 门户中创建存储帐户的“基本信息”选项卡和选项的屏幕截图。

  2. 在“网络”选项卡中,选择 “专用终结点”。 如果选择了 专用终结点以外的选项,则 Azure 门户不允许在部署向导的 “查看 + 创建 ”部分中创建存储帐户。 如果启用了公共终结点,该策略将阻止你创建此服务。

    显示“网络”选项卡和专用终结点选项的屏幕截图。

  3. 你可以在现在创建专用终结点,也可以在创建存储帐户之后再创建。 此示例演示如何在创建存储帐户后创建专用终结点。 选择 “查看 + 创建 ”以完成此步骤。

  4. 创建存储帐户后,通过 Azure 门户创建专用终结点。

    显示专用终结点设置的屏幕截图。

  5. “资源 ”部分中,找到在上一步中创建的存储帐户。 在目标子资源下,选择 Blob,然后选择“ 下一步”。

    显示用于选择目标子资源的“资源”选项卡的屏幕截图。

  6. “配置” 部分中,选择虚拟网络和子网后,请确保 “与专用 DNS 区域集成 ”设置为 “否”。 否则,Azure 门户将阻止您创建专用终结点。 Azure Policy 不允许创建具有前缀的 privatelink 专用 DNS 区域。

    显示用于将集成与专用 DNS 区域选项设置为“否”的“配置”选项卡的屏幕截图。

  7. 选择 “查看 + 创建”,然后选择“ 创建 ”以部署专用终结点。

  8. 几分钟后,策略 DeployIfNotExists 将触发。 然后,后续 dnsZoneGroup 部署会在集中管理的 DNS 区域中为专用终结点添加所需的 DNS 记录。

  9. 创建专用终结点后,选择它,并查看其 FQDN 和专用 IP:

    显示查看专用终结点、FQDN 和专用 IP 的位置的屏幕截图。

  10. 检查创建专用终结点的资源组的活动日志。 或者,可以检查专用终结点本身的活动日志。 几分钟后,策略操作 DeployIfNotExist 将运行,该操作将在专用终结点上配置 DNS 区域组。

    显示资源组和专用终结点的活动日志的屏幕截图。

  11. 如果中央网络团队转到 privatelink.blob.core.windows.net 专用 DNS 区域,则他们确认你创建的专用终结点存在 DNS 记录,并且名称和 IP 地址都与专用终结点中的值匹配。

    显示专用 DNS 区域以及确认 DNS 记录所在的位置的屏幕截图。

此时,应用程序团队可以通过中心辐射型网络环境中的任何虚拟网络和本地的专用终结点来使用存储帐户。 DNS 记录已自动记录在专用 DNS 区域中。

如果应用程序所有者删除专用终结点,则会自动删除专用 DNS 区域中的相应记录。

重要

你仍然可以在基础结构中创建专用终结点作为代码工具。 但是,如果使用 DeployIfNotExists 本文中的策略方法,则不应在代码中集成 DNS。 具有专用 DNS 区域所需 RBAC 的 DeployIfNotExists 策略可管理 DNS 集成。

后续步骤