此仓库展示了一种使用 Apigee 代理来强制执行外部定义的访问控制决策的方法,从而包装不安全的 MCP 服务器。
许多人认为 MCP 足够独特,需要一个不同的网关,一种完全不同的网络方法。
但实际上它并没有那么不同。
听起来很熟悉吗?如果你有 Apigee,你已经拥有一个可以为此类 API 提供适当治理的平台。
可以在 Apigee 中包含“基本”访问控制,使用 Apigee 配置流语言。所谓“基本”,是指你可以配置一个 API 代理来检查传入请求是否提供了令牌,并且该令牌对于给定的操作是否有效。但这是一种“客户端导向”的授权检查——它不考虑附加用户的标识——并且它是静态的。
但要将更动态的访问控制纳入 Apigee API 代理中,通常你会希望将访问控制决策“外部化”,并允许 Apigee 执行该决策。这种外部化的决策可以依赖于任意数据,包括调用者的身份、环境数据、特定用户最近的历史记录、一天中的时间等等。
此仓库展示了一种实现方法,涉及以下内容:
有一个 屏幕录像,展示了这一切是如何工作的。我鼓励你去看看!
这个示例不是官方的 Google 产品,也不是官方 Google 产品的组成部分。它只是一个示例。
此示例依赖于众多移动部件和系统:
这是一个巨大的努力,比我目前能够承诺的还要大。因此,我无法分享一个包含完全测试过的、可工作的代码和脚本的仓库,让你自己重现这一切。
但我仍然会发布代码和配置,因为我认为阅读和检查这些移动部件会有帮助。
在 Apigee 中使用 Apigee 配置流语言进行“基本”访问控制很简单。例如,配置一个 Apigee API 代理以仅在调用方提供有效的令牌时才允许访问(使用内置的 Apigee 策略 OAuthV2,操作 = VerifyAccessToken)。或者一个有效的未过期的 API 密钥(使用内置的 Apigee 策略 VerifyAPIKey)。
在简单情况下,OAuthV2/VerifyAccessToken 策略看起来像这样:
<OAuthV2 name="OAuthV2-Verify-Access-Token">
<Operation>VerifyAccessToken</Operation>
</OAuthV2>
而 VerifyAPIKey 策略看起来像这样:
<VerifyAPIKey name="APIKeyVerifier">
<APIKey ref="request.queryparam.apikey" />
</VerifyAPIKey>
在前者的情况下,即依赖于 OAuthV2 访问令牌,当然,调用的应用程序必须通过某种授权流程先前获得了访问令牌。这只是标准的 OAuthV2 模型,没有什么新的东西。
但是正如你可以看到的,无论是使用密钥还是令牌,控制都是二进制的。要么调用方具有当前调用有效的有效密钥或令牌,要么没有。如果你想获得更细粒度的控制,特别是对于 MCP 服务器和工具,你需要比这种粗粒度检查提供的更多的控制和灵活性。
为了超越基本检查,Apigee 有 API 产品概念。API 发布者可以配置特定的客户端凭证(客户端 ID 或 API 密钥),使其被授权用于特定的 API 产品。产品实际上只是带有元数据的 API 代理集合。每个传入请求都会呈现一个凭证,这将解析为一个有效的 API 产品。然后,在运行时,Apigee 将验证所呈现的应用程序客户端凭证是否被授权用于包含当前 API 请求使用的特定动词 + 路径对的 API 产品。
有关 API 产品概念和隐含的动词+路径授权检查的 15 分钟屏幕录像,请参见 这里。但基本要点是:
在配置时:
在运行时:
除此之外,你还可以配置 Apigee 来检查访问令牌的作用域。
有一个方便的 工作示例,实际在 Apigee 中演示了这一点。看看吧!
这里缺少的是“基于角色的访问控制”,简称 RBAC,它允许根据操作应用程序的人的身份来做出访问控制决策。还缺少的是 ABAC,即 OWASP 称之为“基于属性的访问控制”,它不仅基于调用者的角色或身份,还基于额外的数据进行控制,如:职位角色、一天中的时间、项目名称、来源 IP 地址、记录创建日期、之前的活动模式等。Apigee 自身没有一个好的机制来进行用户级别的 RBAC 或更通用的 ABAC。
为了实现基于用户的 RBAC 或更通用的 ABAC,典型的做法是将访问控制决策“外部化”,并使用 Apigee 来执行该决策。你会将此作为补充基本授权检查的手段,这些检查可以通过 API 产品在 Apigee 中完成。
处理传入调用(无论是 MCP 还是其他变体)的方式如下:
Apigee 运行时收集或确定所有需要的信息以告知访问控制决策。这可能包括关于请求用户的某些信息、账单账户状态、最近的活动模式等。通常用户信息是从类似由独立身份提供者签名的 ID 令牌中获得的。
Apigee 向外部访问控制系统发送访问控制请求。此请求必须包含外部系统做出决策所需的所有元数据。调用者的身份、请求的资源、请求的具体动作、源 IP 地址等。无论需要什么。
外部系统做出决定(允许或拒绝),并将结果返回给 Apigee。
然后,Apigee API 代理执行该决定。
此仓库中的示例展示了如何使用自定义 Cloud Run 服务来对外部化 MCP 服务器的访问控制决策。
这里的示例展示了基本思路。 以下是其工作原理。
客户端应用(例如代理)向 Apigee API 代理发送 MCP 调用请求。此调用必须在 Authorization 标头中包含访问令牌。
Apigee API 代理验证访问令牌,检查其是否对该代理有效。
如果通过验证,Apigee API 代理调用 外部访问控制服务,传递 {JWT 负载,MCP 方法,MCP 工具}。此服务恰好是用 C# 实现的,但这只是一个细节。
访问控制服务使用 Google Sheets REST API 从 Google 表格中检索访问控制规则。这些数据被缓存在访问控制服务中。
访问控制服务将访问规则应用于传入数据。它使用访问令牌上的 "az_groups" 声明以及 MCP 动词和工具来查找匹配的规则。如果有 ALLOW 条目,则允许请求。否则,不允许。
服务向代理返回 "ALLOW" 或 "DENY"。
代理执行该决定,并在允许的情况下代理到上游 MCP 服务器,否则发出 403 状态。
规则看起来像这样:

以及评估请求是否应被授权的逻辑,
一些实现注意事项:
在步骤 1 中,代理发送的访问令牌是通过 OAuthV2 授权码授予类型从注册给特定 MCP 服务器的 OpenID Connect 服务器获得的。你需要提供自己的 OIDC 服务器。
你可以使用 Auth0.com;具体设置请参见 Auth0 设置。
不管你使用哪个 OIDC 服务器,它都必须发出一个带有 "az_groups" 声明的访问令牌,该声明应该是一个字符串列表。访问控制服务器检查该声明以确定是否允许请求。
API 代理假设 JWKS 端点位于 ${OIDC_SERVER}/jwks,并且令牌发行者与 ${OIDC_SERVER} URL 相同。
访问控制服务是一个 GRPC 服务。这意味着从你的 Apigee API 代理调用它相对快速且高效,应该可以接受为每次 API 请求承担该检查。如果相对低延迟仍然不可接受,你可以将规则评估逻辑移至 Apigee 代理本身。这里没有显示。
好问题!Open Policy Agent 是存储、管理和评估任意系统或资源访问规则的好解决方案。它是开源的,维护良好,并且可以作为可部署的容器镜像提供。你可以将 容器镜像 直接部署到类似 Cloud Run 的地方;无需构建代码。
听起来不错,对吧?我看到的唯一缺点是 OPA 依赖于 REGO 来表达策略。这是一种领域特定语言;我没有见过它在 OPA 之外的任何地方使用。而且它有些新颖。这可能会成为某些团队的障碍。
对于这个特定示例,我决定使用 Google 表格来存储访问规则,原因如下:
所有这些,你都可以免费获得 Google 表格。
检索和应用规则的 C# 逻辑也很容易理解。所有这些因素的组合意味着使用 Sheets 和 C# 的解决方案比基于 OPA 和 REGO 的解决方案更具普遍的“可访问性”。
但是,使用 OPA 的解决方案架构模型与我这里使用自定义 C# 服务和 Google 表格的模型完全相同。
要遵循说明在您自己的环境中部署此示例,您需要以下先决条件:
您可以在 Google Cloud Shell 中获得所有这些工具。
这些步骤需要您的一些定制。这尚未经过充分测试和验证。
修改 env.sh 文件以适应您的环境。然后通过 source 命令设置这些变量以供后续命令使用:
source ./env.sh
启用所需的各项服务:
./1-enable-services.sh
使用 gcloud 登录以允许脚本创建电子表格:
./2-auth-login.sh
部署“产品”MCP 服务器到 Cloud Run
3-deploy-products-mcp-to-cloud-run.sh
创建包含规则 + 角色的电子表格。
./4-create-sheet.sh
当脚本完成后,定义电子表格 ID 的 shell 变量。从“创建电子表格”步骤的输出中找到该值。
export SHEET_ID=VALUE-FROM-PRIOR-STEP
创建访问控制服务的服务帐户。
./5-create-service-account-for-access-control-service.sh
手动将之前创建的电子表格与 SA 邮件地址共享。
部署将读取并应用电子表格中规则的 Cloud Run 服务。
./6-deploy-access-control-service-to-cloud-run.sh
这需要几分钟时间。它将源代码上传到 Cloud Build,构建服务,然后从镜像部署。
创建 Apigee 目标服务器。
这是指向访问控制服务器的服务器实体。
./7-create-apigee-target-server-for-authz.sh
安装 apigeecli
./8-install-apigeecli.sh
导入并部署 Apigee API 代理
有一个用于处理 MCP “已知端点”(基础路径 /.well-known/),另一个用于处理其他 MCP 事务。
./9-import-and-deploy-apigee-proxies.sh
在您选择的聊天机器人或代理(如 Gemini CLI)中配置 MCP 服务器,如下所示:
"mcpServers": {
"products": {
"httpUrl": "https://your-apigee-endpoint/mcp-access-control/mcp",
"oauth": {
"enabled": true,
"clientId": "ab4aded9d20f44RHgmrNCq",
"clientSecret": "26a86ab545704312b748e331f854"
}
}
}
clientId 和 clientSecret 需要被您的 OIDC 服务器知道。 或者,如果您的服务器支持动态客户端注册(DCR),您可以省略它们。
删除 Apigee 资产。
这包括目标服务器和 API 代理。
./99a-clean-apigee-entities.sh
删除 Cloud Run 资产。
这包括服务帐户。
./99b-clean-cloud-run-authorization-service.sh
手动删除 Google 表格。
此调用和示例代理是开源软件,不是 Apigee 的受支持部分。如果您对此有疑问或需要帮助,可以尝试在 专门针对 Apigee 的 Google Cloud 社区论坛上询问。对于发布到该站点的问题,没有服务级别保证。
此材料 版权所有 © 2025 Google LLC,并根据 Apache 2.0 许可证许可。这包括 Java 代码以及 API 代理配置。
Cloud Run 服务部署为允许“未经身份验证的访问”。如果您在真实系统中使用类似的东西,您将希望部署 Cloud Run 服务以允许 run.invoke 来自您的访问控制服务运行的服务帐户。
API 代理不会对访问令牌内的客户端 ID 执行“VerifyAPIKey”。这是一个简单的扩展。它需要同步 Apigee 中的应用程序与 OIDC 服务器中的客户端 ID。
访问控制服务不会检查格式错误的规则。