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

大规模专用链接和 DNS 集成

本文介绍如何将适用于 PaaS 服务的 Azure 专用链接与中心辐射型网络体系结构中的 Azure 专用 DNS 区域集成。

介绍

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

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

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

中央网络虚拟设备(例如Azure 防火墙)提供 Internet 出站连接。 此外,该设备(例如使用 Azure 防火墙 DNS 代理)或中心相邻的其他服务通常用于自定义 DNS 转发。

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

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

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

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

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

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

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

下图显示了具有中心 DNS 解析的企业环境的典型高级体系结构,其中专用链接资源的名称解析是通过 Azure 专用 DNS 完成的:

具有中央 DNS 解析和专用链接资源名称解析的高级体系结构示意图。

在上图中,突出显示这一点非常重要:

  • 本地 DNS 服务器为每个专用终结点公共 DNS 区域配置了条件转发器,这些转发器指向托管在中心 VNet 中的专用 DNS 解析程序。
  • 托管在中心 VNet 中的专用 DNS 解析程序使用 Azure 提供的 DNS (168.63.129.16) 作为转发器。
  • 中心 VNet 必须链接到 Azure 服务的私人 DNS区域名称(如privatelink.blob.core.windows.net图中所示)。
  • 所有 Azure VNet 都使用中心 VNet 中托管私人 DNS解析程序
  • 由于私人 DNS解析程序对客户的公司域不具有权威性, 由于这只是转发器(例如 Active Directory 域名),因此它应将出站终结点转发器指向客户的企业域,指向本地 DNS 服务器(172.16.1.10 和 172.16.1.11)或 Azure 中部署的对此类区域的权威 DNS 服务器。

注意

可以在中心虚拟网络以及 ExpressRoute 网关等部署 DNS 专用解析程序。但是,必须确保允许解析公共 FQDN,并通过 DNS 转发规则集规则回复到目标 DNS 服务器的有效响应。 由于某些 Azure 服务依赖于将公共 DNS 名称解析为正常运行的能力。 在此处了解详细信息

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

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

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

建议部署与 PaaS 实例关联的多个区域专用终结点,每个区域中有一个客户端,启用每个区域专用链接和私人 DNS区域。 使用具有内置 DR 功能(异地冗余存储帐户、SQL DB 故障转移组等)的 PaaS 服务时,必须使用多个区域专用终结点。

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

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

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

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

  • 中心网络和/或中心平台团队必须确保应用程序团队只能通过专用终结点部署和访问 Azure PaaS 服务。
  • 中心网络和/或中心平台团队必须确保在创建专用终结点时,他们设置如何处理相应的记录。 设置相应的记录,以便在与所创建服务匹配的集中式专用 DNS 区域中自动创建这些记录。
  • DNS 记录必须遵循专用终结点的生命周期,在该生命周期中,删除专用终结点时会自动将其删除。

注意

如果需要在Azure 防火墙和防火墙策略中使用基于 DNS 解析的网络规则中的 FQDN(此功能允许使用任何 TCP/UDP 协议(包括 NTP、SSH、RDP 等)筛选出站流量。 必须启用Azure 防火墙 DNS 代理才能在网络规则中使用 FQDN,然后这些分支 VNet 强制将其 DNS 设置从自定义 DNS 服务器更改为Azure 防火墙 DNS 代理。 更改辐射 VNet 的 DNS 设置需要重新启动该 VNet 中的所有 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. Deny PaaS 服务策略的公共终结点。

    此策略可防止用户使用公共终结点创建 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 区域配合使用。 必须防止应用程序团队所有者创建自己的专用链接专用 DNS 区域并将服务链接到其订阅。

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

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

    如果选择 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二个策略同时使用这两privateLinkServiceId个策略和 groupID。 将与其他资源发生冲突(碰撞)时groupId,请使用第二个策略

    例如,groupIdSQL 用于 Cosmos DB 和 Synapse Analytics。 如果同时部署了资源类型和第一个策略以在专用终结点条目上创建privateDNSZoneGroup策略,则会创建并映射到 Cosmos DB 或 Synapse Analytics 的错误私人 DNS区域。 然后,由于第一个策略在其策略规则中查找的冲突 groupId ,它可能会在每个区域之间切换。

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

提示

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

第一个DeployIfNotExists策略 - 仅匹配groupId

如果创建具有特定于服务的 groupId专用终结点资源,则此策略将触发此策略。 groupId 是从此专用终结点应连接到的远程资源(服务)获取的组的 ID。 然后,它会触发专用终结点内的部署 privateDNSZoneGroup ,该终结点将专用终结点与专用 DNS 区域相关联。 在此示例中,Azure 存储 groupId blob 为 blob. 有关其他 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"
      }
    }
  }
}

第二DeployIfNotExists个策略 - 匹配groupIdprivateLinkServiceId

如果创建专用终结点资源且特定于服务的 groupId 专用终结点资源, privateLinkServiceId则此策略将触发此策略。 groupId 是从此专用终结点应连接到的远程资源(服务)获取的组的 ID。 privateLinkServiceId此专用终结点应连接到的远程资源(服务)的资源 ID。 然后,触发专用终结点内的部署 privateDNSZoneGroup ,该终结点将专用终结点与专用 DNS 区域相关联。

在此示例中,groupId对于 Azure Cosmos DB(SQL)是SQL必须包含Microsoft.DocumentDb/databaseAccountsprivateLinkServiceId 。 有关groupIdprivateLinkServiceId其他 Azure 服务的详细信息,请参阅“子资源”列下的 Azure 专用终结点 DNS 配置。 当策略查找 groupId 并在 privateLinkServiceId 专用终结点中时,它会在专用终结点中部署一个 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"
     }
  }
}

策略分配

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

重要

除了分配策略中定义的 roleDefinition 之外,还记得在订阅和资源组中分配私人 DNS区域参与者角色角色,其中专用 DNS 区域托管在由策略分配创建的DeployIfNotExists托管标识,该角色将负责在专用 DNS 区域中创建和管理专用终结点 DNS 记录。 这是因为专用终结点位于应用程序所有者 Azure 订阅,而专用 DNS 区域位于不同订阅(如中央连接订阅)。

平台团队完成配置后:

  • 应用程序团队的 Azure 订阅已准备就绪,团队可以专门创建具有专用终结点访问权限的 Azure PaaS 服务。
  • 团队必须确保从相应的专用 DNS 区域自动注册专用终结点的 DNS 记录(并在删除专用终结点后删除)。

应用程序所有者体验

在平台团队部署平台基础结构组件(专用 DNS 区域和策略)后,应用程序所有者在尝试将 Azure PaaS 服务部署到 Azure 订阅时具有以下体验。 无论它们是通过 Azure 门户 或其他客户端(例如 PowerShell 或 CLI)执行其活动,都是相同的,因为 Azure 策略控制了其订阅。

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

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

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

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

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

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

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

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

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

  6. 在“配置”部分中,选择 VNet 和子网后,请确保“与专用 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 记录所在的位置的屏幕截图。

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

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

后续步骤

查看 本地和 Azure 资源的 DNS。 查看 虚拟机远程访问计划。

重要

本文概述了使用分配给管理组的 DINE(DeployIfNotExists)策略大规模实现 DNS 和专用链接集成。 这意味着,使用此方法创建专用终结点时,无需在代码中处理 DNS 集成,因为它由策略处理。 应用程序团队也不太可能拥有对集中式私人 DNS区域的 RBAC 访问权限。

下面是使用 Bicep 和 HashiCorp Terraform 创建专用终结点时查看的有用链接。

对于使用基础结构即代码创建专用终结点:

但是,如果按照本文中所述的 DINE 策略方法,仍可以在基础结构即代码中创建专用终结点,并让具有所需 RBAC 的 DINE 策略改为处理私人 DNS区域。