☰
Docker 沙盒实战:给 OpenClaw 套上隔离层,API 密钥不再“裸奔”
2026/9/25 9:14:32 网站建设 项目流程

1. 本地跑 OpenClaw,密钥为什么总在“裸奔”

OpenClaw 是今年开源圈里跑得最快的 AI 编码代理之一,它能在你本机直接读写文件、执行 Shell、发起网络请求,一条指令就能让 AI 帮你改 Bug、跑测试、提交代码。方便是真方便,但风险也藏在这份“自由”里:它默认继承你当前用户的环境变量,而ANTHROPIC_API_KEY、OPENAI_API_KEY这类密钥通常就写在.env或 shell profile 里。代理一旦被提示注入、被恶意仓库里的脚本诱导,或者只是单纯地“理解错了任务”,它完全有能力把密钥读出来、发到外部地址。

我试过在本地直接跑 OpenClaw,第一次看到它自动cat .env去确认配置时,后背是有点发凉的。这不是 OpenClaw 的 bug,而是所有本地 AI 代理的共性:它需要密钥才能调用大模型,但密钥一旦进入它的进程空间,就不再受你控制。Docker 官方给出的思路很直接——把 OpenClaw 关进沙盒,让密钥由代理层注入,代理进程本身永远拿不到明文。这篇就按这个思路,给你一套可复制的 Dockerfile 与 docker-compose 骨架,并演示密钥注入和沙盒逃逸验证,目标是你照着做就能跑起一套“密钥不落地”的 OpenClaw 环境。

2. 前置准备:TaoToken 与 Docker 环境

2.1 为什么这里会用到 TaoToken

OpenClaw 本身只是个代理框架,真正干活的是背后的大模型。你可以选择本地 Model Runner 跑开源模型,也可以接云端 API 获得更强的编码能力。接云端时,密钥管理就是核心问题。TaoToken 提供统一的模型接入层,你可以在它的控制台生成 API Key,然后在沙盒里通过环境变量注入,OpenClaw 进程只拿到一个指向本地代理的地址,密钥原文不进入容器。

具体来说,TaoToken 的 API 端点是https://taotoken.net/api,兼容 OpenAI 风格的调用方式。你需要在控制台创建一个 Key,后面我们会把它写进宿主机的.env,再由 docker-compose 注入到沙盒的代理层,而不是直接塞给 OpenClaw。

2.2 Docker 环境要求

你需要 Docker Desktop 24 以上版本,并且开启 Sandboxes 支持(目前主要在 macOS 和 Linux 的 Docker Desktop 中可用)。如果你只是用普通容器做隔离,也可以,但 microVM 级别的内核隔离会更彻底。先确认版本:

docker version docker sandbox --help

如果docker sandbox命令不存在,说明你的 Docker Desktop 版本偏低,升级到最新稳定版即可。另外,本地至少留 8GB 内存给沙盒和模型推理,编码代理跑起来后内存占用不低。

2.3 目录结构规划

我们在宿主机建一个工作目录,把配置和密钥分开存放:

mkdir -p ~/openclaw-sandbox/{config,workspace,secrets} cd ~/openclaw-sandbox

secrets目录只放.env,权限设为600,并且不挂载进沙盒。workspace是 OpenClaw 唯一能读写的区域。config放 OpenClaw 的配置文件。

3. 可复制配置:Dockerfile 与 docker-compose 骨架

3.1 Dockerfile:构建带桥接脚本的 OpenClaw 镜像

Docker 官方有预构建镜像olegselajev241/openclaw-dmr:latest,但为了让你看清每一层,我们手写一个精简版。核心是 Node.js 22、OpenClaw 本体,以及一个把请求转发到沙盒网络代理的桥接脚本。

FROM node:22-slim # 安装基础工具 RUN apt-get update && apt-get install -y --no-install-recommends \ curl ca-certificates git \ && rm -rf /var/lib/apt/lists/* # 安装 OpenClaw RUN npm install -g @openclaw/cli # 创建非 root 用户,降低逃逸后的破坏面 RUN useradd -m -s /bin/bash claw && mkdir -p /workspace && chown claw:claw /workspace # 桥接脚本:把本地请求转发到沙盒网络代理 COPY bridge.js /usr/local/bin/bridge.js COPY start-openclaw.sh /usr/local/bin/start-openclaw.sh RUN chmod +x /usr/local/bin/start-openclaw.sh USER claw WORKDIR /workspace ENTRYPOINT ["/usr/local/bin/start-openclaw.sh"]

桥接脚本bridge.js的作用是监听127.0.0.1:54321,把 OpenClaw 发出的请求转发到host.docker.internal:3128,也就是沙盒的网络代理层。这样 OpenClaw 只能通过这条受控通路访问外部,不能自己乱发请求。

// bridge.js const http = require('http'); const { request } = require('http'); const PROXY_HOST = 'host.docker.internal'; const PROXY_PORT = 3128; const LISTEN_PORT = 54321; http.createServer((req, res) => { const options = { host: PROXY_HOST, port: PROXY_PORT, path: req.url, method: req.method, headers: { ...req.headers, host: `${PROXY_HOST}:${PROXY_PORT}` }, }; const proxyReq = request(options, (proxyRes) => { res.writeHead(proxyRes.statusCode, proxyRes.headers); proxyRes.pipe(res); }); proxyReq.on('error', (err) => { res.writeHead(502); res.end(`bridge error: ${err.message}`); }); req.pipe(proxyReq); }).listen(LISTEN_PORT, '127.0.0.1', () => { console.log(`bridge listening on 127.0.0.1:${LISTEN_PORT}`); });

启动脚本start-openclaw.sh负责拉起桥接、设置 OpenClaw 的 API 地址指向桥接端口,然后启动 OpenClaw:

#!/bin/bash set -e node /usr/local/bin/bridge.js & sleep 1 export OPENCLAW_API_BASE="http://127.0.0.1:54321/v1" export OPENCLAW_MODEL="${OPENCLAW_MODEL:-claude-sonnet}" exec openclaw "$@"

注意这里没有出现任何真实密钥,OPENCLAW_API_BASE指向的是本地桥接,桥接再走代理层。密钥由代理层在转发时注入。

3.2 docker-compose:密钥注入与网络隔离

docker-compose 负责把宿主机.env里的密钥传给沙盒代理,而不是传给 OpenClaw 容器本身。这里用env_file加载到代理服务,OpenClaw 服务只拿到代理地址。

version: "3.9" services: sandbox-proxy: image: alpine/socat:latest command: > TCP-LISTEN:3128,fork,reuseaddr TCP:host.docker.internal:12434 environment: - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} - OPENAI_API_KEY=${OPENAI_API_KEY} env_file: - ./secrets/.env networks: - claw-net openclaw: build: . depends_on: - sandbox-proxy volumes: - ./workspace:/workspace - ./config:/home/claw/.config/openclaw environment: - OPENCLAW_API_BASE=http://sandbox-proxy:3128/v1 - OPENCLAW_MODEL=claude-sonnet networks: - claw-net # 关键:不挂载 secrets 目录,不传密钥环境变量 read_only: false security_opt: - no-new-privileges:true networks: claw-net: driver: bridge

secrets/.env内容示例:

ANTHROPIC_API_KEY=sk-ant-xxxxxxxx OPENAI_API_KEY=sk-xxxxxxxx

这个文件权限设为600,只被sandbox-proxy读取。OpenClaw 容器里执行env是看不到这些 Key 的,它只能看到OPENCLAW_API_BASE。

4. 验证请求与沙盒逃逸测试

4.1 启动并确认密钥不可见

先构建并启动:

docker compose build docker compose up -d docker compose exec openclaw env | grep -i key

预期输出为空,或者只有OPENCLAW_API_BASE这类非敏感变量。如果你看到了ANTHROPIC_API_KEY,说明注入路径写错了,密钥泄漏到了代理进程。

接着在 OpenClaw 容器里尝试读取宿主机文件:

docker compose exec openclaw cat /etc/shadow docker compose exec openclaw ls /home

因为容器只挂载了workspace和config,/etc/shadow会返回权限拒绝,/home下也看不到宿主机的用户目录。这就是文件访问被硬限制在工作区的效果。

4.2 验证模型调用通路

在 OpenClaw 里发一个最小请求,确认桥接和代理层工作正常:

docker compose exec openclaw curl -s http://127.0.0.1:54321/v1/models

如果返回模型列表,说明桥接把请求转发到了代理层,代理层再路由到 TaoToken 或本地 Model Runner。你也可以直接在宿主机用 TaoToken 的 API 端点测试 Key 是否有效:

curl -s https://taotoken.net/api/v1/models \ -H "Authorization: Bearer $ANTHROPIC_API_KEY"

注意这个命令在宿主机执行,用的是宿主机环境变量,和沙盒内的进程完全隔离。

4.3 沙盒逃逸验证动作

我们做两个轻量级验证,确认边界有效。第一,尝试从 OpenClaw 容器访问宿主机 localhost 的敏感端口:

docker compose exec openclaw curl -s --max-time 3 http://host.docker.internal:12434

如果代理层没有放行这个端口,请求会超时或被拒。第二,尝试写入工作区之外:

docker compose exec openclaw touch /etc/test-escape

预期返回Permission denied。这两个动作能让你直观看到:OpenClaw 能碰到的,只有你给它的那片空间。

5. 本篇常见错排查

5.1 桥接脚本报 502

如果curl http://127.0.0.1:54321/v1/models返回 502,先检查sandbox-proxy是否在运行:

docker compose ps docker compose logs sandbox-proxy

常见原因是host.docker.internal在 Linux 上不自动解析,需要在 compose 里加:

extra_hosts: - "host.docker.internal:host-gateway"

5.2 密钥仍然出现在 OpenClaw 环境里

检查docker-compose.yml里openclaw服务是否误加了env_file或environment里的 Key。密钥只能出现在sandbox-proxy服务。另外确认secrets目录没有被挂载进openclaw的 volumes。

5.3 OpenClaw 启动后找不到模型

如果 OpenClaw 报模型不存在,检查OPENCLAW_MODEL是否和代理层实际提供的模型名一致。用 TaoToken 时,模型名以控制台展示的为准;用本地 Model Runner 时,先docker model pull拉取对应模型,再确认localhost:12434可访问。

5.4 沙盒内 DNS 解析失败

microVM 沙盒的网络默认走代理层,如果代理层没有配置 DNS 转发,容器内解析外部域名会失败。可以在sandbox-proxy里加dns配置,或者直接用 IP 访问。更稳妥的做法是让代理层统一处理域名解析,OpenClaw 只认桥接地址。

5.5 工作区文件权限问题

OpenClaw 以非 root 用户claw运行,如果workspace目录在宿主机属于 root,容器内会写不进去。启动前执行:

sudo chown -R 1000:1000 ~/openclaw-sandbox/workspace

其中1000是容器内claw用户的 UID,你可以用docker compose exec openclaw id确认。

6. 把密钥关进代理层,让 OpenClaw 只干活不碰钥匙

这套方案的核心不是“信任 OpenClaw”,而是给它设定可验证的边界:文件访问限制在工作区,网络请求经过代理层过滤,API 密钥由代理层注入、代理进程不可见。你可以在 TaoToken 控制台生成和管理 API Key,把 Key 写进宿主机的secrets/.env,再通过 docker-compose 注入到sandbox-proxy,OpenClaw 容器里始终只有一个指向桥接的地址。

如果你需要长期跑编码代理或 Agent 工作流,建议把镜像保存下来复用:

docker compose build docker save openclaw-sandbox_openclaw:latest -o openclaw-sandbox.tar

团队成员拿到镜像后,各自在宿主机配置自己的 TaoToken Key,沙盒环境一致,密钥互不干扰。需要更强模型能力时,在 TaoToken 控制台切换模型即可,OpenClaw 侧不用改任何配置。密钥不落地,代理才敢放开跑。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询