使用Pomerium和Google OAuth 2.0保护Kubernetes MCP服务器
在不到一年的时间里,MCP(可能指某种技术或平台,具体需根据上下文确定,此处保留原英文缩写)迅速改变了人工智能领域的格局。它不仅为大型语言模型(LLMs)的工具访问提供了标准化,同时也带来了安全挑战。在这篇文章中,我们将探讨如何在其中添加身份验证和授权机制 Kubernetes MCP 服务器,这暴露了诸如……之类的工具 helm_list, pods_list, pods_log,和 pods_get。
我们将使用 “Pomerium”在中文中可以翻译为“罗马城墙界限”或“罗马城界”。这个术语源自古罗马时期,指的是围绕罗马城的一道城墙或界限,具有重要的政治和军事意义。在现代用语中,它可能用来比喻某个特定区域或界限,具有象征性的含义。,一个最近新增了功能的开源身份感知代理 MCP支持 为Model Context Protocol(MCP)服务器提供安全访问。演示将展示用户通过Google OAuth身份验证登录Pomerium,并且仅根据Pomerium的配置被授权运行允许列表中的命令。
演示概述
- 用户通过(某种方式)访问MCP服务器 MCP 检测器(或 MCP 检查器) (基于图形用户界面)或 MCP-CLI 可以翻译为“MCP 命令行界面”或“MCP 命令行工具”,具体取决于上下文和该工具的具体功能。在这里,“MCP”可能代表某个特定的系统、软件或服务的名称,而“CLI”则代表“Command Line Interface”(命令行界面) (基于命令行界面)的测试工具
- 请求通过……进行路由
Pomerium,负责处理Google OAuth 2.0认证 - 一旦验证通过,
Pomerium仅允许访问特定的允许列表 Kubernetes MCP 服务器 工具(见下文配置)。示例:基于策略中的pomerium.yaml,helm_list将会起作用,而events_list不会
policy:
allow:
and:
- email:
in: [youremail@gmail.com]
- mcp_tool:
in: [helm_list, pods_list, events_list] ## allowed list of tools to be allowedMCP Inspector Google OAuth via Pomerium
💡 Note
Pomerium offers three ways to protect MCP servers, but we will demonstrate only one of them in this blog post.
配置与设置
1. 配置Google OAuth客户端
在(某处)创建OAuth 2.0凭据 Google 云端控制台 带有重定向URI,例如 https://www.ukaul.net:8443/oauth2/callback 并记下客户端ID和密钥。
2. 启动Pomerium和Kubernetes MCP服务器
- 确保您能够访问一个运行正常的Kubernetes集群
- 根据以下示例配置,配置 Pomerium。
📄 View Pomerium Configuration (pomerium.yaml)
shared_secret: ozGghKH6NPBjjih/fqRhPTIgSNX4R2D5zXfQH+ZUKzc= # you can generate this using command : head -c32 /dev/urandom | base64
cookie_secret: K6eNnqNk6i0TQqihJoprwdeIBrPtvjBZgqYx2tT3SU0= # you can generate this using command : head -c32 /dev/urandom | base64
idp_client_id: "your-google-client-id-here" # your google oauth2 client id goes here
idp_client_secret: "your-google-client-secret-here" # your google oauth2 client secret goes here
authenticate_service_url: https://www.ukaul.net:8443 # your public URL
authorize_service_url: https://www.ukaul.net:8443
forward_auth_url: https://www.ukaul.net:8443
idp_provider: google
idp_scopes: "openid email profile"
certificate_file: "/root/certs"
certificate_key_file: "/root/key"
log_level: info # options: debug, info, warn, error
runtime_flags:
mcp: true
routes:
- from: https://www.ukaul.net:8443
path: /mcp
to: http://192.168.15.5:8080/mcp # this is ip address where your kubernetes-mcp-server listens
pass_identity_headers: false
set_request_headers:
authorization: ""
mcp:
server:
enabled: true
policy:
allow:
and:
- email:
in: [youremail@gmail.com] # change this
- mcp_tool:
in: [helm_list, pods_list, events_list] # list of commands allowed- 在下面的Docker Compose文件中指定配置文件。根据您的设置自定义文件路径
🐳 View Docker Compose Configuration (docker-compose.yaml)
version: '3.9'
services:
pomerium:
image: pomerium/pomerium:latest
container_name: pomerium
network_mode: "host"
volumes:
- /tmp/pomerium:/root/
command: --config=/root/pomerium.yaml
depends_on:
- kubernetes-mcp-server
kubernetes-mcp-server:
image: quay.io/manusa/kubernetes_mcp_server:latest-linux-amd64
container_name: kubernetes-mcp-server
network_mode: "host"
environment:
KUBECONFIG: "/root/kubeconfig.yaml"
volumes:
- /tmp/pomerium:/root/
command: ["--port", "8080", "--log-level", "7"]
3a. 使用 MCP 检测器 进行测试
- 关注 这些 下载并安装mcp-inspector的说明。
📟 Launch mcp-inspector (see my example below)
~ % mcp-inspector
Starting MCP inspector...
⚙️ Proxy server listening on localhost:6277
🔑 Session token: 9e595de6f9033a71e4db82dbfa6222d596b99698cd0138c44407b8d51a0c28ae
Use this token to authenticate requests or set DANGEROUSLY_OMIT_AUTH=true to disable auth
🚀 MCP Inspector is up and running at:
http://localhost:6274/?MCP_PROXY_AUTH_TOKEN=9e595de6f9033a71e4db82dbfa6222d596b99698cd0138c44407b8d51a0c28ae
🌐 Opening browser...
New StreamableHttp connection request
Query parameters: {"url":"https://www.ukaul.net:8443/mcp","transportType":"streamable-http"}
Created StreamableHttp server transport
Created StreamableHttp client transport
Client Proxy sessionId: f4fe9bb0-b954-4a81-9e93-8344ab1cc81d
Error from MCP server: Error: Error POSTing to endpoint (HTTP 401): {"error":"Unauthenticated","request_id":"083d7427-9176-4d72-81ed-b8b45d2c8b50"}
at StreamableHTTPClientTransport.send (file:///Users/umeshkaul/Projects/inspector/node_modules/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js:284:23)
at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
New StreamableHttp connection request
Query parameters: {"url":"https://www.ukaul.net:8443/mcp","transportType":"streamable-http"}
Created StreamableHttp server transport
Created StreamableHttp client transport
Client Proxy sessionId: be9eb6e4-646a-43c1-8218-7b16f92d4f6e
Received POST message for sessionId be9eb6e4-646a-43c1-8218-7b16f92d4f6e
Received GET message for sessionId be9eb6e4-646a-43c1-8218-7b16f92d4f6e
Received POST message for sessionId be9eb6e4-646a-43c1-8218-7b16f92d4f6e
Received POST message for sessionId be9eb6e4-646a-43c1-8218-7b16f92d4f6e
Received POST message for sessionId be9eb6e4-646a-43c1-8218-7b16f92d4f6e
Error from MCP server: Error: SSE stream disconnected: TypeError: terminated
at processStream (file:///Users/umeshkaul/Projects/inspector/node_modules/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js:203:88)
at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
Received POST message for sessionId be9eb6e4-646a-43c1-8218-7b16f92d4f6e
Error from MCP server: Error: Error POSTing to endpoint (HTTP 401): {"error":"Unauthorized","request_id":"e9e63bda-4f70-4f16-bbc3-e35852873cca"}
at StreamableHTTPClientTransport.send (file:///Users/umeshkaul/Projects/inspector/node_modules/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js:284:23)
at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
Received POST message for sessionId be9eb6e4-646a-43c1-8218-7b16f92d4f6e
- 以下演示展示了如何仅授权白名单中的工具,而拒绝其他工具
MCP Inspector with Google OAuth via Pomerium Demo
3b. 使用 mcp-cli 翻译为中文是“MCP 命令行界面”或“MCP 命令行工具”。这里,“MCP”可能代表某个特定的系统、服务或平台的名称,而“cli”则是“Command Line Interface”的缩写,意为“命令行界面” 进行测试
- 使用
npm install -g mcp-cli下载并安装mcp-cli。参见 这个 详细说明的链接。
💻 Launch the cli (see my example below)
mcp-cli % npm start https://www.ukaul.net:8443/mcp
> mcp-cli@1.0.0 start
> node dist/cli/cli.js https://www.ukaul.net:8443/mcp
🚀 MCP CLI - Interactive Client
Connecting to: https://www.ukaul.net:8443/mcp
🔗 Attempting to connect to https://www.ukaul.net:8443/mcp with OAuth...
🚢 Trying Streamable HTTP transport with OAuth...
Could not load OAuth Protected Resource metadata, falling back to /.well-known/oauth-authorization-server Error: Resource server does not implement OAuth 2.0 Protected Resource Metadata.
📌 OAuth redirect handler called - opening browser
🌐 Opening browser for authorization: https://www.ukaul.net:8443/.pomerium/mcp/authorize?response_type=code&client_id=db0c4b07-8981-41c5-a845-6e9029da35de&code_challenge=P43mK15rVhrz0q-boNx5QR99PSMz4eAlXqEqFhTKKGQ&code_challenge_method=S256&redirect_uri=http%3A%2F%2Flocalhost%3A8090%2Fcallback&scope=mcp%3Atools
Client error: UnauthorizedError: Unauthorized
OAuth callback server started on http://localhost:8090
📥 Received callback: /callback?code=yPT0BOxo9M7uf8%2Ft%2FTkimHfawyEwgQXeXv1C5pP%2F6g%2Ffc48VhSYw8aTDKLSkYsvn1abNgzfI9inA%2F%2BmeiICjlkxFo1IbreNeXKOMsmKwxtoiWNQ9H8gfLP3D56755w%3D%3D&state=
✅ Authorization code received: yPT0BOxo9M...
✅ Authorization code received: yPT0BOxo9M...
🔐 Authorization completed, reconnecting...
Could not load OAuth Protected Resource metadata, falling back to /.well-known/oauth-authorization-server Error: Resource server does not implement OAuth 2.0 Protected Resource Metadata.
🎯 Successfully connected using streamable-http transport
🎯 Interactive MCP Client
Connected via: streamable-http
Type "help" for available commands or "quit" to exit
mcp> 📥 Received callback: /apple-touch-icon-precomposed.png
❌ No authorization code or error in callback
📥 Received callback: /apple-touch-icon.png
❌ No authorization code or error in callback
mcp>
mcp> list
📋 Available tools:
1. configuration_view
Description: Get the current Kubernetes configuration content as a kubeconfig YAML
2. events_list
Description: List all the Kubernetes events in the current cluster from all namespaces
- 以下演示展示了如何仅授权白名单中的工具,而拒绝其他工具
MCP CLI with Google OAuth via Pomerium Demo
更多关于Pomerium MCP支持的信息
Pomerium 提供了三种保护 MCP 服务器的方法——在本文中我们仅探讨了第一种方法。
1. 外部AI访问内部MCP服务器
Pomerium充当一个安全网关,在允许访问内部MCP服务器之前,会验证用户和AI的授权。这既防止了外部AI直接访问敏感的内部数据,又应用了细粒度的角色基于权限管理。例如,一名营销经理使用Claude从公司CRM数据库生成报告时,Pomerium会先验证该经理的身份和授权,然后才允许其访问内部MCP服务器;例如,他们可能对某些工具只有只读访问权限,而对MCP服务器暴露的其他工具则有完全访问权限。这就是我们将在本博客文章中演示的内容。
2. 外部服务的OAuth管理
Pomerium负责处理MCP服务器需要连接的外部服务(如GitHub)的认证流程,通过提供安全的临时令牌来替代直接存储凭据。这样既避免了凭据暴露给AI代理,又保持了访问的安全性。例如,当内部AI代理需要搜索私有GitHub仓库时,Pomerium会管理与GitHub的OAuth流程,并向MCP服务器提供一个安全令牌,确保AI永远不会直接处理或看到敏感的开发者凭据。
3. 为内部应用程序提供安全令牌
Pomerium为内部应用程序发放针对特定用户的、有效期短的令牌,使人工智能功能能够代表特定员工进行身份验证,同时确保所有人工智能操作均可审计且可追溯至用户。例如,当员工使用项目管理应用程序的人工智能功能创建任务时,Pomerium会发放一个安全令牌,该应用程序将此令牌传递给人工智能,从而使人工智能能够证明其是在代表员工行事,而不是直接进行自我认证。
