跳转至

可信代理身份验证

Warning

安全敏感功能。 此模式将身份验证完全委托给你的反向代理。配置错误可能导致你的 Gateway 暴露给未授权访问。启用前请仔细阅读本页。

何时使用

  • 你在 身份感知代理(Pomerium、Caddy + OAuth、nginx + oauth2-proxy、Traefik + forward auth)后面运行 OpenClaw。
  • 你的代理处理所有身份验证,并通过请求头传递用户身份。
  • 你处于 Kubernetes 或容器环境中,代理是访问 Gateway 的唯一路径。
  • 你遇到 WebSocket 1008 unauthorized 错误,因为浏览器无法在 WS 负载中传递令牌。

何时不要使用

  • 你的代理不验证用户(只是 TLS 终结器或负载均衡器)。
  • 存在任何绕过代理访问 Gateway 的路径(防火墙漏洞、内部网络访问)。
  • 你不确定你的代理是否正确剥离/覆盖转发请求头。
  • 你只需要个人单用户访问(请考虑改用 Tailscale Serve + 回环)。

工作原理

1. 代理验证用户

你的反向代理验证用户(OAuth、OIDC、SAML 等)。

2. 代理添加身份请求头

代理添加一个包含已验证用户身份的请求头(例如 x-forwarded-user: nick@example.com)。

3. Gateway 验证可信来源

OpenClaw 检查请求是否来自 可信代理 IP(gateway.trustedProxies)。回环来源需要显式 allowLoopback 许可;其他 Gateway 本地接口地址会被拒绝。

4. Gateway 提取身份

OpenClaw 读取必需的请求头,然后从配置的请求头中读取用户身份。

5. 授权

如果一切检查通过,并且用户通过 allowUsers(如果已设置),则请求被授权。

配置

{
  gateway: {
    // Trusted-proxy auth expects the proxy's source IP to be non-loopback by default
    bind: "lan",

    // CRITICAL: Only add your proxy's IP(s) here
    trustedProxies: ["10.0.0.1", "172.17.0.1"],

    auth: {
      mode: "trusted-proxy",
      identityScopes: {
        "admin@company.org": ["operator.admin"],
      },
      trustedProxy: {
        // Header containing authenticated user identity (required)
        userHeader: "x-forwarded-user",

        // Optional: headers that MUST be present (proxy verification)
        requiredHeaders: ["x-forwarded-proto", "x-forwarded-host"],

        // Optional: restrict to specific users (empty = allow all)
        allowUsers: ["nick@example.com", "admin@company.org"],

        // Optional: allow a same-host loopback proxy after explicit opt-in
        allowLoopback: false,

        // Optional: let authenticated proxy users enroll UI devices and upgrade scopes
        deviceAutoApprove: {
          enabled: false,
          scopes: ["operator.read", "operator.write", "operator.approvals", "operator.questions"],
        },
      },
    },
  },
}

Warning

运行时规则,按评估顺序

  1. 代理形态的流量在 Gateway 身份验证之前进行归属。请求的源 IP 必须匹配 gateway.trustedProxies(支持 CIDR),并且其客户端地址请求头必须解析为非回环客户端。否则,Gateway 身份验证路由会在接受身份请求头之前以 proxy_attribution_required 拒绝它。插件身份验证的 Webhook 路由可能仍会处理该请求,但它们会忽略不可信的转发地址,并使用套接字来源进行自身的限制。
  2. 代理必须用安全链覆盖 X-Forwarded-For。如果 gateway.allowRealIpFallback = true,当 X-Forwarded-For 不存在时,也会接受被覆盖的 X-Real-IP。除非代理移除客户端提供的 X-Real-IP,否则不要启用该回退。
  3. 回环源请求(127.0.0.1、::1)会被拒绝,除非 gateway.auth.trustedProxy.allowLoopback = true 并且回环地址也在 trustedProxies 中(trusted_proxy_loopback_source)。此检查在请求头检查之前运行,因此即使必需的请求头也缺失,回环源也会以这种方式失败。
  4. 匹配 Gateway 主机自身本地网络接口地址之一的非回环来源会作为防欺骗保护被拒绝(trusted_proxy_local_interface_source)。如果接口发现本身失败,请求也会被拒绝(trusted_proxy_local_interface_check_failed)。
  5. requiredHeaders 和 userHeader 必须存在且非空白。
  6. 如果 allowUsers 非空,则必须包含提取出的用户。

转发请求头证据会覆盖本地直连回退中的回环本地性。 如果请求通过回环到达,但携带 Forwarded、任何 X-Forwarded-* 或 X-Real-IP 请求头,则该证据会使其不符合本地直连密码回退和设备身份门控,尽管它仍会因回环来源而失败可信代理身份验证。

allowLoopback 对 Gateway 主机上的本地进程的信任程度与反向代理相同。仅当 Gateway 仍被防火墙阻止直接远程访问,并且本地代理剥离或覆盖客户端提供的身份请求头时,才启用它。

不经过反向代理的内部 Gateway 客户端应使用 gateway.auth.password / OPENCLAW_GATEWAY_PASSWORD,而不是可信代理身份请求头。当未提供 --url 覆盖时,openclaw gateway status 会自动选择此本地密码,包括使用 --json 时。对于浏览器访问,省略 gateway.controlUi.allowedOrigins 以使用 gateway.publicOrigin 作为默认值,或配置一个显式列表来覆盖它。

更新和重启健康检查在没有配置共享凭据时,也可以重用本地 CLI 的现有配对设备凭据。这些检查读取现有身份和令牌状态,而不会创建身份或保存替换凭据。

配置参考

gateway.trustedProxies string[] (路径) 必填
要信任的代理 IP 地址(或 CIDR)数组。来自其他 IP 的请求会被拒绝。 IPv4 范围可以按原样书写(10.0.0.0/8),也可以以 IPv4 映射 IPv6 形式书写(::ffff:10.0.0.0/104);两者等价,并且都匹配以 10.1.2.3 或 ::ffff:10.1.2.3 连接的对等方。映射前缀计算前 96 个映射位,因此 ::ffff:0:0/96 表示整个 IPv4 —— 包括回环,回环仍需要 gateway.auth.trustedProxy.allowLoopback。原生 IPv6 对等方永远不会匹配映射范围。
gateway.auth.mode string (路径) 必填
必须为 "trusted-proxy"。

授予已验证 trusted-proxy 或 Tailscale 身份的仅限连接的 operator 范围。电子邮件键不区分大小写匹配;未知的范围名称会导致配置验证失败。

gateway.auth.trustedProxy.userHeader string (路径) 必填
包含已认证用户身份的请求头名称。
gateway.auth.trustedProxy.requiredHeaders string[] (路径)
请求要被信任时必须存在的其他请求头。
gateway.auth.trustedProxy.allowUsers string[] (路径)
用户身份允许列表。为空表示允许所有已认证用户。
gateway.auth.trustedProxy.allowLoopback boolean (路径) 默认值: false
选择启用对同主机回环反向代理的支持。
gateway.auth.trustedProxy.deviceAutoApprove.enabled boolean (路径) 默认值: false
在 trusted-proxy 认证后,自动批准新的浏览器和原生 UI operator 设备以及同密钥范围升级。
gateway.auth.trustedProxy.deviceAutoApprove.scopes string[] (路径) 默认值: ["operator.read", "operator.write", "operator.approvals", "operator.questions"]
授予自动批准的 operator 设备的最大范围。显式列出 operator.admin 会让每个通过代理认证的用户都能请求自动获得完整管理员设备授权,使无范围请求自动获得完整管理员权限,并触发 CRITICAL gateway.trusted_proxy_device_auto_approve_admin 安全审计发现以及 Gateway 启动警告。

Warning

任何能够连接到 Gateway 的本地进程都可以通过发送身份请求头来冒充回环反向代理。仅当反向代理是接收用户流量的唯一本地监听器、直接访问 Gateway 已被锁定,并且你信任本地进程时,才启用 allowLoopback。代理必须认证用户,并删除或覆盖客户端提供的身份请求头;仅凭必需请求头无法将代理与另一个本地进程区分开来。

使用向导配置

运行 openclaw configure --section gateway,然后选择 Trusted Proxy。输入在 Gateway 运行时规则下匹配回环源地址的地址或 CIDR 时,会显示上述安全警告,并询问是否允许回环认证。这包括包含回环的地址范围,即使其基础地址不是回环地址。对于新配置,默认值为 否。选择 是 会保存 gateway.auth.trustedProxy.allowLoopback: true;选择 否 会保持其未设置,并警告回环代理请求将因 trusted_proxy_loopback_source 而失败,同时提供返回此页面的链接。

重新配置现有 trusted-proxy 设置时,提示默认使用现有的 allowLoopback 选择项。选择 否 会撤销该选择。如果输入的任何地址或范围都不匹配回环源地址,向导会保持现有值不变。同模式重新配置还会原样保留 deviceAutoApprove;此提示不会更改设备注册策略。从其他认证模式切换不会恢复处于休眠状态的 trusted-proxy 选择项。

启用实时配置重载后,对 gateway.trustedProxies、gateway.allowRealIpFallback、gateway.auth.allowTailscale、gateway.auth.identityScopes 和 gateway.auth.trustedProxy 的更改无需重启 Gateway 即可生效。传输策略更改要求客户端重新连接,同时保留访问授权未变化的已接受运行和排队输入。这包括代理请求头、OIDC 映射、设备自动批准以及可信代理地址。从 allowUsers 中移除已连接身份、禁用其认证方法,或更改其自身的身份范围授权,仍会撤销已接受的工作。恢复授权不会恢复已撤销的工作。针对其他身份的身份范围编辑不会更改现有连接和工作;没有已验证 operator 身份的客户端也会忽略这些编辑。HTTP 请求和插件认证 Cookie 不使用身份范围授权,也不受这些范围编辑影响。配置写入方会在其连接关闭前收到其已接受的结果。待处理握手和 HTTP 请求会在异步等待后重新检查适用于其权限的策略。

按身份范围授权

使用 gateway.auth.identityScopes 为选定的已验证用户授予额外的 operator 范围,而不扩大其持久设备授权:

{
  gateway: {
    auth: {
      mode: "trusted-proxy",
      identityScopes: {
        "admin@example.com": ["operator.admin"],
        "operator@example.com": ["operator.read", "operator.write"],
      },
      trustedProxy: {
        userHeader: "x-forwarded-user",
      },
    },
  },
}

映射键是已验证的 trusted-proxy 身份或 Tailscale WhoIs 登录名。电子邮件匹配不区分大小写;非电子邮件身份必须完全匹配。每次连接时,OpenClaw 会将匹配的身份范围添加到设备已授权范围中,然后应用显式的 x-openclaw-scopes 连接上限。

这些授权仅限会话。它们不会创建或更新设备配对记录,也不会触发设备范围升级请求。Token、密码和无认证连接不携带已验证身份,也永远不会获得授权。

自动设备批准

Trusted-proxy 认证可以选择将代理身份用作新浏览器和原生 UI operator 设备以及同密钥范围升级的批准边界:

{
  gateway: {
    auth: {
      mode: "trusted-proxy",
      trustedProxy: {
        userHeader: "x-forwarded-user",
        allowUsers: ["operator@example.com"],
        deviceAutoApprove: {
          enabled: true,
          scopes: ["operator.read", "operator.write", "operator.approvals", "operator.questions"],
        },
      },
    },
  },
}

默认值为 enabled: false。启用后,以下所有规则均适用:

  1. WebSocket 必须通过 trusted-proxy 方法完成认证,并且当配置了允许列表时,其非空用户身份必须通过 allowUsers。Token、密码、Tailscale 和未认证连接永远不会使用此策略。
  2. 新的浏览器 operator 设备(包括 Control UI 和 WebChat)、处于 UI 模式的原生 macOS、Linux、iOS 和 Android 客户端,以及来自具有相同配对公钥的现有设备的范围升级会自动解决。原生客户端必须提供已签名的设备身份,并在每次连接时通过代理进行认证。Node 角色连接、角色升级以及对固定平台或设备系列元数据的更改不符合此自动批准策略。如果现有授权已覆盖可自动批准的范围,则会话会缩小到该授权,而不产生配对请求或审计条目;否则,deviceAutoApprove.scopes 可以自动批准扩大后的交集。声称使用现有设备 ID 但公钥不同的连接会在创建配对请求之前被拒绝。
  3. 设备以 operator 角色获得批准。如果显式指定了 deviceAutoApprove.scopes 列表,则请求的范围会与列表求交集;省略范围的请求会收到该列表。当列表未设置时,默认值为 operator.read、operator.write、operator.approvals 和 operator.questions。在使用此默认列表进行自动批准期间,即使旧版 UI 客户端未请求,OpenClaw 也会添加 operator.questions。显式范围列表永远不会被扩大。随后,如果存在连接中的 x-openclaw-scopes 代理请求头,则生成的授权还会受到其上限限制,因此缩小用户范围的代理也会限制 持久 设备授权,而不仅仅是会话——存在但为空的请求头不会授予任何范围。即使客户端省略其自身的范围列表,此上限也适用。
  4. operator.admin 只能通过显式列在 deviceAutoApprove.scopes 中才允许。当列出时,每个通过代理认证的用户都可以在新的 operator 设备上请求并自动获得完整管理员权限;无范围的请求会自动获得完整管理员权限。openclaw security audit 会报告 CRITICAL gateway.trusted_proxy_device_auto_approve_admin 发现,并且 Gateway 会在启动时记录一次警告。当选定的已验证用户需要会话管理员权限而不需要持久管理员设备授权时,优先使用有针对性的 identityScopes 管理员授权。

Warning

启用此选项会将新的浏览器和原生 UI 操作员设备注册完全委托给反向代理身份。如果代理账户被攻破,则可以使用所有已配置的作用域注册一个持久化设备。列入 operator.admin 会使该设备无需人工审批即成为完全管理员。请仅通过代理访问 Gateway,要求强代理认证,覆盖身份请求头,并使用较窄的 allowUsers 列表。

Control UI 配对行为

浏览器会在每个源(包括纯 HTTP)上附加设备身份,因此首次连接遵循标准配对流程:当 deviceAutoApprove 启用时自动审批,否则在 Gateway 主机上进行一次性审批。当 gateway.auth.mode = "trusted-proxy" 处于激活状态且请求通过可信代理检查时,只有来自完全无法提供设备身份的浏览器的 Control UI 会话才会被允许以无设备方式接入。

作用域影响:

  • 无设备的 Control UI WebSocket 会话无法自行声明权限。OpenClaw 会将其请求的作用域列表清空为 [],然后在代理身份验证后应用任何匹配的服务器端 identityScopes 授权。
  • 如果在 WebSocket 连接成功后方法失败并提示 missing scope,请重新加载以让浏览器配对设备身份,或批准待处理的设备请求。参见 Control UI 不安全 HTTP。

反向代理作用域上限:如果你的代理在 Control UI WebSocket 升级请求上发送 x-openclaw-scopes,OpenClaw 会限制设备注册或升级请求,以及设备授权与身份授予的会话作用域的最终并集。此请求头不会授予作用域;它只会收窄权限。当 deviceAutoApprove.enabled 为 true 时,该上限也会限制由自动设备审批写入的持久化设备授权。

影响:

  • 配对不再是设备无 Control UI 访问的主要门槛。匹配的 identityScopes 条目可以在不创建配对记录的情况下授权该会话。当 deviceAutoApprove.enabled 为 true 时,代理身份也会成为新浏览器和原生 UI 操作员设备注册的审批门槛。
  • 你的反向代理认证策略和 allowUsers 成为有效的访问控制。
  • 保持 Gateway 入口仅锁定到受信任的代理 IP(gateway.trustedProxies + 防火墙)。

自定义 WebSocket 客户端不是 Control UI 会话。已废弃的 Control UI 升级输入不会授予任意 client.mode: "backend" 或 CLI 形态客户端临时访问权限。自定义自动化应使用设备身份/配对、保留的直连本地 client.id: "gateway-client" 后端辅助路径,或在 HTTP 请求/响应接口更合适时使用 admin HTTP RPC 插件。

操作员作用域请求头

可信代理认证是一种携带身份的 HTTP 模式,因此调用方可以选择在 HTTP API 请求上通过 x-openclaw-scopes 声明操作员作用域。

注意:WebSocket 作用域由 Gateway 协议握手和设备身份绑定决定。在 Control UI WebSocket 升级请求上,x-openclaw-scopes 仅作为协商会话作用域的上限,而非授权。参见 Control UI 配对行为。

示例:

  • x-openclaw-scopes: operator.read
  • x-openclaw-scopes: operator.read,operator.write
  • x-openclaw-scopes: operator.admin,operator.write

行为:

  • 当请求头存在时,OpenClaw 会遵循声明的作用域集。
  • 当请求头存在但为空时,请求声明无操作员作用域。
  • 当请求头不存在时,常规携带身份的 HTTP API 会回退到标准操作员默认作用域集(operator.admin、operator.read、operator.write、operator.approvals、operator.pairing、operator.talk.secrets)。
  • Gateway 认证插件 HTTP 路由默认更窄:当 x-openclaw-scopes 不存在时,其运行时作用域仅回退到 operator.write。
  • 即使可信代理认证成功,浏览器来源的 HTTP 请求仍必须通过 gateway.controlUi.allowedOrigins(或有意的 Host 头回退模式)。

实用规则:当你希望可信代理请求比默认作用域更窄,或当 gateway-auth 插件路由需要比 write 作用域更强的权限时,请显式发送 x-openclaw-scopes。

TLS 终止与 HSTS

使用一个 TLS 终止点,并在该处应用 HSTS。

当你的反向代理为 https://control.example.com 处理 HTTPS 时,请在代理上为该域设置 Strict-Transport-Security。

  • 非常适合面向互联网的部署。
  • 将证书与 HTTP 加固策略集中在同一处。
  • OpenClaw 可以继续在代理后面的回环 HTTP 上运行。

示例请求头值:

Strict-Transport-Security: max-age=31536000; includeSubDomains

如果 OpenClaw 自身直接提供 HTTPS(没有 TLS 终止代理),请设置:

{
  gateway: {
    tls: { enabled: true },
    http: {
      securityHeaders: {
        strictTransportSecurity: "max-age=31536000; includeSubDomains",
      },
    },
  },
}

strictTransportSecurity 接受字符串形式的请求头值,或 false 以显式禁用。

推出指南

  • 先使用较短的最大存活时间(例如 max-age=300)验证流量。
  • 只有在信心较高时才增加到长期值(例如 max-age=31536000)。
  • 仅当所有子域都已准备好 HTTPS 时才添加 includeSubDomains。
  • 只有在你确实满足整套域的 preload 要求时才使用 preload。
  • 仅回环的本地开发不会从 HSTS 中受益。

代理设置示例

Cloudflare Access 在 Cloudflare Tunnel 和 Access 中进行了端到端覆盖,包括隧道和节点路由。

Pomerium

Pomerium 通过 x-pomerium-claim-email(或其他声明头)传递身份,并通过 x-pomerium-jwt-assertion 传递 JWT。

{
  gateway: {
    bind: "lan",
    trustedProxies: ["10.0.0.1"], // Pomerium's 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: nick@example.com
    pass_identity_headers: true
使用 OAuth 的 Caddy

带有 caddy-security 插件的 Caddy 可以认证用户并传递身份头。

{
  gateway: {
    bind: "lan",
    trustedProxies: ["10.0.0.1"], // Caddy/sidecar proxy 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";
}
使用 forward auth 的 Traefik
{
  gateway: {
    bind: "lan",
    trustedProxies: ["172.17.0.1"], // Traefik container IP
    auth: {
      mode: "trusted-proxy",
      trustedProxy: {
        userHeader: "x-forwarded-user",
      },
    },
  },
}

混合 token 配置

Gateway 启动时会拒绝 trusted-proxy 认证,如果同时配置了共享 token(gateway.auth.token 或 OPENCLAW_GATEWAY_TOKEN)。两者互斥,因为共享 token 会让同主机调用方通过一条与代理验证身份完全不同的路径进行认证,而该模式本应强制执行代理验证身份。

如果启动时出现类似 gateway auth mode is trusted-proxy, but a shared token is also configured 的错误:

  • 使用 trusted-proxy 模式时,移除共享 token,或者
  • 如果你打算使用基于 token 的认证,请将 gateway.auth.mode 切换为 "token"。

回环 trusted-proxy 身份头仍然失败关闭:同主机调用方不会被静默认证为代理用户。绕过代理的内部 OpenClaw 调用方可以改用 gateway.auth.password / OPENCLAW_GATEWAY_PASSWORD 进行认证。在 trusted-proxy 模式下,token 回退仍被有意不支持。

将独立的 Gateway 限制为单一所有者

当某个所有者需要不同的信任边界时,请使用独立的 Gateway cell。在同一 OS 用户下的独立 workspace、模型选择器过滤器或 Gateway 进程,并不能将其凭据和状态与以该用户运行的其他 agent 隔离开来。

Fleet 管理的 cell 当前使用 token 认证。此 trusted-proxy 流程需要一个独立配置的 cell;不要覆盖 Fleet 的托管认证配置。

具备身份识别能力的代理必须在转发任何 HTTP 请求或 WebSocket 升级之前拒绝所有其他用户。将该策略绑定到一个经过验证的不可变身份,例如带颁发者限定的 OIDC subject,并用该身份覆盖 userHeader。将 allowUsers 设置为相同的单个值,作为第二重检查。Gateway 的 allowUsers 会精确比较修剪后的头值;它不会验证 JWT、解析账户 ID,也不会使电子邮件地址不可变。requiredHeaders 只检查头是否存在且非空。

仅让该代理能够访问 Gateway。不要仅依赖 allowUsers 来撤销访问:有效的配对设备或 bootstrap 凭据拥有自己的 WebSocket 认证路径。现有连接也需要显式撤销或断开。在代理处对所有路由(包括插件路由)强制执行所有者限制,并且不要创建未受保护的 node 路由。

对于仅代理 cell,请省略 Gateway token 和密码配置及其环境变量。当代理具有独立网络身份时,保持 allowLoopback: false。cell 内的 provider 凭据用于让工作负载向其 provider 认证;它不会认证使用 Gateway 的人类用户。主机管理员仍被视为可信。

安全检查清单

在启用 trusted-proxy 认证之前,请确认:

  • [ ] 代理是唯一路径:Gateway 端口除你的代理外,被防火墙隔离于所有其他来源。
  • [ ] trustedProxies 保持最小化:仅包含你实际的代理 IP,而不是整个子网。
  • [ ] 回环代理来源是有意为之:除非为同主机代理显式启用 gateway.auth.trustedProxy.allowLoopback,否则 trusted-proxy 认证对回环来源请求失败关闭。
  • [ ] 代理会剥离头:你的代理会覆盖(而不是追加)来自客户端的 x-forwarded-* 头。
  • [ ] 客户端 IP 可追溯:代理始终使用原始非回环客户端地址重建 X-Forwarded-For。
  • [ ] TLS 终止:你的代理处理 TLS;用户通过 HTTPS 连接。
  • [ ] 浏览器来源已配置:非回环 Control UI 使用 gateway.publicOrigin,并省略 gateway.controlUi.allowedOrigins,或使用显式允许列表。
  • [ ] 已设置 allowUsers(推荐):限制为已知用户,而不是允许任何已认证用户。
  • [ ] 没有混合 token 配置:不要同时设置 gateway.auth.token 和 gateway.auth.mode: "trusted-proxy"。
  • [ ] 本地密码回退是私有的:如果你为内部直连调用方配置了 gateway.auth.password,请保持 Gateway 端口被防火墙保护,使非代理的远程客户端无法直接访问。
  • [ ] 设备自动批准是有意为之:如果 deviceAutoApprove.enabled 为 true,请将反向代理账户安全视为设备注册边界,并保持授予的 scope 列表为非管理员且最小化。

安全审计

openclaw security audit 会将 trusted-proxy 身份验证标记为 严重 级别发现。这是有意为之;它提醒你将安全委托给了你的代理配置。

审计检查以下内容:

  • 基础 gateway.trusted_proxy_auth 警告/严重提醒。
  • 缺少 trustedProxies 配置。
  • 缺少 userHeader 配置。
  • 空的 allowUsers(允许任何已认证用户)。
  • 为同一主机代理源启用了 allowLoopback。
  • 启用了操作员设备自动批准(将新的浏览器和原生 UI 设备配对委托给代理身份)。

独立的、非 trusted-proxy 专属的发现也会在 Control UI 暴露时适用:通配符或缺失的 gateway.controlUi.allowedOrigins,以及 Host 头来源回退。

故障排除

Control UI 提示需要代理身份验证

Gateway 可访问,但它拒绝了代理身份验证或转发的身份。对于 AUTH_IDENTITY_HEADER_REQUIRED,所需的代理头缺失或为空;这不是网络中断。

打开已配置的已认证代理或 SSO 仪表板 URL,并在那里登录,而不是直接访问 Gateway 的环回 URL。如果错误仍然存在,请要求 Gateway 管理员验证 WebSocket 升级请求 上的身份和必需头转发,并确认已登录的账户被允许。

Gateway token 不能替代代理身份验证。不要从浏览器发送身份头,不要扩大 trustedProxies,也不要移除 allowUsers 来绕过拒绝。

trusted_proxy_untrusted_source

请求并非来自 gateway.trustedProxies 中的 IP。请检查:

  • 代理 IP 是否正确?(Docker 容器 IP 可能会变化。)
  • 你的代理前面是否有负载均衡器?
  • 使用 docker inspect 或 kubectl get pods -o wide 查找实际 IP。
trusted_proxy_loopback_source

OpenClaw 拒绝了来自环回源的 trusted-proxy 请求。

请检查:

  • 代理是否从 127.0.0.1 / ::1 连接?
  • 你是否试图在同一主机环回反向代理上使用 trusted-proxy 身份验证?

修复:

  • 对于不经过代理的内部同一主机客户端,使用显式配置的本地密码;trusted-proxy 模式下不支持 token 回退,或
  • 通过非环回 trusted proxy 地址路由,并将该 IP 保留在 gateway.trustedProxies 中,或
  • 对于有意设置的同一主机反向代理,设置 gateway.auth.trustedProxy.allowLoopback = true,将环回地址保留在 gateway.trustedProxies 中,并确保代理剥离或覆盖身份头。
trusted_proxy_local_interface_source / trusted_proxy_local_interface_check_failed

请求的源 IP 匹配了 Gateway 主机自身的某个非环回网络接口地址(不是代理),这是针对 tailnet 或 Docker 桥接网络上伪造的同一主机流量的防护。..._check_failed 表示接口发现本身出错,因此 OpenClaw 会失败关闭。

请检查:

  • 是否有 Gateway 主机上的进程直接发送身份头,绕过代理?
  • 代理是否与 Gateway 运行在同一网络命名空间中,并且其 IP 也显示为本地接口?

修复:将代理流量路由到一个未被 Gateway 主机本地绑定的地址,或者仅对真正的同一主机代理设置使用 allowLoopback。

trusted_proxy_user_missing

用户头为空或缺失。请检查:

  • 你的代理是否配置为传递身份头?
  • 头名称是否正确?(不区分大小写,但拼写很重要)
  • 用户是否确实在代理处已认证?
trusted_proxy_missing_header_*

必需的请求头不存在。请检查:

  • 你的代理配置中针对这些特定头的设置。
  • 这些头是否在某处被剥离。
trusted_proxy_user_not_allowed

用户已认证,但不在 allowUsers 中。请使用被允许的账户登录,或要求 Gateway 管理员审查预期的访问策略。不要移除允许列表作为连接性变通方案。

trusted_proxy_no_proxies_configured / trusted_proxy_config_missing

gateway.auth.mode 为 "trusted-proxy",但 gateway.trustedProxies 为空,或者 gateway.auth.trustedProxy 本身缺失。在两者都设置之前,所有请求都会被拒绝。

trusted_proxy_origin_not_allowed

Trusted-proxy 身份验证成功,但浏览器 Origin 头未通过 Control UI 来源检查。

请检查:

  • gateway.controlUi.allowedOrigins 包含确切的浏览器来源。
  • 除非你有意想要允许所有行为,否则不要依赖通配符来源。
  • 如果你有意使用 Host 头回退模式,则 gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true 是有意设置的。
连接成功但方法报告缺少范围

WebSocket 连接成功,但 chat.history、sessions.list 或 models.list 失败,并报告 missing scope: operator.read。

常见原因:

  • 无设备的 Control UI 会话:OpenClaw 按设计清除自声明的范围,并且未配置匹配的 gateway.auth.identityScopes 授权。
  • 自定义后端客户端:已弃用的 Control UI 升级输入永远不会授予任意后端或 CLI 形状的 WebSocket 客户端访问权限。
  • 过于狭窄的 x-openclaw-scopes:如果你的代理在 Control UI WebSocket 升级请求上注入此头,则会话范围会被限制为该集合。空头值将导致没有范围。

修复:

  • 对于 Control UI,重新加载仪表板,以便浏览器生成设备身份并完成配对(通过 HTTP 也可工作)。
  • 对于自定义自动化,使用设备身份/配对、保留的直连本地 gateway-client 后端辅助路径,或 admin HTTP RPC。
  • 不要将已弃用的 gateway.controlUi.dangerouslyDisableDeviceAuth 键添加到当前配置;它会被忽略,并且 openclaw doctor --fix 会移除它。
WebSocket 仍然失败

请确保你的代理:

  • 支持 WebSocket 升级(Upgrade: websocket、Connection: upgrade)。
  • 在 WebSocket 升级请求上传递身份标头(不仅仅是 HTTP)。
  • 没有为 WebSocket 连接设置单独的身份验证路径。

从令牌身份验证迁移

1. 配置代理

配置代理以验证用户身份并传递标头。

2. 独立测试代理

独立测试代理配置(使用带标头的 curl)。

3. 更新 OpenClaw 配置

使用可信代理身份验证更新 OpenClaw 配置。

4. 重启 Gateway

重启 Gateway。

5. 测试 WebSocket

从 Control UI 测试 WebSocket 连接。

6. 审计

运行 openclaw security audit 并查看结果。

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 cl/openclaw