0

ch-11

约 15000 字DraftOpenClaw Book

第 11 章 · 安全与生产部署

OpenClaw 的 Agent 能执行 Shell 命令、读写文件、访问网络——这意味着"把 AI 接入消息通道"这件事本身就有攻击面。本章教你的不是"让它绝对安全"(这不可能),而是"让它在你理解的风险边界内可控运行"。

本章你将学到:

  • 理解 OpenClaw 的信任模型和安全哲学
  • 掌握沙盒、工具策略、凭据管理的完整配置
  • 能独立完成从本地开发到 VPS/容器化生产部署的全流程
  • 建立持续安全审计的运维习惯

11.1 先理解信任模型:个人助手,不是多租户平台

OpenClaw 的安全设计基于一个核心假设:一个 Gateway = 一个信任边界

┌─────────────────────────────────────────────────┐
│                信任边界                            │
│                                                   │
│  ┌─────────┐    ┌─────────┐    ┌─────────┐       │
│  │ 用户 A  │    │ 用户 B  │    │ 用户 C  │       │
│  └────┬────┘    └────┬────┘    └────┬────┘       │
│       │              │              │             │
│       ▼              ▼              ▼             │
│  ┌──────────────────────────────────────────┐     │
│  │         同一个 Gateway / Agent            │     │
│  │    (共享同一个工具权限和会话空间)          │     │
│  └──────────────────────────────────────────┘     │
│                                                   │
│  ⚠️ 如果 A、B、C 互不信任 → 这不是推荐用法        │
└─────────────────────────────────────────────────┘

这个模型意味着:

  • 一个 Gateway 里的所有用户共享同一个 Agent 权限。如果 A 能让 Agent 执行 exec,B 和 C 也能。
  • 会话隔离是隐私边界,不是权限边界。DM 隔离能防止 A 看到 B 的对话,但不能防止 B 利用 Agent 做事。
  • 如果用户之间可能互相对抗,必须拆分 Gateway(不同机器/不同 OS 用户/不同 VPS)。

⚠️ 安全警告

OpenClaw 不是多租户安全隔离平台。不要在一个共享 Gateway 上运行互不信任的用户。这不是 bug,这是设计假设。

11.1.1 安全的核心理念:先控制访问,再依赖智能

OpenClaw 的安全哲学可以浓缩为一句话:假设模型可以被操纵,让操纵的代价尽可能高

安全防御层次(从外到内):

第一层:身份控制 — 谁能和 Agent 对话?
  ├── DM 配对(pairing)/ 白名单(allowlist)
  └── 群聊 @提及 / 回复激活

第二层:工具策略 — Agent 能做什么?
  ├── 工具配置文件(profile)
  ├── 允许/拒绝列表(allow/deny)
  └── 工具组简写(group:*)

第三层:执行沙盒 — 在哪里做?
  ├── Docker 容器
  ├── SSH 远程主机
  └── OpenShell 托管沙盒

第四层:凭据管理 — 密钥怎么存?
  ├── SecretRef(env/file/exec)
  ├── 活跃表面过滤
  └── 运行时快照 + 原子替换

第五层:模型选择 — 用什么模型?
  └── 越强的模型,抗注入能力越好

大多数安全事件不是"炫酷的 0day 利用",而是"有人给 Bot 发了条消息,Bot 就照做了"。所以真正的防线是:最小权限 + 分层防御

11.2 安全审计:openclaw security audit

OpenClaw 内置了一个安全审计工具,能在几秒内扫描你的配置并报告常见的安全问题。

11.2.1 运行审计

# 基础审计(检查配置文件)
openclaw security audit

# 深度审计(还会尝试连接运行中的 Gateway 做实时探测)
openclaw security audit --deep

# 自动修复可修复的问题(如文件权限)
openclaw security audit --fix

# JSON 格式输出(适合 CI/CD 集成)
openclaw security audit --json

11.2.2 审计检查什么

审计工具会按优先级检查以下内容:

严重级别 检查项 典型发现
critical 网络暴露 Gateway 绑定 LAN 但没有认证
critical 文件权限 ~/.openclaw 目录对其他用户可写
critical 工具暴露 公开群聊 + exec 工具 + 无沙盒
critical Tailscale Funnel 开启了公共互联网暴露
critical Control UI 非回环部署但没有配置 allowedOrigins
warn Exec 审批漂移 security: "full" 绕过了命令审批
warn 插件 加载了未明确白名单的扩展
warn 模型选择 小模型 + 不安全的工具表面
warn 日志脱敏 redactSensitive: "off"

11.2.3 60 秒加固基线

这是一个"先锁死,再按需开放"的安全配置模板。把它作为生产部署的起点:

{
  gateway: {
    mode: "local",
    bind: "loopback",
    auth: { mode: "token", token: "替换为长随机字符串" },
  },
  session: {
    dmScope: "per-channel-peer",  // 多用户 DM 隔离
  },
  tools: {
    profile: "messaging",
    deny: [
      "group:automation",  // 禁止 cron/gateway
      "group:runtime",     // 禁止 exec/bash/process
      "group:fs",          // 禁止文件读写
      "sessions_spawn",
      "sessions_send",
    ],
    fs: { workspaceOnly: true },
    exec: { security: "deny", ask: "always" },
    elevated: { enabled: false },
  },
  channels: {
    whatsapp: {
      dmPolicy: "pairing",
      groups: { "*": { requireMention: true } },
    },
  },
}

这个配置做了以下事情:

  • Gateway 只监听本地回环地址,必须用 token 认证
  • 每个 DM 对话独立隔离
  • 默认只给消息类工具(messaging profile)
  • 禁止所有运行时工具、文件工具、自动化工具
  • WhatsApp 需要配对才能 DM,群聊需要 @提及

💡 提示:从这个基线开始,根据你的实际需求逐个开放工具,而不是反过来。每次开放一个工具后,重新跑一次 openclaw security audit 看看有什么新发现。

11.3 沙盒:让工具在隔离环境中执行

沙盒是 OpenClaw 最强的执行隔离机制。启用后,Agent 的 Shell 命令和文件操作都在容器里运行,而不是在宿主机上。

11.3.1 三种模式:何时启用沙盒

{
  agents: {
    defaults: {
      sandbox: {
        mode: "off",       // 完全关闭(默认)
        // mode: "non-main",  // 只对非主会话启用沙盒
        // mode: "all",       // 所有会话都启用沙盒
      },
    },
  },
}
模式 行为 适用场景
off 所有工具在宿主机运行 本地开发、单用户
non-main 主会话在宿主机,群聊/其他会话在沙盒 "我自己 DM 信任,陌生人群聊不信任"
all 所有会话都在沙盒 生产环境、多用户

⚠️ 踩坑记录

问题:设置了 non-main 模式,但在 Discord 群聊里 Agent 还是说"工具被沙盒策略阻止"。

原因non-main 是基于 session.mainKey 判断的,群聊和频道会话有自己的 key,不是"main"。

解决:如果群聊也需要在宿主机运行,要么改 mode: "off",要么在群聊里使用 elevated 逃逸。

11.3.2 三种后端:沙盒在哪里运行

{
  agents: {
    defaults: {
      sandbox: {
        backend: "docker",  // 本地 Docker 容器(默认)
        // backend: "ssh",    // 任意 SSH 可达的远程主机
        // backend: "openshell", // OpenShell 托管的远程沙盒
      },
    },
  },
}
后端 运行位置 适用场景
Docker 本地容器 本地开发、完全隔离
SSH 任意远程主机 将工具执行卸载到专用机器
OpenShell 托管远程沙盒 需要双向同步的远程环境

Docker 后端(最常用)

Docker 是默认后端。先构建沙盒镜像:

# 基础镜像(最小化,不含 Node)
./scripts/sandbox-setup.sh

# 增强镜像(含 curl、jq、node、python3、git)
./scripts/sandbox-common-setup.sh
{
  agents: {
    defaults: {
      sandbox: {
        mode: "non-main",
        backend: "docker",
        scope: "session",         // 每个会话一个容器
        workspaceAccess: "none",  // 沙盒看不到工作空间
        docker: {
          network: "none",        // 无网络访问(默认)
          image: "openclaw-sandbox:bookworm-slim",
        },
      },
    },
  },
}

安全默认值

  • 容器默认无网络network: "none"
  • network: "host" 被阻止
  • network: "container:<id>" 默认被阻止(命名空间逃逸风险)
  • 危险 bind 源(docker.sock/etc/proc/sys)被自动阻止

SSH 后端

SSH 后端让工具在任意远程主机上执行:

{
  agents: {
    defaults: {
      sandbox: {
        mode: "all",
        backend: "ssh",
        scope: "session",
        workspaceAccess: "rw",
        ssh: {
          target: "user@sandbox-host:22",
          workspaceRoot: "/tmp/openclaw-sandboxes",
          identityFile: "~/.ssh/id_ed25519",
          strictHostKeyChecking: true,
        },
      },
    },
  },
}

SSH 后端的工作方式:

  1. 首次使用时,OpenClaw 把本地工作空间种子同步到远程主机
  2. 之后所有 execreadwrite 操作直接在远程主机上执行
  3. 远程变更是不会自动同步回本地的(远程规范化模型)

⚠️ 踩坑记录

问题:在本地编辑了文件,但沙盒里的 Agent 看不到更新。

原因:SSH 后端只在首次创建时种子同步一次。之后的本地修改不会自动反映到远程。

解决:运行 openclaw sandbox recreate 删除远程工作空间并重新种子同步。或者改用 OpenShell 的 mirror 模式。

OpenShell 后端

OpenShell 是一个更高级的远程沙盒,支持两种工作空间模式:

{
  plugins: {
    entries: {
      openshell: {
        enabled: true,
        config: {
          mode: "mirror",  // 或 "remote"
          remoteWorkspaceDir: "/sandbox",
        },
      },
    },
  },
}
  • mirror:本地是权威来源。每次 exec 前同步到远程,执行后同步回来。
  • remote:远程是权威来源。首次种子同步后不再同步。

选择原则:把沙盒当"临时执行环境"用 mirror,把沙盒当"真正的工作空间"用 remote

11.3.3 工作空间访问控制

沙盒的工作空间访问通过 workspaceAccess 控制:

行为 风险
none 沙盒只能看到自己的临时空间 最低
ro 工作空间以只读方式挂载到 /agent
rw 工作空间以读写方式挂载到 /workspace

11.3.4 自定义 Bind Mount

如果沙盒需要访问宿主机上的特定目录,可以用 bind mount:

{
  agents: {
    defaults: {
      sandbox: {
        docker: {
          binds: [
            "/home/user/source:/source:ro",    // 只读挂载源码
            "/var/data/myapp:/data:ro",       // 只读挂载数据
          ],
        },
      },
    },
  },
}

安全要点

  • bind mount 穿透沙盒文件系统——挂载什么就能看到什么
  • 省略 :ro 就是读写,务必显式标注
  • 永远不要 bind docker.sock(除非你完全知道后果)
  • scope: "shared" 时,per-agent 的 bind 会被忽略

11.3.5 setupCommand:容器初始化

setupCommand 在容器首次创建后执行一次(不是每次运行):

{
  agents: {
    defaults: {
      sandbox: {
        docker: {
          setupCommand: "apt-get update && apt-get install -y python3 nodejs",
          network: "bridge",  // 需要网络才能安装包
        },
      },
    },
  },
}

⚠️ 踩坑记录

问题setupCommand 执行失败,报网络不可达。

原因:默认 network: "none",容器没有网络出口。

解决:安装包时需要设置 network: "bridge"。安装完成后可以改回 "none"。但注意,改网络设置需要 recreate 沙盒。

11.3.6 沙盒浏览器

OpenClaw 还支持在独立容器中运行沙盒浏览器:

{
  agents: {
    defaults: {
      sandbox: {
        browser: {
          autoStart: true,
          network: "openclaw-sandbox-browser",  // 专用 Docker 网络
          allowHostControl: false,               // 不允许控制宿主机浏览器
        },
      },
    },
  },
}
# 构建浏览器沙盒镜像
./scripts/sandbox-browser-setup.sh

11.4 工具策略:三层控制

OpenClaw 有三个相关但不同的控制层,理解它们的关系是调试"为什么这个工具被阻止"的关键。

11.4.1 三层控制模型

┌──────────────────────────────────────────────────┐
│  第一层:工具策略(Tool Policy)                    │
│  决定"哪些工具可用"                                │
│  ├── tools.profile(基础白名单)                   │
│  ├── tools.allow / tools.deny(全局增减)          │
│  └── tools.sandbox.tools.*(沙盒内额外策略)       │
├──────────────────────────────────────────────────┤
│  第二层:沙盒(Sandbox)                           │
│  决定"工具在哪里运行"                              │
│  └── agents.defaults.sandbox.mode                 │
├──────────────────────────────────────────────────┤
│  第三层:提权执行(Elevated)                      │
│  exec 的"逃逸通道"                                │
│  └── tools.elevated(仅影响 exec,在宿主机运行)    │
└──────────────────────────────────────────────────┘

关键规则

  1. deny 永远赢。如果工具在 deny 列表里,沙盒和提权都救不回来。
  2. 如果 allow 非空,其他所有工具都视为被阻止。
  3. /exec 指令只调整会话默认值,不授予工具访问权。
  4. 提权只影响 exec,不授予新工具。

11.4.2 工具组简写

工具策略支持 group:* 简写,一次控制多个工具:

{
  tools: {
    deny: [
      "group:runtime",   // exec, bash, process
      "group:fs",        // read, write, edit, apply_patch
      "group:sessions",  // sessions_list, sessions_history, sessions_send, sessions_spawn
      "group:memory",    // memory_search, memory_get
      "group:ui",        // browser, canvas
      "group:automation", // cron, gateway
      "group:messaging", // message
      "group:nodes",     // nodes
      "group:openclaw",  // 所有内置 OpenClaw 工具
    ],
  },
}

11.4.3 沙盒内工具策略

当会话在沙盒中运行时,可以额外限制沙盒内可用的工具:

{
  tools: {
    sandbox: {
      tools: {
        allow: ["group:runtime", "group:fs", "group:memory"],
        // deny: ["*image*"],  // 永远不剪裁包含图片的工具结果
      },
    },
  },
}

11.4.4 提权执行(Elevated)

提权是 exec 的"宿主机逃逸通道"——当你在沙盒中但需要在宿主机执行命令时:

/elevated on       # 启用提权(exec 在宿主机运行)
/elevated full     # 启用提权并跳过 exec 审批

提权配置:

{
  tools: {
    elevated: {
      enabled: true,
      allowFrom: {
        telegram: ["123456789"],           // 只允许特定用户提权
        discord: ["987654321012345678"],
      },
    },
  },
}

⚠️ 踩坑记录

问题:用户 A 在群聊里用 /elevated on 成功提权了。

原因allowFrom 没有配置,默认所有授权发送者都能提权。

解决:设置 allowFrom 限制哪些用户可以使用提权。或者设置 enabled: false 彻底关闭。

11.4.5 调试"为什么工具被阻止"

sandbox explain 快速诊断:

openclaw sandbox explain
openclaw sandbox explain --session agent:main:main
openclaw sandbox explain --agent work
openclaw sandbox explain --json

输出包括:

  • 有效的沙盒模式/范围/工作空间访问
  • 当前会话是否在沙盒中
  • 有效的工具 allow/deny(以及来源:全局/Agent/默认)
  • 提权门控状态和修复路径

11.5 凭据管理:SecretRef 体系

把 API Key 写在配置文件里是最简单的方式,但也是最不安全的。OpenClaw 提供了一套完整的凭据管理系统——SecretRef。

11.5.1 SecretRef 合约

每个 SecretRef 都是一个统一的对象:

{ source: "env" | "file" | "exec", provider: "default", id: "..." }

三种来源:

来源 格式 示例 适用场景
env 环境变量 { source: "env", id: "OPENAI_API_KEY" } 最简单,适合 Docker/CI
file 本地文件 { source: "file", id: "/providers/openai/apiKey" } 本地持久化
exec 外部命令 { source: "exec", provider: "vault", id: "providers/openai/apiKey" } 集成 1Password/Vault

11.5.2 运行时模型:内存快照 + 原子替换

SecretRef 不是"用时读取"(lazy),而是"启动时读取"(eager):

启动 / 重载
    │
    ▼
从所有 Provider 读取所有 SecretRef
    │
    ▼
组装成内存快照(Runtime Snapshot)
    │
    ├── 成功 → 原子替换旧快照
    │
    └── 失败 → 保留上次已知的好快照(last-known-good)

这个设计的好处:

  • 密钥提供者宕机不会影响热路径——运行时只读内存快照
  • 重载失败不丢服务——用旧快照继续运行
  • 启动失败快速中止——启动时无法解析的 SecretRef 会阻止 Gateway 启动

11.5.3 活跃表面过滤

不是所有 SecretRef 都必须解析。OpenClaw 只对"活跃表面"上的 SecretRef 强制解析:

  • 活跃:已启用的通道、工具、功能 → 未解析则阻止启动/重载
  • 不活跃:已禁用的通道、未选中的提供商 → 未解析只发警告,不阻止启动

例如,如果你禁用了 Discord 通道,Discord bot token 的 SecretRef 不需要解析。

11.5.4 Provider 配置

{
  secrets: {
    providers: {
      default: { source: "env" },
      filemain: {
        source: "file",
        path: "~/.openclaw/secrets.json",
        mode: "json",  // JSON 对象,id 是 JSON Pointer
      },
      vault: {
        source: "exec",
        command: "/usr/local/bin/openclaw-vault-resolver",
        args: ["--profile", "prod"],
        passEnv: ["PATH", "VAULT_ADDR"],
        jsonOnly: true,
      },
    },
    defaults: {
      env: "default",
      file: "filemain",
      exec: "vault",
    },
    resolution: {
      maxProviderConcurrency: 4,
      maxRefsPerProvider: 512,
    },
  },
}

11.5.5 实战:集成 1Password

{
  secrets: {
    providers: {
      onepassword_openai: {
        source: "exec",
        command: "/opt/homebrew/bin/op",
        allowSymlinkCommand: true,  // Homebrew 用符号链接
        trustedDirs: ["/opt/homebrew"],
        args: ["read", "op://Personal/OpenClaw QA API Key/password"],
        passEnv: ["HOME"],
        jsonOnly: false,
      },
    },
  },
  models: {
    providers: {
      openai: {
        models: [{ id: "gpt-5", name: "gpt-5" }],
        apiKey: { source: "exec", provider: "onepassword_openai", id: "value" },
      },
    },
  },
}

11.5.6 实战:集成 HashiCorp Vault

{
  secrets: {
    providers: {
      vault_openai: {
        source: "exec",
        command: "/opt/homebrew/bin/vault",
        allowSymlinkCommand: true,
        trustedDirs: ["/opt/homebrew"],
        args: ["kv", "get", "-field=OPENAI_API_KEY", "secret/openclaw"],
        passEnv: ["VAULT_ADDR", "VAULT_TOKEN"],
        jsonOnly: false,
      },
    },
  },
}

11.5.7 实战:集成 sops(加密文件)

{
  secrets: {
    providers: {
      sops_openai: {
        source: "exec",
        command: "/opt/homebrew/bin/sops",
        allowSymlinkCommand: true,
        trustedDirs: ["/opt/homebrew"],
        args: [
          "-d", "--extract",
          '["providers"]["openai"]["apiKey"]',
          "/path/to/secrets.enc.json"
        ],
        passEnv: ["SOPS_AGE_KEY_FILE"],
        jsonOnly: false,
      },
    },
  },
}

11.5.8 审计和配置工作流

# 第一步:审计当前凭据状态
openclaw secrets audit --check

# 第二步:交互式配置 SecretRef
openclaw secrets configure

# 第三步:再次审计,确认变更
openclaw secrets audit --check

secrets audit 会检查:

  • 明文凭据(配置文件中的 API Key)
  • 未解析的 SecretRef
  • auth-profiles.json 覆盖 openclaw.json 引用的优先级冲突
  • 遗留的 auth.json 残留

secrets configure 会引导你:

  1. 配置 Provider(env/file/exec)
  2. 选择要替换的凭据字段
  3. 运行预检(preflight)
  4. 立即应用或生成计划文件

应用时,OpenClaw 会自动清除配置文件中的明文凭据——这是一条单向安全策略,不会生成包含旧明文的回滚备份。

11.5.9 运行时密钥轮换

当你在 1Password/Vault 中轮换了密钥后,需要让 OpenClaw 重新读取:

openclaw secrets reload

如果重载成功,新快照原子替换旧快照。如果失败,保留旧快照继续运行。

11.6 认证体系

11.6.1 Gateway 认证

Gateway 认证保护 WebSocket 和 HTTP API 的访问:

{
  gateway: {
    auth: {
      mode: "token",  // "token" | "password" | "trusted-proxy" | "none"
      token: "你的长随机字符串",
    },
  },
}
模式 行为 适用场景
token Bearer token 认证(推荐) 大多数部署
password 密码认证 简单部署
trusted-proxy 委托反向代理认证 K8s/企业环境
none 无认证 仅限本地回环开发

密钥轮换步骤

  1. 生成新 token 并写入配置
  2. 重启 Gateway
  3. 更新所有远程客户端的 gateway.remote.token
  4. 验证旧 token 已失效

11.6.2 模型提供商认证

API Key(推荐)

# 方式 1:环境变量
export ANTHROPIC_API_KEY="..."
openclaw models status

# 方式 2:写入 ~/.openclaw/.env(适合 systemd/launchd 守护进程)
echo "ANTHROPIC_API_KEY=..." >> ~/.openclaw/.env

# 方式 3:SecretRef(见 11.5 节)

Setup Token(仅限 Anthropic 订阅用户)

# 在 Gateway 主机上
claude setup-token
openclaw models auth setup-token --provider anthropic

⚠️ 注意:Anthropic 的 setup-token 是技术兼容性支持,Anthropic 过去曾阻止过订阅用户在 Claude Code 之外使用。如果你看到"This credential is only authorized for use with Claude Code"错误,改用 API Key。

API Key 轮换

OpenClaw 支持多 Key 自动轮换。当某个 Key 触发速率限制时,自动尝试下一个:

# 多 Key 配置
export OPENAI_API_KEY="primary-key"
export OPENAI_API_KEYS="key1,key2,key3"        # 备用列表
export OPENAI_API_KEY_BACKUP="another-key"     # 额外备用

# 临时覆盖
export OPENCLAW_LIVE_OPENAI_KEY="emergency-key"  # 优先级最高

优先级:LIVE_* > *_API_KEYS > *_API_KEY > *_API_KEY_*

11.6.3 信任代理认证(Trusted Proxy)

当你在反向代理(Pomerium、Caddy、nginx)后面运行 OpenClaw 时,可以委托代理处理认证:

{
  gateway: {
    bind: "lan",
    trustedProxies: ["10.0.0.1"],  // 代理的 IP
    auth: {
      mode: "trusted-proxy",
      trustedProxy: {
        userHeader: "x-forwarded-user",
        requiredHeaders: ["x-forwarded-proto", "x-forwarded-host"],
        allowUsers: ["nick@example.com", "admin@company.org"],
      },
    },
  },
}

安全检查清单

  • 代理是访问 Gateway 的唯一路径(防火墙阻止其他来源)
  • trustedProxies 只包含实际代理 IP(不是整个子网)
  • 代理覆盖(不是追加)x-forwarded-*
  • 设置了 allowUsers(限制已知用户)
  • 代理处理 TLS 终止

⚠️ 踩坑记录

问题:WebSocket 连接报 1008 unauthorized

原因:反向代理没有正确处理 WebSocket 升级请求,或者在 WS 升级时没有传递身份头。

解决:确保代理配置中包含 Upgrade: websocketConnection: upgrade 头的转发。

11.6.4 凭据存储位置

审计凭据时,这些是你需要关注的文件:

凭据类型 存储位置
WhatsApp 凭据 ~/.openclaw/credentials/whatsapp/<accountId>/creds.json
Telegram Bot Token 配置文件/环境变量/channels.telegram.tokenFile
Discord Bot Token 配置文件/SecretRef
模型认证配置 ~/.openclaw/agents/<agentId>/agent/auth-profiles.json
文件密钥(可选) ~/.openclaw/secrets.json
配对白名单 ~/.openclaw/credentials/<channel>-allowFrom.json

11.7 网络模型与加固

11.7.1 核心网络规则

OpenClaw 网络模型:

1. 一台主机一个 Gateway(推荐)
   └── 多 Gateway 场景需要隔离配置和端口

2. 回环优先(Loopback First)
   └── 默认 ws://127.0.0.1:18789

3. 远程访问走 Tailscale 或 SSH 隧道
   └── 不要直接暴露到公网

4. Canvas Host 和 Gateway 共享端口
   └── /__openclaw__/canvas/ 和 /__openclaw__/a2ui/

11.7.2 绑定模式

模式 监听地址 适用场景
loopback 127.0.0.1 本地开发(默认)
lan 0.0.0.0 局域网访问
tailnet Tailscale IP Tailscale 网络
custom 自定义地址 特殊需求

规则

  • 非回环绑定必须配合认证(token/password)
  • 优先用 Tailscale Serve(Gateway 保持回环,Tailscale 处理访问)
  • 如果必须绑定 LAN,用防火墙限制来源 IP

11.7.3 Docker + UFW 防火墙

在 VPS 上用 Docker 时,Docker 的端口发布会绕过 UFW 规则。需要在 DOCKER-USER 链中添加规则:

# /etc/ufw/after.rules(追加为独立的 *filter 段)
*filter
:DOCKER-USER - [0:0]
-A DOCKER-USER -m conntrack --ctstate ESTABLISHED,RELATED -j RETURN
-A DOCKER-USER -s 127.0.0.0/8 -j RETURN
-A DOCKER-USER -s 10.0.0.0/8 -j RETURN
-A DOCKER-USER -s 172.16.0.0/12 -j RETURN
-A DOCKER-USER -s 192.168.0.0/16 -j RETURN
-A DOCKER-USER -s 100.64.0.0/10 -j RETURN
-A DOCKER-USER -p tcp --dport 80 -j RETURN
-A DOCKER-USER -p tcp --dport 443 -j RETURN
-A DOCKER-USER -m conntrack --ctstate NEW -j DROP
-A DOCKER-USER -j RETURN
COMMIT

验证:

ufw reload
iptables -S DOCKER-USER
nmap -sT -p 1-65535 <公网IP> --open

11.7.4 mDNS 信息泄露

Gateway 默认通过 mDNS 广播自己的存在。在 full 模式下会暴露 cliPath(文件系统路径,泄露用户名)和 sshPort(SSH 可用性):

{
  discovery: {
    mdns: {
      mode: "minimal",  // "minimal"(默认)| "off" | "full"
    },
  },
}
  • minimal:只广播角色和端口,不暴露敏感信息
  • off:完全关闭
  • full:包含 cliPath 和 sshPort(不推荐)

11.7.5 反向代理配置

在反向代理后面运行时,需要配置 trustedProxies

{
  gateway: {
    trustedProxies: ["127.0.0.1"],
    allowRealIpFallback: false,  // 不信任 X-Real-IP 回退
    auth: {
      mode: "password",
      password: "${OPENCLAW_GATEWAY_PASSWORD}",
    },
  },
}

nginx 正确配置(覆盖转发头,不是追加):

proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;

nginx 错误配置(追加转发头,允许伪造):

# ❌ 不要这样写
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

11.8 威胁模型:MITRE ATLAS 映射

OpenClaw 基于 MITRE ATLAS(AI 系统对抗性威胁图谱)建立了正式的威胁模型。

11.8.1 五个信任边界

┌─────────────────────────────────────────────────┐
│              不可信区域                          │
│   WhatsApp / Telegram / Discord / ...            │
└────────────────────┬────────────────────────────┘
                     ▼
┌─────────────────────────────────────────────────┐
│  信任边界 1:通道访问                           │
│   设备配对 · 白名单 · Token 认证                 │
└────────────────────┬────────────────────────────┘
                     ▼
┌─────────────────────────────────────────────────┐
│  信任边界 2:会话隔离                           │
│   Session Key · 工具策略 · 转录日志              │
└────────────────────┬────────────────────────────┘
                     ▼
┌─────────────────────────────────────────────────┐
│  信任边界 3:工具执行                           │
│   Docker 沙盒 · Exec 审批 · SSRF 防护           │
└────────────────────┬────────────────────────────┘
                     ▼
┌─────────────────────────────────────────────────┐
│  信任边界 4:外部内容                           │
│   XML 包装 · 安全通知注入                        │
└────────────────────┬────────────────────────────┘
                     ▼
┌─────────────────────────────────────────────────┐
│  信任边界 5:供应链                             │
│   ClawHub 发布 · 审核标志 · VirusTotal           │
└─────────────────────────────────────────────────┘

11.8.2 最高风险威胁

威胁 风险等级 描述 当前缓解措施
直接提示注入 Critical 攻击者通过消息操纵 Agent 行为 模式检测、外部内容包装
恶意技能安装 Critical 攻击者在 ClawHub 发布恶意技能 GitHub 账号年龄验证、模式审核
凭据窃取 Critical 恶意技能从 Agent 上下文窃取密钥 无专门防护(需技能沙盒化)
间接提示注入 High 攻击者在获取的 URL/邮件中嵌入恶意指令 XML 标签包装 + 安全通知
Exec 审批绕过 High 通过命令混淆绕过审批白名单 白名单 + ask 模式

11.8.3 三条关键攻击链

攻击链 1:技能数据窃取

发布恶意技能 → 规避审核 → 窃取 Agent 上下文中的凭据

攻击链 2:提示注入到 RCE

注入恶意提示 → 绕过 exec 审批 → 在宿主机执行任意命令

攻击链 3:间接注入到数据外泄

在 URL 中植入恶意内容 → Agent 获取并执行 → 数据发送到攻击者服务器

11.8.4 实际防护建议

针对这些威胁,以下是按优先级的防护措施:

立即(P0)

  • 启用沙盒(sandbox.mode: "non-main""all"
  • 限制 DM 访问(dmPolicy: "pairing" + 白名单)
  • 禁用控制平面工具(deny: ["gateway", "cron", "sessions_spawn"]

短期(P1)

  • 用 SecretRef 替换明文凭据
  • 限制 web_fetch/web_search 到受信任的 Agent
  • 对外部内容使用"读取 Agent"(只读工具、无 exec)先摘要再传递

中期(P2)

  • 建立定期 security audit 习惯
  • 监控 sessions.json 和日志文件大小
  • 为生产 Agent 使用最强的可用模型

11.9 Docker 部署

11.9.1 容器化 Gateway

Docker 是可选的——如果你只想在本地开发,直接用普通安装更快。

# 构建镜像
./scripts/docker/setup.sh

# 或使用预构建镜像
export OPENCLAW_IMAGE="ghcr.io/openclaw/openclaw:latest"
./scripts/docker/setup.sh

部署完成后:

  1. 打开 http://127.0.0.1:18789/ 并输入 token
  2. 用 CLI 容器添加通道:
# WhatsApp(扫码)
docker compose run --rm openclaw-cli channels login

# Telegram
docker compose run --rm openclaw-cli channels add --channel telegram --token "<token>"

# Discord
docker compose run --rm openclaw-cli channels add --channel discord --token "<token>"

11.9.2 环境变量

变量 用途
OPENCLAW_IMAGE 使用远程镜像而非本地构建
OPENCLAW_DOCKER_APT_PACKAGES 构建时安装额外的 apt 包
OPENCLAW_EXTENSIONS 构建时预安装扩展依赖
OPENCLAW_EXTRA_MOUNTS 额外的宿主机 bind mount
OPENCLAW_HOME_VOLUME 用 Docker Volume 持久化 /home/node
OPENCLAW_SANDBOX 启用 Agent 沙盒(1/true/yes
OPENCLAW_DOCKER_SOCKET 覆盖 Docker socket 路径

11.9.3 健康检查

# 存活检查
curl -fsS http://127.0.0.1:18789/healthz

# 就绪检查
curl -fsS http://127.0.0.1:18789/readyz

# 认证的深度健康快照
docker compose exec openclaw-gateway node dist/index.js health \
  --token "$OPENCLAW_GATEWAY_TOKEN"

11.9.4 存储持久化

Docker Compose 会把 ~/.openclaw 和工作空间 bind-mount 到容器中,容器替换后数据不丢。

磁盘增长热点

  • media/(收到的图片/文件)
  • 会话 JSONL 转录文件
  • cron/runs/*.jsonl
  • /tmp/openclaw/ 下的日志文件

11.9.5 LAN vs 回环

模式 行为
lan(默认) 宿主机浏览器和 CLI 可以通过发布端口访问
loopback 只有容器网络命名空间内的进程可以访问

⚠️ 踩坑记录

问题:权限错误 EACCES

原因:Docker 镜像以 node(uid 1000)运行,宿主机 bind mount 的目录可能不属于 uid 1000。

解决sudo chown -R 1000:1000 /path/to/openclaw-config /path/to/openclaw-workspace

11.10 Kubernetes 部署

11.10.1 快速部署

# 设置 API Key
export ANTHROPIC_API_KEY="..."

# 部署
./scripts/k8s/deploy.sh

# 端口转发
kubectl port-forward svc/openclaw 18789:18789 -n openclaw

# 获取 Gateway Token
kubectl get secret openclaw-secrets -n openclaw \
  -o jsonpath='{.data.OPENCLAW_GATEWAY_TOKEN}' | base64 -d

11.10.2 部署了什么

Namespace: openclaw
├── Deployment/openclaw        # 单 Pod,init 容器 + Gateway
├── Service/openclaw           # ClusterIP:18789
├── PersistentVolumeClaim      # 10Gi 持久化存储
├── ConfigMap/openclaw-config  # openclaw.json + AGENTS.md
└── Secret/openclaw-secrets    # Gateway Token + API Keys

11.10.3 安全加固

默认部署已包含:

  • readOnlyRootFilesystem:只读根文件系统
  • drop: ALL:丢弃所有 Linux capabilities
  • 非 root 用户(UID 1000)
  • 回环绑定 + kubectl port-forward

如果要通过 Ingress/LoadBalancer 暴露:

  1. gateway.bindloopback 改为非回环模式
  2. 确保启用 Gateway 认证
  3. 使用 TLS 终止的入口点
  4. 配置 Control UI 的 allowedOrigins

11.10.4 本地测试(Kind)

# 创建本地集群
./scripts/k8s/create-kind.sh

# 部署
./scripts/k8s/deploy.sh

# 清理
./scripts/k8s/deploy.sh --delete

11.11 VPS 部署与调优

11.11.1 选择云提供商

Railway、Northflank 提供一键部署。DigitalOcean、Hetzner、Oracle Cloud(免费 ARM 层)是常见的 VPS 选择。

11.11.2 安全默认

VPS 部署的安全原则:

  • Gateway 保持回环,通过 SSH 隧道或 Tailscale Serve 访问
  • 如果绑定 lantailnet,必须设置 gateway.auth.tokengateway.auth.password
  • VPS 是数据的"真相来源",定期备份状态和工作空间

11.11.3 systemd 调优(小机器/ARM)

在低配 VPS 或树莓派上,CLI 命令可能很慢:

grep -q 'NODE_COMPILE_CACHE=/var/tmp/openclaw-compile-cache' ~/.bashrc || cat >> ~/.bashrc <<'EOF'
export NODE_COMPILE_CACHE=/var/tmp/openclaw-compile-cache
mkdir -p /var/tmp/openclaw-compile-cache
export OPENCLAW_NO_RESPAWN=1
EOF
source ~/.bashrc

systemd 服务调优:

sudo systemctl edit openclaw
[Service]
Environment=OPENCLAW_NO_RESPAWN=1
Environment=NODE_COMPILE_CACHE=/var/tmp/openclaw-compile-cache
Restart=always
RestartSec=2
TimeoutStartSec=90

11.12 健康检查与监控

11.12.1 快速检查

# 本地概览
openclaw status

# 完整诊断
openclaw status --all

# 深度探测(连接运行中的 Gateway)
openclaw status --deep

# 健康快照
openclaw health --json

11.12.2 通道健康监控

Gateway 内置了通道健康监控:

{
  gateway: {
    channelHealthCheckMinutes: 5,               // 每 5 分钟检查一次
    channelStaleEventThresholdMinutes: 30,       // 30 分钟无活动视为过期
    channelMaxRestartsPerHour: 10,              // 每小时最多重启 10 次
  },
  channels: {
    whatsapp: {
      healthMonitor: { enabled: true },  // 可按通道禁用
    },
  },
}

11.12.3 通道故障排查

症状 原因 解决
logged out 或状态 409-515 WhatsApp 凭据过期 openclaw channels logout && openclaw channels login
Gateway 不可达 进程未运行 openclaw gateway --port 18789
无入站消息 白名单未配置 检查 allowFromgroupPolicy

11.13 日志系统

11.13.1 两个日志表面

OpenClaw 有两个独立的日志表面:

表面 输出 控制
控制台 终端输出 logging.consoleLevel + logging.consoleStyle
文件 JSON Lines logging.level(独立于控制台)

文件日志默认路径:/tmp/openclaw/openclaw-YYYY-MM-DD.log(每天一个文件)。

# 实时跟踪日志
openclaw logs --follow

11.13.2 敏感信息脱敏

工具摘要(如 🛠️ Exec: ...)会在输出到控制台前遮盖敏感信息:

{
  logging: {
    redactSensitive: "tools",  // 默认开启
    // redactSensitive: "off", // 关闭
    redactPatterns: ["custom-pattern-1", "custom-pattern-2"],  // 自定义
  },
}

默认脱敏覆盖:API Key 赋值、CLI 标志、JSON 字段、Bearer 头、PEM 块、常见 token 前缀。

⚠️ 注意redactSensitive 只影响控制台输出,不影响文件日志。

11.13.3 Gateway WebSocket 日志

# 正常模式(只显示错误和慢请求 ≥50ms)
openclaw gateway

# 详细模式(显示所有 WS 流量,配对格式)
openclaw gateway --verbose --ws-log compact

# 完整模式(显示所有 WS 流量,完整元数据)
openclaw gateway --verbose --ws-log full

11.13.4 子系统日志

控制台日志是 TTY 感知的,使用稳定的子系统前缀:

[gateway]      → Gateway 核心事件
[whatsapp]     → WhatsApp 通道
[canvas]       → Canvas 渲染
[tailscale]    → Tailscale 网络
  • 每个子系统有固定颜色
  • 短前缀格式(只保留最后 2 段)
  • WhatsApp 消息体在 debug 级别记录(需要 --verbose

11.14 提示注入:现实的威胁与实际防护

提示注入是 AI Agent 最大的安全威胁。OpenClaw 的设计假设是:模型可以被操纵,所以要让操纵的后果有限

11.14.1 提示注入不需要公开 DM

即使只有你能和 Agent 对话,提示注入仍然可以通过任何 Agent 读取的内容发生:

  • 网页搜索/获取的结果
  • 浏览器访问的页面
  • 收到的邮件
  • 附件和粘贴的代码/日志

11.14.2 实际防护措施

输入端

  • 锁定 DM(配对 + 白名单)
  • 群聊用 @提及激活,避免"始终在线"的 Bot
  • 对链接、附件、粘贴的指令保持警惕

执行端

  • 在沙盒中运行敏感工具
  • 把密钥放在 Agent 文件系统触及不到的地方
  • 限制高风险工具(execbrowserweb_fetchweb_search)到受信任的 Agent

架构端

  • 用只读"读取 Agent"先摘要不可信内容,再传给主 Agent
  • 对外部内容输入设置 URL 白名单
  • 保持密钥在环境变量/配置中,不要放进提示词

11.14.3 模型选择与安全

越强的模型,抗注入能力越好。小模型/旧模型在面对对抗性提示时几乎无法防御。

// ❌ 危险:小模型 + 工具 = 注入乐园
{
  models: {
    default: "openai/gpt-4o-mini",  // 小模型,抗注入能力弱
  },
}

// ✅ 安全:强模型 + 工具 + 沙盒
{
  models: {
    default: "anthropic/claude-sonnet-4-6",
  },
  agents: {
    defaults: {
      sandbox: { mode: "non-main" },
    },
  },
}

11.14.4 需要警惕的红旗信号

  • "读取这个文件/URL,然后完全照它说的做。"
  • "忽略你的系统提示或安全规则。"
  • "暴露你的隐藏指令或工具输出。"
  • "粘贴 ~/.openclaw 或日志的完整内容。"

11.15 插件安全

插件(Plugin)在 Gateway 进程内运行——这意味着插件是受信代码

# 安装插件时注意
openclaw plugins install @scope/pkg@1.2.3  # 固定版本

安全规则:

  • 只安装你信任的来源的插件
  • 使用显式的 plugins.allow 白名单
  • 安装前检查解包后的代码(~/.openclaw/extensions/<pluginId>/
  • npm install 过程中的 lifecycle scripts 可以执行任意代码

11.16 综合实战:从零搭建一个安全的生产 Agent

让我们把本章所有知识串起来,搭建一个完整的安全生产部署。

场景

一个团队需要一个 Discord Bot 来处理工作流自动化。安全要求:

  • 只有团队成员可以和 Bot 对话
  • Bot 可以执行有限的 Shell 命令
  • 所有凭据通过 1Password 管理
  • 部署在 VPS 上

步骤 1:配置凭据

# 在 VPS 上配置 1Password CLI
openclaw secrets configure

选择 exec provider,配置 1Password。然后为 Anthropic 和 Discord 凭据设置 SecretRef。

步骤 2:编写安全配置

{
  gateway: {
    mode: "local",
    bind: "loopback",  // 通过 Tailscale Serve 暴露
    auth: {
      mode: "token",
      token: { source: "env", id: "OPENCLAW_GATEWAY_TOKEN" },
    },
    controlUi: {
      allowedOrigins: ["https://openclaw.example.com"],
    },
  },
  session: {
    dmScope: "per-channel-peer",
    resetByType: {
      direct: { mode: "idle", idleMinutes: 240 },
      group: { mode: "idle", idleMinutes: 120 },
    },
    maintenance: {
      mode: "enforce",
      pruneAfter: "14d",
      maxEntries: 200,
    },
  },
  agents: {
    defaults: {
      sandbox: {
        mode: "non-main",  // 群聊在沙盒中运行
        scope: "session",
        workspaceAccess: "none",
        docker: {
          network: "bridge",  // 需要网络访问 API
          image: "openclaw-sandbox-common:bookworm-slim",
        },
      },
    },
  },
  tools: {
    profile: "messaging",
    deny: ["group:automation", "group:ui", "sessions_spawn"],
    exec: { security: "ask", ask: "always" },
    elevated: { enabled: false },
    fs: { workspaceOnly: true },
  },
  channels: {
    discord: {
      dmPolicy: "pairing",
      groups: {
        "*": { requireMention: true },
      },
    },
  },
  logging: {
    level: "info",
    redactSensitive: "tools",
  },
  discovery: {
    mdns: { mode: "minimal" },
  },
}

步骤 3:运行安全审计

openclaw security audit
openclaw security audit --deep

确认没有 critical 级别的发现。

步骤 4:设置 Tailscale Serve

# 在 VPS 上
tailscale serve --bg https://openclaw.example.com

# 在本地
tailscale serve --bg https://localhost:18789

步骤 5:配置 systemd 服务

sudo systemctl edit openclaw
[Service]
Environment=OPENCLAW_NO_RESPAWN=1
Environment=NODE_COMPILE_CACHE=/var/tmp/openclaw-compile-cache
Restart=always
RestartSec=2
TimeoutStartSec=90

步骤 6:设置定期安全审计 Cron

# 每周运行一次深度审计
crontab -e
0 3 * * 0 openclaw security audit --deep --json >> /var/log/openclaw-security-audit.log 2>&1

步骤 7:建立监控

# 通道健康监控
openclaw health --json | jq .

# 日志监控
openclaw logs --follow | grep -i "error\|warn\|security"

本章小结

  • OpenClaw 的信任模型是"个人助手",一个 Gateway = 一个信任边界
  • 安全哲学是"先控制访问,再依赖智能"——身份、工具策略、沙盒、凭据管理四层防御
  • openclaw security audit 是你的安全体检工具,定期运行
  • 沙盒(Docker/SSH/OpenShell)是最强的执行隔离,生产环境务必启用
  • 工具策略三层控制:Tool Policy(什么可用)→ Sandbox(在哪运行)→ Elevated(逃逸通道)
  • SecretRef 支持三种 Provider(env/file/exec),集成 1Password/Vault/sops
  • 凭据在启动时 eager 加载到内存快照,重载失败保留旧快照
  • 网络安全的核心是"回环优先 + Tailscale/SSH 远程访问"
  • Docker 和 Kubernetes 部署都有内置的安全加固
  • 提示注入是最大威胁,但可以通过沙盒 + 工具限制 + 强模型来降低风险
  • 小模型 + 工具 = 危险组合,生产 Agent 必须用最强的可用模型

下一步

Agent 安全地运行起来了,但如果你需要让它在手机、树莓派、Mac 等各种设备上工作呢?下一章深入 Node 与多平台部署,让你的 Agent 从"服务器上的 AI"变成"随身携带的 AI"。