跳到主要内容

IDE AI 流量正向代理

组织可以将 AISIX 部署在终止 TLS 的出口设备之后,以治理必须继续使用官方服务端点的 IDE 和编码 Agent 流量。本指南以 GitHub Copilot IDE 扩展和 Copilot CLI 为例。AISIX 从该设备接收明文 HTTP 流量,在使用员工凭证将各请求转发到官方上游之前,可以执行访问控制、审计、内容检查和请求限制。

AISIX 不会拦截 TLS,也不会签发证书颁发机构证书。客户端继续使用官方服务端点。流量可以通过显式代理配置或透明拦截到达出口设备;当该设备终止 TLS 时,客户端必须信任该设备的证书颁发机构。

前置条件

请准备以下内容:

  • 一个 AISIX 部署:
    • 对于 AISIX Cloud,需要一个已关联网关的环境,以及一个具有写入权限范围的管理员 Token。
    • 对于开源 AISIX 网关,需要将网关配置为加载声明式资源文件。
  • 一个能够保留原始 Host 请求头并注入 HTTP 请求头的 TLS 终止出口设备。
  • 在客户端计算机上配置代理和证书信任的权限。
  • 最新的 GitHub Copilot 允许列表Copilot 网络设置
  • curljq。本地验证使用 pipx 安装 mitmproxy

流量拓扑

客户端将 HTTPS 流量发送到出口设备。该设备终止 TLS,保留原始 Host,注入网关 Key 和员工身份,并将解密后的 HTTP 流量发送到 AISIX。AISIX 移除仅供网关使用的请求头,并通过 HTTPS 使用员工的上游凭证转发请求。

网关接受携带原始 Host 的 origin-form 请求,透明重定向和代理链均使用这种形式。当代理链中的上游代理未提供 Host 时,网关也可以读取 URI authority 来接受 absolute-form 请求目标。与 hosts 匹配的路由会先于网关自身的类型化路由执行,因此 /v1/messages 等上游路径会被转发,而不会由网关的 Messages 端点处理。

选择要检查的主机

路由示例在路由的 hosts 字段中使用以下值,以检查 Copilot 推理、代码建议和选定的 GitHub API 流量:

resources.yaml(路由 hosts 字段)
hosts:
- api.githubcopilot.com
- "*.individual.githubcopilot.com"
- "*.business.githubcopilot.com"
- "*.enterprise.githubcopilot.com"
- copilot-proxy.githubusercontent.com
- origin-tracker.githubusercontent.com
- api.github.com

这并不是完整的 Copilot 网络允许列表。身份认证、资产、遥测、实验和编辑器特定服务可能会使用其他主机。请对照 GitHub 最新的允许列表检查出口策略,再决定设备将哪些主机发送到 AISIX,以及允许哪些主机直接访问。

api.github.com 由 Copilot 和其他 GitHub 客户端共享。如果设备分流该主机,所有使用此代理的客户端对该主机发出的请求都可能匹配此路由。如果只有选定的 GitHub API 路径需要经过 AISIX,请从路由中移除该主机,或在设备上缩小分流范围。

配置 Copilot 路由

该路由使用 preserve_host,以便通过一个允许列表转发多个官方主机。header_key 使用设备注入的网关凭证,而 forward_client 则保留员工的上游 Authorization,供 GitHub 使用。

AISIX Cloud

导出 AISIX Cloud 连接信息:

# AISIX_CP 包含 /api,且末尾没有斜杠。
export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_BASE_URL"
export AISIX_TOKEN="YOUR_ADMIN_TOKEN"
export ENV_ID="YOUR_ENVIRONMENT_ID"

创建路由:

ROUTE_RESPONSE=$(curl --fail-with-body -sS -X POST \
"$AISIX_CP/environments/$ENV_ID/passthrough_routes" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "copilot",
"hosts": [
"api.githubcopilot.com",
"*.individual.githubcopilot.com",
"*.business.githubcopilot.com",
"*.enterprise.githubcopilot.com",
"copilot-proxy.githubusercontent.com",
"origin-tracker.githubusercontent.com",
"api.github.com"
],
"preserve_host": true,
"auth_mode": "header_key",
"auth_header_name": "x-aisix-api-key",
"credential_mode": "forward_client",
"identity_header": "x-aisix-user"
}')

export ROUTE_ID=$(printf '%s' "$ROUTE_RESPONSE" | jq -er '.passthrough_route.id')
printf '%s' "$ROUTE_RESPONSE" | jq '.warnings // []'

如果计划专门为此路由关联安全护栏,请保留 ROUTE_ID

为出口设备创建专用调用方 Key。其明文只会返回一次:

CALLER_RESPONSE=$(curl --fail-with-body -sS -X POST \
"$AISIX_CP/environments/$ENV_ID/api_keys" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"display_name": "Copilot egress device",
"allowed_models": [],
"allowed_routes": ["copilot"]
}')

export EGRESS_DEVICE_KEY=$(printf '%s' "$CALLER_RESPONSE" | jq -er '.plaintext')
printf '%s' "$CALLER_RESPONSE" | jq '.warnings // []'

也可以在控制台中完成相同的操作,入口分别位于环境的 Passthrough Routes 页面和调用方 Key 的 Passthrough route access 部分。上线前请检查返回的所有兼容性警告。警告仅供参考,因此请通过每个网关验证流量。关联路由范围的安全护栏时,也可能产生相应的警告。

开源 AISIX 网关

选择出口设备要注入的 Key:

export EGRESS_DEVICE_KEY="YOUR_GATEWAY_CALLER_KEY"

从网关当前使用的完整资源文件开始配置。将路由和调用方 Key 添加到对应的集合中,并保持不相关的资源不变:

resources.yaml(Copilot 路由和调用方 Key)
passthrough_routes:
- name: copilot
hosts:
- api.githubcopilot.com
- "*.individual.githubcopilot.com"
- "*.business.githubcopilot.com"
- "*.enterprise.githubcopilot.com"
- copilot-proxy.githubusercontent.com
- origin-tracker.githubusercontent.com
- api.github.com
preserve_host: true
auth_mode: header_key
auth_header_name: x-aisix-api-key
credential_mode: forward_client
identity_header: x-aisix-user

api_keys:
- display_name: egress-device
key_env: EGRESS_DEVICE_KEY
allowed_models: []
allowed_routes: [copilot]

验证组装后的完整文件:

aisix validate --resources resources.yaml

在进程环境中设置 EGRESS_DEVICE_KEY,然后启动或重新创建网关。重新加载无法向已运行的进程添加环境变量。

了解身份认证和归属信息

员工的上游凭证保留在 Authorization 中,因此网关凭证需要使用不同的传递方式:

  • 上文所示的 header_keyx-aisix-api-key 读取网关 Key,并在转发前移除该请求头。员工的 Authorization 仍可供 GitHub 使用。
  • 当设备无法注入网关 Key 时,可以使用 anonymous。将路由绑定到专用的调用方 Key 主体,并将 source_cidrs 限制为 AISIX 为这些请求解析出的地址:通常是设备地址;如果启用了真实客户端 IP 解析,则为原始客户端网段。

在这两种模式中,解析出的调用方 Key 都必须在 allowed_routes 中授予 copilot

按员工追踪流量

AISIX 不会验证 identity_header 中的值。出口设备必须验证员工身份,移除客户端提供的所有 x-aisix-user,并用可信身份覆盖该请求头。AISIX 将受长度限制的值记录为 client_identity,并在转发前移除该请求头。

如果没有此请求头,解析出的来源 IP 通常表示出口设备,而不是员工。要恢复原始客户端地址,请只为确切的可信设备网段和转发请求头配置真实客户端 IP 解析。对于匿名路由,还需要在 source_cidrs 中允许这些解析出的客户端网段。

应用审计、安全护栏和限制

该路由本身不拥有限流或预算配置。控制项从已认证的调用方解析,并在支持时从其他关联范围解析。

请求限制

调用方 API Key、团队和成员的请求限制会在分发前应用。透传路由没有限流字段或路由策略范围。如果不同主机组需要不同的请求限制或并发限制,请使用不同的调用方 Key。

从可识别协议载荷中提取的 Token 用量会记录在用量事件中,但不会递增 tpmtpd 计数器。已经耗尽的共享 Token 计数器可以拒绝请求,但透传流量不会推进该计数器。对于 SSE,AISIX 返回流式响应时会释放并发配额,而不是等到数据流结束时才释放。

预算

在 AISIX Cloud 中,已经应用于解析后调用方的预算会在分发前检查。透传用量目前没有模型 ID,以零成本记录,也不会向预算账本增加支出。开源 AISIX 网关没有本地预算资源。

安全护栏

在 AISIX Cloud 中,使用 Passthrough routes 范围关联安全护栏,可以只检查此路由。环境、调用方 Key 和团队范围的安全护栏也可能应用。

开源资源文件通过 guardrail_attachments 集合声明挂载关系,因此文件中定义的安全护栏只有在 Attachment 将其作用域覆盖到此路由时才会检查该路由的流量:可以使用 scope_type: env 覆盖整个环境,也可以使用 scope_type: passthrough_route 并指定此路由。

请求被拦截时,会在调用上游之前返回 422。缓冲响应会在交付前接受检查。SSE 响应开始后,如果触发拦截,数据流会以 SSE content_filter 错误帧结束。启用暂缓发送的安全护栏可能会在检查期间延迟数据帧。

内容和用量导出

对于成功转发的流量,配置了 content_mode: full 的可观测性导出器会以字符串内容接收请求体,而不是接收服务提供方协议载荷的标准化副本。当缓冲响应符合支持的提取格式时,会记录提取出的文本;否则,会将响应体记录为文本。对于流式响应,会记录累积提取出的文本;不透明的数据载荷也会作为文本保留。所有采集仍受已配置的限制约束。

采集的内容只会发送到支持内容的导出器。用量事件包含匹配的路由、调用方、记录的 Token 数量和 client_identity。当前 AISIX Cloud 的 Request Logs 界面会显示调用方和 Token 元数据,但不会显示 passthrough_route_nameclient_identity

了解 Copilot CLI 流量

GitHub Copilot CLI 是一个能够编辑文件、运行 Shell 命令、选择模型并使用其内置 GitHub MCP 服务器的 Agent。其确切的网络端点和协议载荷选择取决于版本,不属于本 AISIX 配置契约的一部分。

AISIX 会识别 messagesinputprompt 请求格式,以便为安全护栏提取内容并提取用量信息。其他流量(包括 JSON-RPC 和普通 GitHub API 调用)均视为不透明流量,并在不转换请求体协议的情况下转发。因此,选定的主机路由不需要协议字段。

GitHub 文档将 /model/mcp/usage/context 列为 CLI 命令,但具体命令是否发送网络流量可能随客户端版本变化。请在实际环境中验证当前客户端行为,不要依赖固定的端点清单。

使用 mitmproxy 验证开源网关

以下本地练习使用 mitmproxy 作为终止 TLS 的设备。本地快速入门网关监听 127.0.0.1:3000,mitmproxy 监听 127.0.0.1:8888

  1. 使用上面配置的 Copilot 路由、调用方 Key 和 EGRESS_DEVICE_KEY 启动网关。

  2. 安装并验证 mitmproxy:

    pipx install mitmproxy
    mitmdump --version
  3. 将以下设备脚本保存为 mitm_to_aisix.py。该脚本会分流选定的主机,恢复原始 Host,注入网关 Key 和用户身份,并保持 SSE 流式传输:

    mitm_to_aisix.py
    import os

    from mitmproxy import http

    AISIX_HOST, AISIX_PORT = "127.0.0.1", 3000
    GATEWAY_KEY = os.environ["EGRESS_DEVICE_KEY"]
    IDENTITY = os.environ.get("AISIX_CLIENT_IDENTITY", "alice@example.com")

    COPILOT_HOSTS = {
    "api.githubcopilot.com",
    "copilot-proxy.githubusercontent.com",
    "origin-tracker.githubusercontent.com",
    "api.github.com",
    }
    COPILOT_SUFFIXES = (
    ".individual.githubcopilot.com",
    ".business.githubcopilot.com",
    ".enterprise.githubcopilot.com",
    )


    def _matches_one_label(host: str, suffix: str) -> bool:
    if not host.endswith(suffix):
    return False
    label = host[: -len(suffix)]
    return bool(label) and "." not in label


    def _diverted(host: str) -> bool:
    return host in COPILOT_HOSTS or any(
    _matches_one_label(host, suffix) for suffix in COPILOT_SUFFIXES
    )


    def request(flow: http.HTTPFlow) -> None:
    host = flow.request.pretty_host
    if not _diverted(host):
    return
    flow.request.host = AISIX_HOST
    flow.request.port = AISIX_PORT
    flow.request.scheme = "http"
    flow.request.headers["host"] = host
    flow.request.headers["x-aisix-api-key"] = GATEWAY_KEY
    flow.request.headers["x-aisix-user"] = IDENTITY


    def responseheaders(flow: http.HTTPFlow) -> None:
    if "text/event-stream" in flow.response.headers.get("content-type", ""):
    flow.response.stream = True

    设置 flow.request.host 会改写 Host 请求头,因此脚本随后会恢复上游主机。如果没有这一行,请求将无法匹配任何主机路由。响应钩子可防止 mitmproxy 将 SSE 缓冲成一个延迟响应。

  4. 在环境中设置网关 Key,并启动代理:

    export AISIX_CLIENT_IDENTITY="alice@example.com"
    mitmdump -s mitm_to_aisix.py --listen-port 8888

    mitmproxy 第一次启动时,会创建后续步骤使用的本地证书颁发机构。

  5. 在另一个终端中,使用已获准执行测试请求的凭证,对代理分流、路由匹配以及到 GitHub 的转发进行冒烟测试:

    curl -x "http://127.0.0.1:8888" \
    --cacert ~/.mitmproxy/mitmproxy-ca-cert.pem \
    -H "Authorization: Bearer YOUR_GITHUB_TOKEN" \
    "https://api.github.com/user"

    如果 401 中提到 x-aisix-api-key,说明设备 Key 未传入。如果返回 403,说明该 Key 未被授予 copilot。空的 404 通常意味着原始主机与路由不匹配。

  6. 配置 Copilot 客户端使用 mitmproxy,并信任其证书颁发机构。Copilot 会检查标准代理变量和 NODE_EXTRA_CA_CERTS

    export HTTPS_PROXY="http://127.0.0.1:8888"
    export HTTP_PROXY="http://127.0.0.1:8888"
    export NODE_EXTRA_CA_CERTS="$HOME/.mitmproxy/mitmproxy-ca-cert.pem"
    copilot

    对于编辑器插件,请配置其 HTTP 代理设置,并让编辑器进程使用同一个证书颁发机构。请按照 GitHub 最新的网络设置文档配置实际使用的客户端。

  7. 如有需要,请配置 OTLP/HTTP 导出器,发送一个普通请求并检查导出的 Span。确认其中记录了 aisix.passthrough.route_name: copilot,并将注入的身份记录为 aisix.client_identity

若要在开源部署中检查 DLP,请声明关键词安全护栏并添加 Attachment:使用 scope_type: env 覆盖整个网关,或使用 scope_type: passthrough_route 并指定此路由。在 AISIX Cloud 中,也请先以同样方式将安全护栏挂载到此路由,再测试被拦截的提示词。

适用范围和限制

  • 透传路由不会转发 WebSocket 升级请求;请从设备分流规则中排除相应主机或路径。
  • preserve_host 以 443 端口上的 https://<matched-host> 为目标。
  • AISIX 不执行 TLS 拦截,也不提供证书颁发机构工具。
  • Copilot 主机和客户端行为会独立于 AISIX 发生变化。部署或升级集成时,请重新检查 GitHub 的允许列表和客户端网络文档。

后续步骤