APIM MCP安全——带OBO认证的Azure功能应用
带有两个HTTP端点的Azure功能应用程序,部署在Azure API管理(APIM)后面,配置为具有OAuth 2.0保护资源元数据和On-Behalf-Of(OBO)令牌交换的MCP服务器。
建筑
MCP Client
│ (Bearer token with access_mcp scope)
▼
┌─────────────────────────────────────────────────┐
│ Azure API Management (MCP Server) │
│ │
│ obo-mcp-server API │
│ ├── GET /echo?name=... → pass-through │
│ └── GET /me → OBO exchange → Graph token │
│ │
│ mcp-auth API │
│ └── /.well-known/oauth-protected-resource │
│ (returns PRM JSON) │
└──────────────────────┬──────────────────────────┘
│
▼
┌────────────────┐ ┌──────────────────┐
│ Function App │──────▶│ Microsoft Graph │
│ (.NET 8) │ │ GET /v1.0/me │
└────────────────┘ └──────────────────┘身份验证流(GetMe)
- MCP客户端使用Entra ID进行身份验证→ 获取令牌
access_mcp范围 - 客户端通过以下方式调用APIM
Authorization: Bearer - APIM验证JWT并执行OBO交换(交换
access_mcp令牌用于User.Read图形令牌) - APIM使用Graph令牌将请求转发到Function App
Authorization头球 - 函数应用程序的GetMe端点调用Microsoft Graph
/me并返回用户配置文件
先决条件
- Azure开发者命令行界面(azd)
- .NET 8 SDK
- Azure功能核心工具v4
- Azure订阅
- 2个Entra ID应用程序注册 (请参阅下面的设置步骤)
Entra ID应用程序注册设置
您需要两个应用程序注册:a 客户端应用程序 (由MCP客户端使用)和 后端API应用程序 (定义 access_mcp 范围,执行OBO,持有 User.Read 委托权限)。
应用程序1--客户端应用程序(MCP客户端)
这是MCP客户端工具用于用户登录和请求令牌的公共客户端。
- 在 Azure门户首选 微软Entra ID→ 应用程序注册→ 新注册.
- 命名它(例如。,
mcp-client),暂时将重定向URI留空,然后单击 注册. - 注意 应用程序(客户端)ID --这是您的MCP客户端将使用的。
- 在...之下 认证,启用 允许公共客户端流 (设备代码/交互流所需)。
- 此应用程序不需要客户端密码。
应用程序2-后端API应用程序(海外建筑运营管理局中间层)
此应用程序定义 access_mcp 客户端请求的作用域,它执行OBO交换以代表用户获取Graph令牌。
- 注册新应用程序(例如。,
mcp-backend-api). - 注意 应用程序(客户端)ID → 这变成了
OBO_CLIENT_ID. - 公开API:
- 设置 应用程序ID URI 到 api:// → 这变成了 MCP_CLIENT_AUDIENCE. - 添加一个名为的作用域 access_mcp (例如,显示名称:“访问MCP服务器”),设置为 管理员和用户. - 在...之下 授权客户端应用程序,添加应用程序1的客户端ID并对其进行授权 access_mcp 范围。
- API权限:
- 添加 Microsoft Graph → User.Read (委托)。 - 授予管理员同意。
- 证书和机密: 创建新的客户端密钥→ 这变成了
OBO_CLIENT_SECRET.
快速开始
1.使用Azure进行身份验证
azd auth login2.初始化环境
azd init3.设置所需的环境变量
azd env set ENTRAID_TENANT_ID
azd env set OBO_CLIENT_ID
azd env set OBO_CLIENT_SECRET
azd env set MCP_CLIENT_AUDIENCE api://
azd env set APIM_PUBLISHER_EMAIL
azd env set APIM_PUBLISHER_NAME 4.部署到Azure
azd up这提供了所有基础设施(功能应用程序、APIM、存储)并部署了功能应用程序代码。
本地开发
cd src/FunctionApp
func start功能应用程序在本地运行 http://localhost:7071:
GET http://localhost:7071/api/echo?name=World--回声参数GET http://localhost:7071/api/me-需要有效的Graph API承载令牌
项目结构
├── azure.yaml # azd configuration
├── infra/
│ ├── main.bicep # Main Bicep orchestration
│ ├── main.parameters.json # Parameters
│ ├── abbreviations.json # Resource naming
│ ├── modules/
│ │ ├── function-app.bicep # Function App + Storage + ASP
│ │ ├── apim.bicep # APIM instance + named values
│ │ └── apim-apis.bicep # APIs, operations, policies
│ └── policies/
│ ├── mcp-auth-policy.xml # PRM metadata response
│ └── obo-getme-policy.xml # OBO token exchange
└── src/
└── FunctionApp/
├── Functions/
│ ├── Echo.cs # Echo endpoint
│ └── GetMe.cs # GetMe endpoint (Graph API)
└── openapi.json # OpenAPI spec for APIM importAPIM命名值
| 命名值 | 源环境变量 | 描述 | 机密 |
|---|---|---|---|
entraid-tenant | ENTRAID_TENANT_ID | 输入持有人ID | 否 |
obo-client-id | OBO_CLIENT_ID | 后端应用程序(应用程序2)客户端ID——用作OBO参与者 | 否 |
obo-client-secret | OBO_CLIENT_SECRET | 后端应用程序(应用程序2)客户端机密-用于OBO令牌交换 | 是 |
mcp-client-audience | MCP_CLIENT_AUDIENCE | Audience APIM根据设置验证传入令牌 api:// | 没有 |
安全须知
- Function App本身不验证令牌——APIM充当身份验证网关
- 客户端机密存储为APIM机密命名值(考虑使用密钥库支持的生产命名值)
- OBO交换确保Function App只接收Graph令牌,从不接收原始客户端令牌
- 为了进行深度防御,考虑将功能应用程序访问限制为仅访问APIM(ExpressRoute集成或功能访问密钥)
