Skip to content

Repository files navigation

mantle-proxy

AWS Bedrock mantle gateway 纯透传代理 —— 让你借代理的出口 IP 绕过 mantle 对 Anthropic (Claude)模型的源 IP 地域封锁

mantle(bedrock-mantle.<region>.api.aws)对 Anthropic 模型按请求源 IP 的地理位置封锁:从受限 地区(如中国大陆)的 IP 调 Claude 会返回 400 Access to Anthropic models is not allowed,而 GLM / MiniMax 等 OpenAI 兼容模型放行。本代理部署在不受限地区(如东京 ap-northeast-1),你把 mantle host 换成代理域名、带上你自己的 mantle Bearer token,请求经代理转发,mantle 看到的源 IP 变成 代理所在地 → Claude 放行。

通用开放中继:代理不持任何密钥、不做调用方鉴权、不绑定任何具体调用方。每个人用自己的 token,quota / 计费落在各自 token 上。它只是一个纯转发器。

怎么用(3 步)

只需把你原来直连 mantle 的代码里的 host 换成代理域名,其余(路径、Bearer token、请求体)完全不变。

1. 换 host —— 原来:

https://bedrock-mantle.ap-northeast-1.api.aws

换成:

https://proxy-mantle.example.com

2. 带上你自己的 Bearer token(代理原样透传 Authorization,不持有、不校验)。

3. 照常调两条路径之一:

Claude(Anthropic Messages API):

curl -N https://proxy-mantle.example.com/anthropic/v1/messages \
  -H "Authorization: Bearer $YOUR_MANTLE_TOKEN" \
  -H "Content-Type: application/json" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-workspace-id: default" \
  -d '{
    "model": "anthropic.claude-haiku-4-5",
    "max_tokens": 256,
    "stream": true,
    "messages": [{"role": "user", "content": "你好"}]
  }'

GLM / MiniMax 等(OpenAI 兼容 Chat Completions):

curl -N https://proxy-mantle.example.com/v1/chat/completions \
  -H "Authorization: Bearer $YOUR_MANTLE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "zai.glm-4.7-flash",
    "max_tokens": 256,
    "stream": true,
    "messages": [{"role": "user", "content": "你好"}]
  }'

模型 ID 用 mantle 短名(如 anthropic.claude-haiku-4-5),不是 us.anthropic.*-vX:0 那种 inference-profile 格式。流式(stream: true)与非流式都支持。

行为契约(与直连 mantle 逐字节等价)

  • 纯透传:path / query / 请求体 / Authorization 及其它头原样转发;上游响应(状态码 / 头 / 体) 原样回传。代理不解析、不改写请求体。
  • 双向流式(SSE):请求体和响应体都流式,不缓冲。首字节延迟与直连同量级。
  • 上游错误如实透传:mantle 返回什么状态码(含 4xx / 5xx),代理原样回,不改写、不自动重试
  • 超时:上游连接/读超时 → 504;上游连接/TLS 失败 → 502
  • GET /healthz200(存活探针,不依赖上游)。

安全模型

这是有意的开放转发器(公网入口 + 无调用方鉴权 + 纯透传),可接受,因为:

  • 代理不持任何密钥——没 token 就调不动(上游 mantle 直接 401/400),代理不放行、不伪造。
  • quota / 计费落在调用方各自的 token 上;token 泄露风险由持有者承担,与代理无关。
  • 代理只转发到硬编码的有界上游集合(2 个固定 host 模板 × 合法 region 语法,不是任意 URL 代理), 忽略入站 Host → 无 SSRF 面(见 specs/002-multi-upstream-routing.md)。
  • 过路凭据不留痕:代理绝不把 Authorization 或请求/响应体写入日志。
  • 防滥用 = 入口 WAF per-IP 限流(防单 IP 霸占带宽);分布式滥用由上游按各 token quota 兜底。

使用建议:token 只经 HTTPS 传输、不要写进日志 / 客户端二进制;它是短时 Bearer,妥善保管。

架构

你的代码 (host = proxy-mantle.example.com, 带你的 Bearer token)
      │  HTTPS
      ▼
[Route53] → [公网 ALB :443 (ACM, idle 300s, access log→私有S3)]
      │        └ REGIONAL WAF (per-IP 限流)
      ▼
[ECS Fargate ×2 (ARM64, 常驻无冷启动)  Rust 纯透传代理]
      │  出站 HTTPS (硬编码上游, TLS 验证, TCP keepalive)
      ▼
bedrock-mantle.<部署region>.api.aws   ← 上游跟随部署 region:东京→东京、美国→us endpoint
  • ALB + ECS Fargate(不用 Lambda Function URL / API Gateway):ALB 原生透传 SSE 流式;Fargate desiredCount≥1 常驻无冷启动。
  • 上游 endpoint 跟随部署 region:部署到东京 → 上游东京 mantle;部署到美国 → 上游 us mantle。

附:传统 Bedrock(非 mantle)是否也能这么绕?

已验证(2026-07-10,美区 sandbox vs 北京 EC2 对照):传统 Bedrock Runtime (bedrock-runtime.<region>.amazonaws.com)对 Anthropic 模型的地域封锁与 mantle 同源——按源 IP 地理位置封锁,错误文案一致(Access to Anthropic models is not allowed from unsupported countries...), 非 Anthropic 模型(如 Amazon Nova)不受影响。且传统 Bedrock 支持纯 Authorization: Bearer <API Key> 鉴权(IAM create-service-specific-credential --service-name bedrock.amazonaws.com 生成的长期 key,走 REST POST /model/<id>/converse),不必 SigV4——鉴权模型与 mantle 几乎一致,东京出口理论上同样能绕。

已实现,不需要独立部署:同一个代理 endpoint 已支持按 ?mantle=&region= 参数切换到传统 Bedrock(见下「单 endpoint 同时代理 mantle 与传统 Bedrock」),不必另起一套栈。

模型 ID 格式不同,调用方需自行注意(代理不解析/不转换 body,这是调用方侵入,不是代理要处理的事):

  • mantle:裸短名,如 anthropic.claude-sonnet-4-6
  • 传统 Bedrock:新一代模型的 on-demand 调用大多要求带 scope 前缀的 inference profile ID,如 jp.anthropic.claude-sonnet-4-6(区域级)或 global.anthropic.claude-sonnet-4-6(全球级);裸短名 会报 ... isn't supported. Retry your request with the ID or ARN of an inference profile

单 endpoint 同时代理 mantle 与传统 Bedrock(?mantle=&region=)

不带任何参数时,代理行为不变(转发到部署时配置的 UPSTREAM_HOST)。带上这两个白名单参数,可以在 同一个代理 endpoint 上切换上游:

# 显式选传统 Bedrock + us-east-1(注意:model ID 要用能跨区域的 global. scope,
# 不能用锁区域的 jp. scope 去配一个不匹配的 region)
curl -N "https://proxy-mantle.example.com/model/global.anthropic.claude-sonnet-4-6/converse?mantle=false&region=us-east-1" \
  -H "Authorization: Bearer $YOUR_BEDROCK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"messages":[{"role":"user","content":[{"text":"你好"}]}]}'

# 只选 region,mantle 默认 true(走 mantle 家族)
curl -N "https://proxy-mantle.example.com/anthropic/v1/messages?region=us-west-2" \
  -H "Authorization: Bearer $YOUR_MANTLE_TOKEN" ...
  • mantle=false → 上游 = bedrock-runtime.<region>.amazonaws.com(传统 Bedrock);缺省或 mantle=true → 上游 = bedrock-mantle.<region>.api.aws(mantle,现状行为)。
  • region 缺省时使用代理部署 region。
  • 这两个参数是代理自己的路由控制参数,转发前会被剥除,不会出现在上游收到的请求里。
  • region 只校验命名语法(如 xx-name-digit),不校验该 region 是否真实存在;传入一个语法合法 但不存在的 region 会在连接阶段失败,代理返回 502(而不是别的错误)。

完整行为契约见 specs/002-multi-upstream-routing.md

开发

# Rust 代理(纯逻辑 + 集成测试,wiremock fake 上游)
cargo test
cargo build --release

# 本地起代理(默认上游东京 mantle)
PORT=8899 ./target/release/mantle-proxy
# 另开终端:curl http://127.0.0.1:8899/anthropic/v1/messages ...(带你的 token)

# CDK 基础设施
cd infra && npm install
npm test                    # CDK 单测(jest,锁 idle 300s / WAF / ARM64 / 上游跟随 region / 无 Function URL)
npx cdk synth               # 合成 + cdk-nag 合规扫描

有两种部署模式,按域名 zone 是否在部署账号选:

A. 同账号自动模式(zone 在部署账号)

CDK 自动 lookup zone、签 ACM 证书(DNS 验证)、建 alias:

cd infra
AWS_PROFILE=<profile> AWS_REGION=ap-northeast-1 \
CDK_DEFAULT_REGION=ap-northeast-1 CDK_DEFAULT_ACCOUNT=<account> \
  npx cdk deploy --require-approval never \
  -c domainName=<fqdn> -c zoneName=<zone>

B. 跨账号 DNS 模式(zone 在另一个账号,如中国区 zone)

代理 ALB 在东京(Global 账号),但域名 zone 在别的账号(如 example.com 权威 NS 在中国区 Route53,是中国区可靠解析的必要条件)。CDK(Global 账号)无法 lookup 该 zone / 自动验证 / 建 alias, 须手动桥接:

  1. 在东京 ACM 手动签证书(给该 FQDN),拿验证 CNAME:
    CERT=$(AWS_PROFILE=<global> aws acm request-certificate \
      --domain-name proxy-mantle.example.com --validation-method DNS \
      --region ap-northeast-1 --query CertificateArn --output text)
    AWS_PROFILE=<global> aws acm describe-certificate --certificate-arn "$CERT" \
      --region ap-northeast-1 --query 'Certificate.DomainValidationOptions[0].ResourceRecord'
  2. 用能管该 zone 的凭据把验证 CNAME 写进 zone,等证书 ISSUED(ACM 自动续期也走同记录)。
  3. 部署时传 certificateArn(此时 stack 不 lookup zone、不建 alias):
    AWS_PROFILE=<global> AWS_REGION=ap-northeast-1 \
    CDK_DEFAULT_REGION=ap-northeast-1 CDK_DEFAULT_ACCOUNT=<account> \
      npx cdk deploy --require-approval never \
      -c domainName=proxy-mantle.example.com -c certificateArn="$CERT"
  4. 部署后取输出的 AlbDns,在 zone 里建 proxy-mantle.example.com CNAME → ALB DNS⚠️ CNAME 漂移:跨账号不能用 Route53 alias(只能 CNAME 指 ALB 官方 DNS 名)。ALB 若被重建 (DNS 名变),须手动更新该 CNAME。

上游 endpoint 跟随部署 region(东京→东京 mantle、美国→us endpoint),或 -c upstreamHost=<host> 显式覆盖。

配置(环境变量)

变量 默认 说明
UPSTREAM_HOST bedrock-mantle.<region>.api.aws 上游 mantle host(CDK 按部署 region 注入)
PORT 8080 监听端口
CONNECT_TIMEOUT_SECS 10 上游连接超时
READ_TIMEOUT_SECS 90 上游 TTFB 超时(SSE 拿到响应头后不再计整流)
TCP_KEEPALIVE_SECS 90 出站 TCP keepalive(防中间盒掐断长 idle SSE)

契约与设计

行为契约见 specs/001-tokyo-mantle-proxy.md(OpenSpec 风格 Requirement / Scenario)。经 codex + Kiro 双评审收敛。

License

Apache-2.0

About

AWS Bedrock mantle gateway 纯透传代理 —— 借非受限区出口 IP 绕过 Claude 源 IP 地域封锁(ALB + ECS Fargate + Rust,SSE 流式)

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages