资讯详情

资讯详情

OpenClaw安全部署:基于Docker Compose的极简实践

OpenClaw这个项目最近在自动化工作流和Agent圈子里讨论度相当高。它本质是一个开源的智能体运行框架可以通过自然语言编排工具调用、代码执行、文件读写一整套流程几乎是“一个能自己干活的AI助手”跑起来的最短路径。也正因为热各种一键部署脚本满天飞我见过不少人直接裸奔拉端口、密钥硬编码进配置文件、容器默认用root跑。就在这时候某长期专注链上安全审计的团队贴出了一份极简安全实践指南把OpenClaw部署这条线的安全基线钉在了一个非常务实的位置。我照着复现了一遍整个过程有收获也有坑这篇文章就是一份可以直接抄作业的记录。1. 先想明白OpenClaw真正面临的是哪几类风险1.1 智能体框架的安全敞口集中在三个地方把OpenClaw部署到服务器上本质上就是运行了一个“可联网、可读文件、可执行命令”的服务进程。这个进程的能力上限就是攻击者拿下它之后能拿到的东西。很多人部署OpenClaw只想着功能没想明白这个逻辑你给它开的权限越完整它被攻破时的代价就越大。它的安全隐患基本集中在三个位置。第一个位置是对外接口。OpenClaw核心服务会暴露HTTP端口如果这个端口不做鉴权任何人只要知道IP就能调用你的Agent能力。这种问题很常见尤其当服务器防火墙配得不严的时候扫描器扫到开放端口之后轻则把你的模型额度刷光重则直接操控Agent执行恶意脚本。第二个位置是代码执行能力。OpenClaw之所以能用自然语言编排任务是因为它内部提供了一套工具集其中包含在操作系统层面执行命令、读写文件、调用第三方API等能力。这套能力是双刃剑如果控制台被未授权访问相当于把服务器的终端窗口递给了攻击者。即便隔离了权限如果Executor沙箱没有做资源限制一个死循环脚本就能打满CPU、吃爆内存。第三个位置是凭据散落。模型API Key、数据库口令、JWT密钥这类敏感信息如果在部署时被写进了代码仓库、配置文件、Dockerfile或者更夸张地写进了镜像构建层那么任何能下载你镜像、拿到仓库访问权限的人都能把这些密钥扒出来。这个问题我在很多项目里都见过OpenClaw的部署教程里如果只演示“把key填到config里”基本就是在埋雷。1.2 极简不等于裸奔三个安全原则必须先定调那份指南最让我认同的地方是没有一上来就堆各种扫描器、WAF、蜜罐而是先立住了三条底线。默认拒绝。所有能力默认关闭需要的时候再显式打开。OpenClaw的API鉴权默认开启、外部访问默认不放开、需要权限的工具默认不启用。这和很多互联网产品的设计相反但作为安全基线反向的默认值才正确。最小权限。服务进程不跑root容器内根文件系统只读内核能力全部丢弃需要什么再加什么。这条听着简单实际操作中我测试过很多镜像OpenClaw这类应用默认运行用户往往是root要自己改。最小暴露。对外只暴露必要入口内部服务之间的通信全部收敛到容器网络内不绑定到宿主机全局端口。换句话说即使Nginx被攻破攻击者最多也只能打到网关这一层不容易直接触达核心服务。这三条对应的其实是同一个思考你不需要把所有威胁都挡住但你一定要把攻击者花费的代价拉到足够高。极简部署的意思就是通过缩小攻击面用最少的配置项获得最高的基础安全性。1.3 为什么选择Docker Compose而不是Kubernetes看到指南里通篇只用docker compose有人会质疑既然要安全为什么不用Kubernetes的NetworkPolicy、RBAC、PodSecurity这些能力我的看法是OpenClaw这种体量的服务单机部署完全够用上K8s是给自己找麻烦。K8s的隔离模型非常优秀但引入它意味着同时引入组件、证书、鉴权、网络插件等一大套需要维护的东西。这些组件本身每一环都有安全配置配置不当新引入的风险比它解决掉的还多。Compose的network隔离、cap_drop、read_only、user这些原语已经能覆盖单机部署场景下最重要的安全需求。它的优势是每一条安全策略都可被逐行审计整个部署文件只有几十行普通人能看懂、能维护。这才是极简的核心不是功能少而是可控性强。2. 部署组件和安全参数逐项拆解2.1 一个最小可用的OpenClaw平台包含哪些角色我复现下来的结论是最精简的部署至少要有四个角色各自职责和风险点不一样。组件职责安全要点openclaw-core任务编排、模型调用、HTTP API对外接口必须鉴权运行态权限最小化openclaw-executor执行Agent生成的代码/命令沙箱隔离限制资源禁止挂载敏感目录cache-db存储会话、任务状态不对外暴露端口口令使用高强度随机值gateway反向代理、TLS终结统一入口HTTP强制跳转HTTPS关键不是这四个组件都齐全而是executor必须和core隔离。有些简化部署会把执行能力直接内嵌在core里这样一旦HTTP接口被绕过攻击者直接进入宿主执行链。隔离之后攻击者先要突破core这一层再要通过容器逃逸进入executor每一步都能被日志记录下来。2.2 密钥管理环境变量注入而不是配置文件说一个很容易被忽略的坑OpenClaw如果以传统方式配置密钥密钥一旦出现在配置文件里再通过Dockerfile复制进镜像它就会永久留在镜像层中。任何人用docker history或者说docker save拿到镜像都能通过查看中间层历史把这个密钥翻出来。正确做法是使用环境变量注入。Compose启动时会读取宿主机上的.env文件把变量传给容器进程配置文件里不出现任何真实密钥。这样即使镜像被分发它也只是一个“半成品”真正的密钥由运行时提供。2.3 Docker安全参数逐个解释这是整份指南里最值得逐行抄写的部分。每一项参数都有明确目的不是随便加的。user: 10001:10001。指定容器运行用户为非root。容器里虽然没有完整内核权限但默认root用户视角下一旦发生逃逸攻击者面对的就是宿主机的root视角。换成一个普通UID能有效抬高提权门槛。read_only: true。根文件系统只读。应用运行的临时写入需求交给tmpfs或卷。这能阻止攻击者往镜像层写任何持久化内容即使执行了恶意命令重启后一切复原。cap_drop: ALL。丢弃所有内核能力。Linux能力机制是容器逃逸的重要放大点删除全部之后再按需添加比默认保留一大撮能力安全得多。security_opt: [no-new-privileges: true]。禁止进程通过setuid等方式提权。如果应用被攻破这条会成为一道硬阀门。pids_limit。限制最大进程数防止执行脚本fork炸弹。tmpfs。临时目录放内存不落盘内存里内容随容器生命周期结束消失。这行参数组合下来OpenClaw的服务就被“关进了一个几乎不可写、不可提权、不可无限扩张进程”的笼子里。我在复现时专门做了几个攻击模拟效果很明显。3. 极简部署实操记录3.1 环境准备这个部署对硬件要求不高一台2核4G内存的Linux服务器就够。系统环境只需要Docker和Compose插件不需要额外安装复杂的语言环境这也是容器化带来的最大便利。建议把项目放在独立目录这样后续维护审计时方便。执行下面的命令完成基本目录准备mkdir -p /opt/openclaw/{data,logs} chown 10001:10001 /opt/openclaw/data /opt/openclaw/logs这条chown很关键。read_only模式下只有挂载卷可写而这个卷在宿主机上归属某个UID。如果目录权限不对容器启动后会直接报Permission Error很多人第一次部署都会卡在这里。3.2 编写docker-compose.yml下面这份Compose文件是我复现后经实际运行通过的版本可以直接作为模板services: gateway: image: nginx:1.25-alpine ports: - 443:443 - 80:80 volumes: - ./nginx/conf.d:/etc/nginx/conf.d:ro - ./certs:/etc/nginx/certs:ro depends_on: - core networks: - internal core: image: openclaw/openclaw:latest user: 10001:10001 environment: OPENCLAW_API_KEY: ${OPENCLAW_API_KEY} OPENCLAW_JWT_SECRET: ${OPENCLAW_JWT_SECRET} OPENCLAW_MODEL_API_KEY: ${OPENCLAW_MODEL_API_KEY} OPENCLAW_DATABASE_URL: postgresql://openclaw:${POSTGRES_PASSWORD}db:5432/openclaw volumes: - ./data:/app/data ports: - 127.0.0.1:8080:8080 read_only: true tmpfs: - /tmp:size64m cap_drop: - ALL security_opt: - no-new-privileges:true pids_limit: 100 restart: unless-stopped depends_on: - db networks: - internal executor: image: openclaw/executor:latest user: 10001:10001 read_only: true cap_drop: - ALL security_opt: - no-new-privileges:true pids_limit: 50 tmpfs: - /tmp:size128m - /workspace:size512m networks: - internal db: image: postgres:16-alpine environment: POSTGRES_USER: openclaw POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} volumes: - ./dbdata:/var/lib/postgresql/data networks: - internal networks: internal: driver: bridge这份Compose的设计核心在几个细节上。core的端口只绑定127.0.0.1。宿主机上除了网关没有人可以直接访问core的8080端口。间接访问只能通过Nginx代理。就算你的防火墙配置失误把宿主端口暴露出去了最坏情况也只是一个仅限本机访问的通道攻击者无法直接远程横向移动。db和executor不映射任何宿主端口。数据库和沙箱都被关在内网桥接网络里外部完全不感知它们存在。这是最小暴露原则的落地体现。executor的workspace只在内存中。tmpfs挂载到/workspace运行时的临时文件全部写在内存容器一停数据和痕迹一起消失。说到这里也要提醒那份指南的建议是不要贸然把宿主机目录挂载到executor里。很多人喜欢让Agent直接访问宿主机的某个工作目录这在没有充分鉴权的前提下相当危险。Agent的每次工具调用都不可预测如果它执行了一条rm -rf /workspace/*你只会看到数据清空而这只是最简单的脚本而已。3.3 生成密钥并配置Nginx反向代理生成强度的建议很简单JWT秘密用openssl随机生成48字节十六进制数据库口令用base64随机生成18字符以上。不要自己拍脑袋想密码。openssl rand -hex 48 openssl rand -base64 18把这些输出保存到/opt/openclaw/.env文件并设置权限600chmod 600 /opt/openclaw/.envNginx部分只需要提供TLS终结和反向代理。下面是经过压缩的配置示例server { listen 80; server_name openclaw.example.com; return 301 https://$host$request_uri; } server { listen 443 ssl http2; server_name openclaw.example.com; ssl_certificate /etc/nginx/certs/fullchain.pem; ssl_certificate_key /etc/nginx/certs/privkey.pem; add_header X-Content-Type-Options nosniff; add_header X-Frame-Options DENY; location / { proxy_pass http://core:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; } }TLS证书申请和续期通过自动化工具完成这里不展开细说但有一点必须强调不要在Nginx配置里直接关闭TLS验证也不要为了图省事就裸用HTTP。你的API Key会在明文里到处跑这比配置难看的后果严重得多。3.4 一键拉起与安全自测一切就绪后启动docker compose up -d启动完成后不要急着用浏览器访问先做一轮安全自测每项都有明确预期。测试项操作预期结果鉴权是否落地不带Token访问core接口返回401而不是200容器是否非rootdocker inspect查看User字段不为空且不是0文件系统是否只读在core容器里touch /test返回Read-only file system端口是否最小暴露ss -tlnp查看监听端口宿主端口只有80和443沙箱是否隔离在Agent里执行ps aux看不到宿主进程列表前四项我一次性通过但第五项第一次踩了坑。默认镜像里executor虽然隔离了网络却因为用了root用户导致进程信息能跨容器看到一部分。改成非root之后这个问题才消失。这一点你验证时需要重点注意。4. 常见问题与排查实录4.1 我实际碰到的问题清单复现过程中我遇到了三个典型问题每一个都有明确的症状和解决方法。问题一容器始终以root运行。现象是docker inspect里User字段为空也就是没生效。原因很可能是镜像里的基础应用要求root权限或者压根没声明USER。解决方法是把Compose里的user字段显式写成10001:10001同时确保卷目录属主改好。如果应用确实需要写某些系统目录优先用tmpfs替代而不是放弃非root要求。问题二打开read_only后服务反复重启。这个问题的本质是应用把运行期的临时数据写到了镜像层目录比如/pkg/cache、/var/log这类地方。处理思路是看日志定位写哪了打开容器日志找到PermissionError对应的路径然后把这个路径改成卷挂载或tmpfs。注意不要图方便关read_only那是拆东墙补西墙。问题三外部访问页面超时。如果按上面方案部署core只监听127.0.0.1外部直接访问宿主IP的8080端口当然通不了这是预期行为。此时你需要确认Nginx容器启动正常、证书文件路径正确、proxy_pass指向的服务名可以解析。这类问题九成出在Nginx配置或证书路径不是OpenClaw本身。4.2 密钥已经泄露了怎么办有一次我在测试时故意模拟了密钥泄露场景在这里总结一下处理流程。首先立刻撤销并重新生成OpenClaw自己的API Key和JWT Secret这一步越快越好。然后到上游模型平台把模型服务的API Key也轮换掉因为Agent如果被控制模型额度只是被消耗的起点模型调用日志里可能存在业务相关信息。第三件事去网关层拉访问日志筛异常调用识别攻击者是否已经完成横向渗透。最后用docker history检查镜像中是否残留硬编码密钥如果残留镜像本身必须重新构建。密钥泄露后的核心原则就一条不要尝试只改一个Key所有关联凭据全部轮换。很多人在这一步省事结果一周后又出同样的问题。4.3 后续进一步加固的经验基础配置完成后我还根据自己的使用场景做了一些额外加固在这里一并列出。有条件的话给网关加一层WAF规则把常见的扫描流量直接拦截掉能有效降低日志噪音。虽然默认配置已经能挡住大多数攻击路径但WAF更多是减少被骚扰的频率不是安全雪中送炭的条件。对访问来源做IP白名单。如果你的OpenClaw只面向团队成员或办公网段这一步效果立竿见影。不管是内部还是外部使用建议在executor容器里绝对不要挂载宿主机的敏感目录比如/etc、/root这种路径一旦被Agent误操作后果无法挽回。最后每周做一次镜像安全扫描。Trivy这类工具能快速找出基础镜像里的CVE漏洞扫描结果建议和Compose文件一起纳入版本管理建立可追踪的安全基线。我在实际操作中的体会是OpenClaw这类Agent项目能力越强的功能对应攻击面越大。那份极简指南最聪明的地方就是把每一条安全配置都落在了“你到底在防什么”的层面上。部署时你最好也针对自己的场景重新过一遍威胁模型只是自己本地用127.0.0.1绑定就够如果是团队多人使用SSO、审计、配额都需要补充。安全没有一次性到位的配置只有持续维护的基线。希望这份极简骨架能帮你省下几个踩坑的夜晚。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →