第 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 对话独立隔离
- 默认只给消息类工具(
messagingprofile) - 禁止所有运行时工具、文件工具、自动化工具
- 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 后端的工作方式:
- 首次使用时,OpenClaw 把本地工作空间种子同步到远程主机
- 之后所有
exec、read、write操作直接在远程主机上执行 - 远程变更是不会自动同步回本地的(远程规范化模型)
⚠️ 踩坑记录
问题:在本地编辑了文件,但沙盒里的 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,在宿主机运行) │
└──────────────────────────────────────────────────┘
关键规则:
deny永远赢。如果工具在 deny 列表里,沙盒和提权都救不回来。- 如果
allow非空,其他所有工具都视为被阻止。 /exec指令只调整会话默认值,不授予工具访问权。- 提权只影响
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 会引导你:
- 配置 Provider(env/file/exec)
- 选择要替换的凭据字段
- 运行预检(preflight)
- 立即应用或生成计划文件
应用时,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 |
无认证 | 仅限本地回环开发 |
密钥轮换步骤:
- 生成新 token 并写入配置
- 重启 Gateway
- 更新所有远程客户端的
gateway.remote.token - 验证旧 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: websocket和Connection: 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
部署完成后:
- 打开
http://127.0.0.1:18789/并输入 token - 用 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 暴露:
- 把
gateway.bind从loopback改为非回环模式 - 确保启用 Gateway 认证
- 使用 TLS 终止的入口点
- 配置 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 访问
- 如果绑定
lan或tailnet,必须设置gateway.auth.token或gateway.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 |
| 无入站消息 | 白名单未配置 | 检查 allowFrom 和 groupPolicy |
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 文件系统触及不到的地方
- 限制高风险工具(
exec、browser、web_fetch、web_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"。