受信任代理認證
安全敏感功能。 此模式將認證完全委派給你的反向代理。設定錯誤可能讓你的 Gateway 暴露在未授權存取之下。啟用前請仔細閱讀本頁。
何時使用
在以下情況使用 trusted-proxy 認證模式:
- 你在一個身分感知代理(Pomerium、Caddy + OAuth、nginx + oauth2-proxy、Traefik + forward auth)後面運行 OpenClaw
- 你的代理已處理所有認證並透過 header 傳遞使用者身分
- 你在 Kubernetes 或容器環境中,代理是唯一能到達 Gateway 的路徑
- 你遇到 WebSocket
1008 unauthorized錯誤,因為瀏覽器無法在 WS payload 中傳遞 token
何時不該使用
- 如果你的代理不認證使用者(只做 TLS 終止或負載平衡)
- 如果有任何路徑可以繞過代理到達 Gateway(防火牆漏洞、內部網路存取)
- 如果你不確定代理是否正確地剝除/覆寫轉送 header
- 如果你只需要個人單使用者存取(考慮 Tailscale Serve + loopback,設定更簡單)
運作原理
- 你的反向代理認證使用者(OAuth、OIDC、SAML 等)
- 代理加入一個帶有已認證使用者身分的 header(例如
x-forwarded-user: [email protected]) - OpenClaw 檢查請求是否來自受信任的代理 IP(在
gateway.trustedProxies中設定) - OpenClaw 從設定的 header 中提取使用者身分
- 如果一切正確,請求即被授權
Control UI 配對行為
當 gateway.auth.mode = "trusted-proxy" 生效且請求通過受信任代理檢查時,Control UI WebSocket session 可以不需要裝置配對身分就能連線。
影響:
- 在此模式下,配對不再是 Control UI 存取的主要閘門。
- 你的反向代理認證策略和
allowUsers成為有效的存取控制。 - 確保 gateway 入口僅限受信任的代理 IP(
gateway.trustedProxies+ 防火牆)。
設定
{
gateway: {
// 同主機代理用 loopback;遠端代理主機用 lan/custom
bind: "loopback",
// 關鍵:只加入你代理的 IP
trustedProxies: ["10.0.0.1", "172.17.0.1"],
auth: {
mode: "trusted-proxy",
trustedProxy: {
// 包含已認證使用者身分的 header(必要)
userHeader: "x-forwarded-user",
// 選用:必須存在的 header(代理驗證)
requiredHeaders: ["x-forwarded-proto", "x-forwarded-host"],
// 選用:限制特定使用者(空 = 允許所有)
allowUsers: ["[email protected]", "[email protected]"],
},
},
},
}
如果 gateway.bind 是 loopback,在 gateway.trustedProxies 中加入 loopback 代理位址(127.0.0.1、::1 或等效的 loopback CIDR)。
設定參考
| 欄位 | 必要 | 說明 |
|---|---|---|
gateway.trustedProxies | 是 | 要信任的代理 IP 陣列。來自其他 IP 的請求會被拒絕。 |
gateway.auth.mode | 是 | 必須設為 "trusted-proxy" |
gateway.auth.trustedProxy.userHeader | 是 | 包含已認證使用者身分的 header 名稱 |
gateway.auth.trustedProxy.requiredHeaders | 否 | 請求被信任時必須存在的額外 header |
gateway.auth.trustedProxy.allowUsers | 否 | 使用者身分白名單。空表示允許所有已認證使用者。 |
TLS 終止與 HSTS
使用一個 TLS 終止點,並在那裡套用 HSTS。
建議模式:代理 TLS 終止
當你的反向代理為 https://control.example.com 處理 HTTPS 時,在代理層為該網域設定 Strict-Transport-Security。
- 適合面向網際網路的部署。
- 把憑證和 HTTP 強化策略集中在一處。
- OpenClaw 可以在代理後面保持 loopback HTTP。
Header 值範例:
Strict-Transport-Security: max-age=31536000; includeSubDomains
Gateway TLS 終止
如果 OpenClaw 自己直接提供 HTTPS(沒有 TLS 終止代理),設定:
{
gateway: {
tls: { enabled: true },
http: {
securityHeaders: {
strictTransportSecurity: "max-age=31536000; includeSubDomains",
},
},
},
}
strictTransportSecurity 接受字串 header 值,或 false 以明確停用。
上線指引
- 先用短的 max age(例如
max-age=300)驗證流量。 - 確認沒問題後再改為長期值(例如
max-age=31536000)。 - 只在所有子網域都準備好 HTTPS 時才加
includeSubDomains。 - 只在你確實符合整個網域集的 preload 要求時才使用 preload。
- Loopback-only 的本機開發不需要 HSTS。
代理設定範例
Pomerium
Pomerium 透過 x-pomerium-claim-email(或其他 claim header)傳遞身分,並在 x-pomerium-jwt-assertion 中包含 JWT。
{
gateway: {
bind: "lan",
trustedProxies: ["10.0.0.1"], // Pomerium 的 IP
auth: {
mode: "trusted-proxy",
trustedProxy: {
userHeader: "x-pomerium-claim-email",
requiredHeaders: ["x-pomerium-jwt-assertion"],
},
},
},
}
Pomerium 設定片段:
routes:
- from: https://openclaw.example.com
to: http://openclaw-gateway:18789
policy:
- allow:
or:
- email:
is: [email protected]
pass_identity_headers: true
Caddy with OAuth
Caddy 搭配 caddy-security 外掛可以認證使用者並傳遞身分 header。
{
gateway: {
bind: "lan",
trustedProxies: ["127.0.0.1"], // Caddy 的 IP(同主機時)
auth: {
mode: "trusted-proxy",
trustedProxy: {
userHeader: "x-forwarded-user",
},
},
},
}
Caddyfile 片段:
openclaw.example.com {
authenticate with oauth2_provider
authorize with policy1
reverse_proxy openclaw:18789 {
header_up X-Forwarded-User {http.auth.user.email}
}
}
nginx + oauth2-proxy
oauth2-proxy 認證使用者並透過 x-auth-request-email 傳遞身分。
{
gateway: {
bind: "lan",
trustedProxies: ["10.0.0.1"], // nginx/oauth2-proxy 的 IP
auth: {
mode: "trusted-proxy",
trustedProxy: {
userHeader: "x-auth-request-email",
},
},
},
}
nginx 設定片段:
location / {
auth_request /oauth2/auth;
auth_request_set $user $upstream_http_x_auth_request_email;
proxy_pass http://openclaw:18789;
proxy_set_header X-Auth-Request-Email $user;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
Traefik with Forward Auth
{
gateway: {
bind: "lan",
trustedProxies: ["172.17.0.1"], // Traefik 容器 IP
auth: {
mode: "trusted-proxy",
trustedProxy: {
userHeader: "x-forwarded-user",
},
},
},
}
安全檢查清單
啟用受信任代理認證前,確認以下各項:
- 代理是唯一路徑:Gateway 連接埠被防火牆限制,只有你的代理能存取
- trustedProxies 最小化:只包含實際代理 IP,不要放整個子網路
- 代理剝除 header:你的代理覆寫(而非附加)來自用戶端的
x-forwarded-*header - TLS 終止:你的代理處理 TLS;使用者透過 HTTPS 連線
- 已設定 allowUsers(建議):限制為已知使用者,而非允許所有已認證者
安全稽核
openclaw security audit 會以 critical 嚴重度標記受信任代理認證。這是故意的 — 它提醒你認證已委派給你的代理設定。
稽核會檢查:
- 缺少
trustedProxies設定 - 缺少
userHeader設定 allowUsers為空(允許任何已認證使用者)
疑難排解
”trusted_proxy_untrusted_source”
請求不是來自 gateway.trustedProxies 中的 IP。檢查:
- 代理 IP 是否正確?(Docker 容器 IP 會改變)
- 代理前面是否有負載平衡器?
- 用
docker inspect或kubectl get pods -o wide找出實際 IP
”trusted_proxy_user_missing”
使用者 header 為空或缺少。檢查:
- 你的代理是否設定了傳遞身分 header?
- Header 名稱是否正確?(不區分大小寫,但拼寫要對)
- 使用者是否確實在代理端完成了認證?
“trustedproxy_missing_header*”
必要的 header 不存在。檢查:
- 你的代理設定中是否包含這些特定 header
- Header 是否在傳遞鏈中被剝除
”trusted_proxy_user_not_allowed”
使用者已認證但不在 allowUsers 中。將他們加入,或移除白名單。
WebSocket 仍然失敗
確認你的代理:
- 支援 WebSocket 升級(
Upgrade: websocket、Connection: upgrade) - 在 WebSocket 升級請求(不只是 HTTP)中也傳遞身分 header
- 沒有為 WebSocket 連線設定不同的認證路徑
從 Token 認證遷移
如果你從 token 認證遷移到受信任代理:
- 設定你的代理來認證使用者並傳遞 header
- 獨立測試代理設定(用 curl 帶 header)
- 更新 OpenClaw 設定為受信任代理認證
- 重新啟動 Gateway
- 從 Control UI 測試 WebSocket 連線
- 執行
openclaw security audit並檢視發現項目