通过


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

保护 Azure 容器应用中的 MCP 服务器

本文介绍如何对 Azure 容器应用上运行的 MCP 服务器进行身份验证和保护。 方法因是托管 独立容器应用 还是在动态会话中使用 平台管理的 MCP 服务器 而异。

先决条件

身份验证模型概述

Azure 容器应用支持 MCP 服务器的两种身份验证模型。 下表汇总了主要差异。

方面 独立容器应用 动态会话 MCP
身份验证机制 使用 Microsoft Entra ID 的容器应用内置身份验证 x-ms-apikey 标头中的 API 密钥
令牌类型 OAuth 2.0 持有者令牌 不透明 API 密钥字符串
身份认证服务提供商 Microsoft Entra ID Azure Resource Manager
密钥/令牌轮换 由 Microsoft Entra ID 管理 通过 Azure 资源管理器 API 重新生成
授权范围 每个应用程序均可配置 会话池级别
传输加密 TLS (容器应用入口) TLS (容器应用会话终结点)

具有 Microsoft Entra ID 身份验证的独立容器应用

将自己的 MCP 服务器部署为容器应用时,你拥有身份验证层。 使用Microsoft Entra ID 支持的容器应用 内置身份验证 功能。

配置内置身份验证

以下步骤注册Microsoft Entra ID 应用程序并在容器应用中启用内置身份验证。

  1. 在 Microsoft Entra ID 中注册应用程序:

    APP_ID=$(az ad app create \
        --display-name "mcp-server-auth" \
        --sign-in-audience AzureADMyOrg \
        --query appId -o tsv)
    
  2. 创建服务主体:

    az ad sp create --id $APP_ID
    
  3. 添加客户端密码:

    CLIENT_SECRET=$(az ad app credential reset --id $APP_ID --query password -o tsv)
    TENANT_ID=$(az account show --query tenantId -o tsv)
    
  4. 在容器应用上启用内置身份验证:

    az containerapp auth microsoft update \
        --name <CONTAINER_APP_NAME> \
        --resource-group <RESOURCE_GROUP> \
        --client-id $APP_ID \
        --client-secret $CLIENT_SECRET \
        --tenant-id $TENANT_ID \
        --issuer "https://login.microsoftonline.com/$TENANT_ID/v2.0" \
        --yes
    
  5. 将未经身份验证的动作设置为需要登录:

    az containerapp auth update \
        --name <CONTAINER_APP_NAME> \
        --resource-group <RESOURCE_GROUP> \
        --unauthenticated-client-action Return401
    

使用持有者令牌从 MCP 客户端进行连接

当 MCP 服务器需要持有者令牌时,请在 MCP 客户端中配置令牌检索。 以下是 GitHub Copilot 的 .vscode/mcp.json 配置示例:

{
    "servers": {
        "my-mcp-server": {
            "type": "http",
            "url": "https://<CONTAINER_APP_NAME>.<REGION>.azurecontainerapps.io/mcp",
            "headers": {
                "Authorization": "Bearer ${input:mcpBearerToken}"
            }
        }
    },
    "inputs": [
        {
            "id": "mcpBearerToken",
            "type": "promptString",
            "description": "Enter your bearer token for the MCP server",
            "password": true
        }
    ]
}

小窍门

在开发环境中,使用 az account get-access-token --resource $APP_ID --query accessToken -o tsv 获取令牌,并在提示时粘贴该令牌。 对于自动化工作流,请与组织的令牌管理系统集成。

配置 CORS

从基于 Web 的环境连接的 MCP 客户端需要 CORS 标头。 使用以下命令在容器应用中配置 CORS:

az containerapp ingress cors update \
    --name <CONTAINER_APP_NAME> \
    --resource-group <RESOURCE_GROUP> \
    --allowed-origins "https://vscode.dev" "https://github.dev" \
    --allowed-methods "GET" "POST" "OPTIONS" \
    --allowed-headers "Content-Type" "Authorization" "Mcp-Session-Id" \
    --max-age 3600

以下标头对于允许是关键的:

  • Content-Type:JSON-RPC 请求所必需的
  • Authorization:持有者令牌身份验证所必需的
  • Mcp-Session-Id:MCP 客户端用于有状态会话

注释

GitHub Copilot 通过 VS Code 桌面应用进行连接,而不是通过浏览器连接至远程 MCP 服务器。 仅当你打算支持基于浏览器的 MCP 客户端或 Web 的 VS Code 时,才需要 CORS。 独立教程为简化起见使用通配符 CORS 源;在生产环境中,请按此处所示限制为特定的受信任源。

独立 MCP 服务器的安全建议

应用以下最佳做法来强化独立的 MCP 服务器。

  • 网络限制:使用 IP 限制虚拟网络集成 来限制对已知客户端 IP 的访问。
  • 速率限制:在应用程序代码中实施速率限制,或使用 Azure API 管理在应用前面实现速率限制。
  • 输入验证:验证 MCP 服务器代码中的所有工具参数。 MCP 工具输入是任意 JSON。 将它们视为不受信任。
  • 无状态设计:首选无状态 MCP 服务器以避免会话劫持风险。 在大多数 MCP SDK 中,这意味着禁用服务器端会话 ID 生成(例如, sessionIdGenerator: undefined 在 TypeScript 或 stateless_http=True Python 中)。
  • 运行状况探测:在单独的终结点(例如 /healthz),而不是 MCP 终结点上配置运行状况探测。 MCP 终结点需要 JSON-RPC POST 请求,对于普通的 GET 探测会返回错误。

使用 API 密钥身份验证的动态会话

重要

动态会话的平台托管 MCP 服务器处于 预览状态。 API 版本 2025-02-02-previewmcpServerSettings 属性可能会更改。

动态会话中的平台管理的 MCP 服务器使用 API 密钥身份验证。 密钥的范围限定为会话池,并授予对池中的所有工具和会话的访问权限。

API 密钥身份验证流

以下步骤介绍了 API 密钥身份验证如何适用于动态会话。

  1. 客户端发送具有 x-ms-apikey 标头的 JSON-RPC 请求。
  2. 会话池代理根据 Azure 控制平面验证密钥。
  3. 如果密钥有效,则请求将转发到会话。 否则,将返回身份验证错误。

检索 API 密钥

使用以下命令提取会话池的 API 密钥。

API_KEY=$(az rest --method POST \
    --uri "https://management.azure.com/subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RESOURCE_GROUP>/providers/Microsoft.App/sessionPools/<SESSION_POOL_NAME>/fetchMCPServerCredentials" \
    --uri-parameters api-version=2025-02-02-preview \
    --query "apiKey" -o tsv)

轮换和缓存 API 密钥

可以随时重新生成 API 密钥。 平台缓存验证结果最多 5 分钟,因此在重新生成后,以前有效的密钥可能会继续工作,直到缓存过期。

若要轮换 API 密钥,请调用会话池中的 regenerateCredentials 操作。

az rest --method POST \
    --uri "https://management.azure.com/subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RESOURCE_GROUP>/providers/Microsoft.App/sessionPools/<SESSION_POOL_NAME>/regenerateCredentials" \
    --uri-parameters api-version=2025-02-02-preview

重新生成后,使用 fetchMCPServerCredentials 如前所示检索新密钥。

动态会话的安全建议

应用以下最佳做法来保护动态会话 MCP 部署。

  • API 密钥范围:API 密钥授予对整个会话池的访问权限。 具有密钥的任何客户端都可以创建环境和执行代码。 不要与不受信任的参与方共享密钥。
  • 环境隔离:每个会话在 Hyper-V 隔离的容器中运行。 一个会话中的代码执行无法访问另一个会话的数据。
  • 网络出口:使用 sessionNetworkConfiguration.status 控制会话是否可以访问 Internet。 如果会话不需要外部网络访问,则设置为 EgressDisabled
  • 会话生存期:配置为 coolDownPeriodInSeconds 自动销毁空闲会话。 如果会话遭到入侵,此设置将限制公开窗口。
  • 机密存储:将 API 密钥存储在 Azure Key Vault容器应用机密 中,而不是存储在代码或配置文件中。

常见的身份验证不匹配

常见的错误是将 API 密钥标头(x-ms-apikey)与独立容器应用一起使用,或使用具有会话 MCP 终结点的持有者令牌。 下表显示了混合它们时会发生什么情况。

Mismatch 结果
x-ms-apikey 发送到独立应用的 标头 忽略标头;请求触发内置身份验证,并在启用身份验证时返回401
Authorization: Bearer 发送到会话 MCP 密钥验证失败并返回 401

确保 MCP 客户端配置与部署的托管模型匹配。