此实例方案使用 Azure 专用链接和 Azure 专用终结点帮助保护与 Microsoft Teams 频道机器人的 Web 应用的连接。 同时,它启用 Teams 客户端中的通道,可以通过 Azure 防火墙实例公开的 IP 与机器人通信。
体系结构
下载此体系结构的 Visio 文件。
数据流
Azure 虚拟网络使 Azure 资源可以相互通信。 此示例中的虚拟网络使用地址空间 10.0.0.0/16,并包含三个子网供方案所需的组件使用:
Azure 防火墙子网 (10.0.1.0/26)。
虚拟网络集成子网 (10.0.2.0/24),用于将流量从机器人的专用终结点路由到防火墙。
专用终结点子网 (10.0.3.0/24),用于将流量从防火墙路由到机器人的专用终结点。
Azure 防火墙公开客户端可用于与基础机器人服务通信的单个公共 IP 地址。 通常,防火墙位于其自己的虚拟网络中,这是中心和分支体系结构的常见模式,但这是一个简化的示例,将所有服务和资源部署到单个虚拟网络中。 Azure 防火墙位于其自己的子网中。
路由表定义流量在虚拟网络中所采用的路由。 它可确保传入和传出机器人的流量通过防火墙。
地址前缀为 0.0.0.0/0 的默认路由指示 Azure 将不在任何其他路由的地址前缀范围内的流量路由到部署了 Azure 防火墙实例的子网。 在此示例中,它是唯一的路由。
虚拟网络集成子网和专用终结点子网与路由表相关联,从而确保通过这两个子网的任何流量都通过防火墙进行路由。
机器人服务由机器人应用程序服务计划、应用程序服务和机器人频道注册组成。
- 应用程序服务有一个已注册的自定义域,该域指向防火墙的 IP 地址。 这样,只能通过防火墙访问应用程序服务。
Azure 专用链接服务,用于通过 Azure 专用终结点对机器人应用程序服务进行入站访问。
虚拟网络集成将应用程序服务连接到虚拟网络,从而确保来自机器人应用程序服务的出站流量通过防火墙。
组件
备选方法
- 应用程序服务环境可提供一个完全隔离且专用的环境,从而安全地大规模运行应用程序服务。 此示例不使用应用程序服务环境来降低成本,但可以通过修改示例体系结构来支持它。
方案详细信息
机器人使 Teams 用户能够通过文本、交互式卡和任务模块与 Web 服务交互。 Microsoft Bot Framework 和 Azure 机器人服务提供了一组易于使用的工具,用于创建和管理这些机器人。
可以使用各种语言(例如 C#、JavaScript 和 Python)来开发机器人。 开发后,可以将它们部署到 Azure。 机器人的关键组件是 Web 应用,其中包含用户与之通信的核心逻辑和接口。 要使机器人正常工作,其中一个关键要求是必须公开可公开访问的 HTTPS 终结点。
InfoSec 策略通常要求发送到 Web 应用的所有传入流量都通过企业防火墙。 这意味着,与任何其他 Web 应用一样,发送到机器人的所有流量以及来自机器人的响应都必须通过企业防火墙进行路由。
可能的用例
组织可以将机器人用于移动端和桌面端用户。 示例包括:
- 简单查询。 机器人可以将完全匹配传递到一个查询或一组相关匹配项,以帮助消除歧义。
- 多回合交互。 机器人可帮助预测可能的后续步骤,使用户更轻松地完成任务流。
- 向用户发送消息。 当文档中的某些内容发生更改或工作项关闭时,机器人会发送消息。
注意事项
监视
尽管此示例方案中未实现监视功能,但机器人的应用程序服务可以利用 Azure Monitor 服务来监视其可用性和性能。
可伸缩性
此方案中使用的机器人托管在 Azure 应用程序服务上。 因此,可以使用标准应用程序服务自动缩放功能来自动缩放运行机器人的实例数,从而使机器人能够跟上需求。 有关自动缩放的详细信息,请参阅自动缩放最佳做法。
有关其他可伸缩性主题,请参阅 Azure 体系结构中心的性能效率清单。
DevOps
常见做法是使用持续部署管道将 Web 应用、API 应用和移动应用部署到 Azure 应用程序服务计划。 由于受保护的机器人的应用程序服务使用专用终结点进行保护,因此外部托管的生成代理没有部署更新所需的访问权限。 要解决这个问题,可能需要使用 Azure Pipelines 自承载 DevOps 代理等解决方案。
安全性
Azure DDoS 防护与应用程序设计最佳做法相结合,提供增强的 DDoS 缓解功能来更全面地防御 DDoS 攻击。 应在任何外围虚拟网络上启用 Azure DDOS 防护。
部署此方案
先决条件
必须已经有 Azure 帐户。 如果没有 Azure 订阅,请在开始之前创建一个免费帐户。
演练
在 Azure Cloud Shell 或你首选的部署 shell 中运行以下 Azure CLI 命令。
这组命令将创建本演练所需的资源组、虚拟网络和子网。 Teams 使用的 IP 范围为 52.112.0.0/14,52.122.0.0/15。
# Declare variables (bash syntax) export PREFIX='SecureBot' export RG_NAME='rg-'${PREFIX} export VNET_NAME='vnet-'${PREFIX} export SUBNET_INT_NAME='VnetIntegrationSubnet' export SUBNET_PVT_NAME='PrivateEndpointSubnet' export LOCATION='eastus' export TEAMS_IP_RANGE='52.112.0.0/14 52.122.0.0/15' export FIREWALL_NAME='afw-'${LOCATION}'-'${PREFIX} # Create a resource group az group create --name ${RG_NAME} --location ${LOCATION} # Create a virtual network with a subnet for the firewall az network vnet create \ --name ${VNET_NAME} \ --resource-group ${RG_NAME} \ --location ${LOCATION} \ --address-prefix 10.0.0.0/16 \ --subnet-name AzureFirewallSubnet \ --subnet-prefix 10.0.1.0/26 # Add a subnet for the Virtual network integration az network vnet subnet create \ --name ${SUBNET_INT_NAME} \ --resource-group ${RG_NAME} \ --vnet-name ${VNET_NAME} \ --address-prefix 10.0.2.0/24 # Add a subnet where the private endpoint will be deployed for the app service az network vnet subnet create \ --name ${SUBNET_PVT_NAME} \ --resource-group ${RG_NAME} \ --vnet-name ${VNET_NAME} \ --address-prefix 10.0.3.0/24
创建专用终结点子网时,默认情况下禁用专用终结点策略。
完成部署后,应在虚拟网络中看到以下子网:
运行以下 CLI 命令,将 Azure 防火墙实例部署到在步骤 1 中创建的防火墙子网:
# Create a firewall az network firewall create \ --name ${FIREWALL_NAME} \ --resource-group ${RG_NAME} \ --location ${LOCATION} # Create a public IP for the firewall az network public-ip create \ --name ${FIREWALL_NAME}-pip \ --resource-group ${RG_NAME} \ --location ${LOCATION} \ --allocation-method static \ --sku standard # Associate the IP with the firewall az network firewall ip-config create \ --firewall-name ${FIREWALL_NAME} \ --name ${FIREWALL_NAME}-Config \ --public-ip-address ${FIREWALL_NAME}-pip \ --resource-group ${RG_NAME} \ --vnet-name ${VNET_NAME} # Update the firewall az network firewall update \ --name ${FIREWALL_NAME} \ --resource-group ${RG_NAME} # Get the public IP address for the firewall and take note of it for later use az network public-ip show \ --name ${FIREWALL_NAME}-pip \ --resource-group ${RG_NAME}
防火墙配置应如下所示:
将基本机器人部署到步骤 1 中创建的资源组。
在此过程中,你将创建一个应用注册,需要该应用注册才能通过频道与机器人交互。 在此过程中,你还将部署必要的应用程序服务计划、应用程序服务和 Web 应用机器人。
注意
选择支持 Azure 专用链接的应用程序服务计划。
将自定义域映射到在步骤 3 中部署到资源组的应用程序服务。
此步骤需要访问域注册机构,并且要求向自定义域添加一条指向在步骤 2 中创建的防火墙的公共 IP 的 A 记录。
通过上传域的现有证书,或在 Azure 中购买并导入应用程序服务证书,来保护映射的自定义域。 可以按照在 Azure 应用程序服务中使用 TLS/SSL 绑定保护自定义 DNS 名称中的步骤执行此操作。
现在,你应该有一个完全正常运行的机器人,可以将其添加到 Teams 中的频道,或者根据 Bot Framework SDK 文档中的说明通过 Web 聊天对其进行测试。
注意
此时仍可通过
azurewebsites.net
URL 和配置的自定义 URL 公开访问机器人的应用程序服务。 在后续步骤中,你将使用专用终结点来禁用公共访问。 另外还需要将防火墙配置为仅允许机器人服务与 Teams 客户端通信。运行以下 Azure CLI 脚本来部署并配置专用终结点。 此步骤还为机器人的应用程序服务实现虚拟网络集成,从而将其连接到虚拟网络的集成子网。
# Disable private endpoint network policies (this step is not required if you're using the Azure portal) az network vnet subnet update \ --name ${SUBNET_PVT_NAME} \ --resource-group ${RG_NAME} \ --vnet-name ${VNET_NAME} \ --disable-private-endpoint-network-policies true # Create the private endpoint, being sure to copy the correct resource ID from your deployment of the bot app service # The ID can be viewed by using the following CLI command: # az resource show --name wapp-securebot --resource-group rg-securebot --resource-type Microsoft.web/sites --query "id" az network private-endpoint create \ --name pvt-${PREFIX}Endpoint \ --resource-group ${RG_NAME} \ --location ${LOCATION} \ --vnet-name ${VNET_NAME} \ --subnet ${SUBNET_PVT_NAME} \ --connection-name conn-${PREFIX} \ --private-connection-resource-id /subscriptions/cad87d9e-c941-4519-a638-c9804a0577b9/resourceGroups/rg-securebot/providers/Microsoft.Web/sites/wapp-securebot \ --group-id sites # Create a private DNS zone to resolve the name of the app service az network private-dns zone create \ --name ${PREFIX}privatelink.azurewebsites.net \ --resource-group ${RG_NAME} az network private-dns link vnet create \ --name ${PREFIX}-DNSLink \ --resource-group ${RG_NAME} \ --registration-enabled false \ --virtual-network ${VNET_NAME} \ --zone-name ${PREFIX}privatelink.azurewebsites.net az network private-endpoint dns-zone-group create \ --name chatBotZoneGroup \ --resource-group ${RG_NAME} \ --endpoint-name pvt-${PREFIX}Endpoint \ --private-dns-zone ${PREFIX}privatelink.azurewebsites.net \ --zone-name ${PREFIX}privatelink.azurewebsites.net # Establish virtual network integration for outbound traffic az webapp vnet-integration add \ -g ${RG_NAME} \ -n wapp-${PREFIX} \ --vnet ${VNET_NAME} \ --subnet ${SUBNET_INT_NAME}
运行这些命令后,应在资源组中看到以下资源:
应用程序服务的“网络”部分下的“VNet 集成”选项应如下所示:
接下来,创建一个路由表,以确保每个子网的传入和传出流量都通过防火墙。 需要上一步中创建的防火墙的专用 IP 地址。
# Create a route table az network route-table create \ -g ${RG_NAME} \ -n rt-${PREFIX}RouteTable # Create a default route with 0.0.0.0/0 prefix and the next hop as the Azure firewall virtual appliance to inspect all traffic. Make sure you use your firewall's internal IP address instead of 10.0.1.4 az network route-table route create -g ${RG_NAME} \ --route-table-name rt-${PREFIX}RouteTable -n default \ --next-hop-type VirtualAppliance \ --address-prefix 0.0.0.0/0 \ --next-hop-ip-address 10.0.1.4 # Associate the two subnets with the route table az network vnet subnet update -g ${RG_NAME} \ -n ${SUBNET_INT_NAME} --vnet-name ${VNET_NAME} \ --route-table rt-${PREFIX}RouteTable az network vnet subnet update -g ${RG_NAME} \ -n ${SUBNET_PVT_NAME} \ --vnet-name ${VNET_NAME} \ --route-table rt-${PREFIX}RouteTable
运行命令后,路由表资源应如下所示:
创建路由表后,向防火墙添加规则,以将来自公共 IP 的流量传送给机器人应用程序服务,并限制来自除 Microsoft Teams 外的任何终结点的流量。 此外,还需要使用服务标记来允许虚拟网络与 Azure 机器人服务或 Microsoft Entra ID 之间的流量。
运行以下命令:
# Create a NAT rule collection and a single rule. The source address is the public IP range of Microsoft Teams # Destination address is that of the firewall. # The translated address is that of the app service's private link. az network firewall nat-rule create \ --resource-group ${RG_NAME} \ --collection-name coll-${PREFIX}-nat-rules \ --priority 200 \ --action DNAT \ --source-addresses ${TEAMS_IP_RANGE} \ --dest-addr 23.100.26.84 \ --destination-ports 443 \ --firewall-name ${FIREWALL_NAME} \ --name rl-ip2appservice \ --protocols TCP \ --translated-address 10.0.3.4 \ --translated-port 443 # Create a network rule collection and add three rules to it. # The first one is an outbound network rule to only allow traffic to the Teams IP range. # The source address is that of the virtual network address space, destination is the Teams IP range. az network firewall network-rule create \ --resource-group ${RG_NAME} \ --collection-name coll-${PREFIX}-network-rules \ --priority 200 \ --action Allow \ --source-addresses 10.0.0.0/16 \ --dest-addr ${TEAMS_IP_RANGE} \ --destination-ports 443 \ --firewall-name ${FIREWALL_NAME} \ --name rl-OutboundTeamsTraffic \ --protocols TCP # This rule will enable traffic to all IP addresses associated with Azure AD service tag az network firewall network-rule create \ --resource-group ${RG_NAME} \ --collection-name coll-${PREFIX}-network-rules \ --source-addresses 10.0.0.0/16 \ --dest-addr AzureActiveDirectory \ --destination-ports '*' \ --firewall-name ${FIREWALL_NAME} \ --name rl-AzureAD \ --protocols TCP # This rule will enable traffic to all IP addresses associated with Azure Bot Services service tag az network firewall network-rule create \ --resource-group ${RG_NAME} \ --collection-name coll-${PREFIX}-network-rules \ --source-addresses 10.0.0.0/16 \ --dest-addr AzureBotService \ --destination-ports '*' \ --firewall-name ${FIREWALL_NAME} \ --name rl-AzureBotService \ --protocols TCP
运行命令后,防火墙规则将如下所示:
确认只能从 Teams 中的频道访问机器人,并且机器人应用程序服务的所有传入和传出流量都通过防火墙。
作者
本文由 Microsoft 维护, 它最初是由以下贡献者撰写的。
首席作者:
- Ali Jafry | 云解决方案架构师
后续步骤
查看 Bot Framework SDK 文档,开始构建机器人。