内容
# AIRS 运行时 API 拦截,用于 Amazon API Gateway + Lambda(MCP 后端)
一个最小、可部署的参考示例,展示了将 Prisma AIRS 运行时扫描集成到 Amazon API Gateway + Lambda 架构中的**正确位置**,该架构面向 MCP 服务器:**集成 Lambda**,而非 Lambda 授权器。
它的存在是因为这是 AWS AIRS POV 中容易出错的地方。AIRS “API 拦截”是一个同步调用,您的代码会调用 AIRS 扫描 API;然后您强制执行判决。人们首先想到 Lambda 授权器,但它无法工作,因为**授权器永远不会看到请求体**(其中包含提示)。部署此示例,运行测试,您就拥有了一个已知的良好堆栈,可以与损坏的堆栈进行比较。
## 架构
```
Authorization: Bearer <token>
客户端 ──POST /mcp──▶ Amazon API Gateway
│
├─▶ Lambda 授权器 (仅身份验证;获取令牌,不获取正文)
│ └─ 允许 / 拒绝
│
└─▶ AIRS 网关 Lambda ◀── AIRS 扫描位于此处
1. 解析 event["body"] (字符串;如果 isBase64Encoded,则为 base64)
2. 预调用 扫描提示 ──▶ AIRS 扫描 API
action=block ─▶ 403,停止
3. 调用 ──▶ MCP 服务器 Lambda(JSON-RPC 后端)
4. 后调用 扫描响应 ──▶ AIRS 扫描 API (捕获 DLP)
action=block ─▶ 403
5. 返回 MCP 结果
```
## 为什么授权器是错误的位置(教学要点)
| 位置 | 看到请求体? | 可以阻止? | AIRS 的正确位置? |
| --- | --- | --- | --- |
| Lambda 授权器(TOKEN) | 否 - 只有令牌头 | 仅允许/拒绝 | 否 |
| Lambda 授权器(REQUEST)/ HTTP API 授权器 | 否 - 头部/查询/路径/上下文,永远不是正文 | 仅允许/拒绝 | 否 |
| API Gateway 映射模板(VTL) | 是,但无法向 AIRS 发出出站 HTTPS 调用 | 否 | 否 |
| **集成/处理 Lambda** | **是** | **是** | **是** |
提示(或 MCP 工具调用)位于正文中。只有集成 Lambda 拥有正文 *和* 能够用阻止短路。所以 AIRS 扫描 API 调用位于此处。授权器继续执行身份验证。参见 `functions/authorizer/app.py` 中的显式“此处无正文”注释。
## 您需要
- AWS SAM CLI(`brew install aws-sam-cli`)和用于沙箱帐户的 AWS 凭证。
- Prisma AIRS **运行时扫描 API 密钥**(数据平面 `x-pan-token`,而非管理凭证)。
- 要扫描的 AIRS **安全配置文件名称**。
## 部署
```bash
sam build
sam deploy --guided
# 回答提示:
# AirsApiKey = <您的 AIRS 运行时扫描 API 密钥>
# AirsProfileName = <您的 AIRS 配置文件名称> <-- 必需(参见问题 #2)
# AirsEndpoint = (默认美国;如果为欧盟等,请使用区域 URL)
# AirsFailOpen = false (在 AIRS 错误/超时时阻止)
# AirsAppName = airs-apigw-mcp-intercept
# DemoBearerToken = <选择一个> (演示授权器接受此令牌)
```
`ApiUrl` 输出是您的端点。
### 在没有 SAM 的情况下部署(SCP 限制帐户)
一些托管 AWS 组织阻止 SAM 转换宏(您将看到 `is not authorized to perform: cloudformation:CreateChangeSet on resource: arn:aws:cloudformation:...:aws:transform/Serverless-2016-10-09`)。在这种情况下,请使用纯 CloudFormation 模板 `cloudformation.yaml`(无转换)通过帮助器脚本:
```bash
export CODE_BUCKET="您拥有的 S3 存储桶" # 在您的区域
export AIRS_API_KEY="$PANW_AI_SEC_API_KEY"
export AIRS_PROFILE_NAME="my-dlp-block-profile"
export DEMO_BEARER_TOKEN="选择一个"
./scripts/deploy-cfn.sh # 压缩,上传,创建/更新堆栈,打印 ApiUrl
```
这部署了相同的架构,只有 `CAPABILITY_IAM`(无宏),因此它在 `sam deploy` 被阻止的地方有效。**这是已在实时 AIRS 租户上验证的端到端**(以下六个测试结果,包括阶段=response DLP 捕获)。
## 测试
```bash
export API_URL="<ApiUrl 输出>"
export TOKEN="<您选择的 DemoBearerToken>"
./scripts/test.sh
```
预期结果:
| # | 请求 | 结果 |
| --- | --- | --- |
| 1 | 良性 `get_weather` | `200` + 天气(流经 AIRS 到 MCP) |
| 2 | `echo` 参数中的恶意指令 | `403 blocked_by prisma-airs, stage=prompt` (预调用) |
| 3a | `get_account_details` (另一个客户的记录) | `403 stage=prompt` (工具调用本身触发主题/代理检测器) |
| 3b | `view_profile` (良性调用,响应中仅包含 PII) | `403 stage=response` (后调用 / DLP) |
| 4 | 错误的令牌 | 来自授权器的 `403` (AIRS 永远不会运行) |
| 5 | 无令牌 | 来自授权器的 `401` |
测试 3b 是竞争性 POV 中最重要的测试:调用看起来是良性的,秘密/PII 仅在**响应**中,只有后调用扫描才能捕获它。仅提示过滤永远看不到它。(3a 与 3b 显示 AIRS 在两个不同阶段捕获相同敏感数据。)
触发的精确检测器取决于您的 AIRS 配置文件。这些结果在具有提示注入/代理安全/主题和 **DLP 设置为阻止** 的配置文件上进行了实时验证。如果 DLP 设置为 *alert*(而非阻止),测试 3b 返回 `200`,并且 PII 被记录,而不是被阻止 - 选择一个 DLP 阻止配置文件来演示响应捕获。
## 两个容易出错的地方
1. **`event["body"]` 是一个字符串**(当 `event["isBase64Encoded"]` 为真时为 base64)。您必须 `json.loads` 它并提取实际的提示,然后再进行扫描。转发 API Gateway 事件信封或仍为字符串的正文是经典的“错误的有效负载到 AIRS”。在 `_parse_body()` 中处理。
2. **`profile_name` 是必填字段。** 如果没有 `ai_profile`,扫描 API 返回 400,而天真的集成 **无声失败打开**。此参考日志大声显示并默认关闭(`AirsFailOpen=false`)。在 `_scan()` 中处理。
## 适应现有的 API Gateway + Lambda
如果客户已经拥有 API Gateway →(授权器)→ MCP/Lambda,您不需要重写它:
1. 让授权器保持不变(仅身份验证)。
2. 在 API Gateway 和 MCP 后端之间放置一个小的“AIRS 网关”Lambda(或在现有处理程序的顶部/底部内联四个扫描步骤)。复制 `functions/airs_gateway/app.py`。
3. 在其中:`json.loads(event["body"])` → 扫描提示 → 允许时调用 MCP 后端 → 扫描响应 → 返回。
4. 设置 `AIRS_API_KEY` 和 `AIRS_PROFILE_NAME`(以及端点/失败打开)。
5. 将 API Gateway 的集成指向 AIRS 网关 Lambda。
如果他们不想自己进行 MCP 扫描,`pan-mcp-relay` 是一个专门的 MCP 扫描代理 - 但对于“我们自己的 API Gateway + Lambda 中的运行时拦截”,这是模式。
## 文件
```
template.yaml SAM 堆栈(推荐;一个 `sam deploy`)
cloudformation.yaml 纯 CFN 等价项(无转换)用于 SCP 限制帐户
functions/authorizer/app.py 仅身份验证;记录为什么 AIRS 不能位于此处
functions/airs_gateway/app.py AIRS 拦截(预 + 后扫描,强制执行,失败打开/关闭)
functions/mcp_server/app.py 微小的 JSON-RPC MCP 后端(良性/恶意/ PII 工具)
scripts/deploy-cfn.sh 压缩 + 上传 + 部署纯 CFN 版本(无需 SAM CLI)
scripts/test.sh curl 上述场景
docs/architecture.md 更深入的请求流演练
```
## 注释
- Lambda 仅使用 Python 标准库(`urllib`)和 `boto3`(已经在运行时),因此没有依赖层,`sam build` 无需 `pip` 步骤。
- 这是一个故意易受攻击的后端上的参考/ POV 资产。在更改种子数据和演示令牌之前,请勿将其指向任何真实内容。