跳转到内容

在 Olivares 下运行 Claude Code(联合部署)

这是 Anthropic 优先这一叙事中的 Operate(操作) 那一半:不仅观察治理 Claude Code, 还要指挥它。控制平面启动一个真实的 claude 进程,将其 I/O 桥接为受治理的流,将每一次生命周期 转换锚定在审计账本中,并将其拆除——在一个共享工作区之上,从 API/CLI(以及后续的门户)进行, 无需 SSH。本页在一台 Linux 主机上以四种拓扑联合部署这两半,默认安全。

关于协作式观察路径(OTLP 遥测 → access map),见 连接 Claude Code;关于治理路径(将 PreToolUse 钩子用作 PEP), 见 govern-claude-code 示例。 本页讲的是联合部署:让两个运行时一起跑起来。

  1. 可选启用(Opt-in)。 Olivares 基础镜像是 distroless 的,且不携带 claude。 Operate-Claude-Code 层是一个独立的工件——一个组合镜像 (Dockerfile.agentops)或一个原生安装附加项。如果你不运行受治理的 Claude Code,就永远不会拉取它, 它额外的攻击面也永远不会触及你的控制平面。
  2. 官方来源,绝不二次分发。 Anthropic 的条款不允许二次分发 claude 二进制文件,因此我们 从 Anthropic 官方的、经 GPG 签名的来源在构建/首次运行时安装它(签名的 apt/dnf/apk 仓库), 做了固定(pin)并禁用了自动更新器。我们不附带任何第三方二进制文件。你也可以 自带(BYO) claude 并让引擎指向它。
#OlivaresClaude Code引擎如何指挥它状态
1DockerDocker同一容器(组合镜像),procRunner 子进程推荐(与 2 相同的受治理路径)
2原生原生同一主机(systemd),procRunner 子进程推荐,已做端到端冒烟测试
3Docker原生(主机)跨命名空间——按现状无法治理改为同址部署(见下文)
4原生Docker(每会话)通过 Docker API 的每会话容器后续工作(已记录)

两种同址(co-located)拓扑(1、2)是安全的默认选项。拓扑 2(原生)由 scripts/smoke-agentops.sh 做了端到端测试;拓扑 1 复用同一条受治理的 procRunner 路径(组合镜像的构建/运行尚未接入自动化测试)。 拓扑 3 和 4 要求治理者与被治理者位于不同的容器中;跨该边界桥接 stdio 需要 Docker-API 访问权限 (这是引擎默认有意获取的特权)。它们诚实的路径在 混合拓扑 中阐明。


拓扑 1 — 两者都在 Docker 中(推荐)

Section titled “拓扑 1 — 两者都在 Docker 中(推荐)”

一个经过加固的容器同时运行引擎 claude;一个工作区卷作为共享的工作目录。仅回环、非 root、 只读根文件系统——与基础 compose 完全相同的姿态,外加被指挥的运行时。

claude 在构建时从 Anthropic 的签名 apt 仓库安装,签名密钥指纹被固定 (31DD DE24 DDFA B679 F42D 7BD2 BAA9 29FF 1A7E CACE)且禁用自动更新。先按摘要固定引擎基础镜像并验证它:

Terminal window
# verify the engine image you build FROM (it is cosign-signed)
cosign verify docker.io/olivaresai/olivares:26.8.0 \
--certificate-identity-regexp '^https://github\.com/olivaresai/olivares/\.github/workflows/release\.yml@refs/tags/v[0-9]+\.[0-9]+\.[0-9]+$' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
docker build -f Dockerfile.agentops \
--build-arg OLIVARES_IMAGE=docker.io/olivaresai/olivares@sha256:<digest> \
--build-arg CLAUDE_CHANNEL=stable \
-t olivares-agentops:26.8.0 .

也可改用 --build-arg CLAUDE_INSTALL=byo 自带 claude(镜像不携带 claude;在运行时挂载你自己的, 并设置 OLIVARES_SESSION_RUNTIME_CLAUDE_BIN)。

Terminal window
export OLIVARES_AGENTOPS_IMAGE=olivares-agentops:26.8.0
docker compose -f deploy/compose/docker-compose.yml \
-f deploy/compose/docker-compose.agentops.yml up -d

该 override 只改动 Operate 所需的部分:组合镜像、四个可写卷 (引擎数据、工作区、claude 的 ~/.claude 主目录、短期推理令牌),以及会话运行时环境变量。 其余一切——绑定到 127.0.0.1 的端口、uid 65532、read_only 根、cap_drop: ALLno-new-privileges——都从基础配置继承。


拓扑 2 — 两者都原生(无 Docker)

Section titled “拓扑 2 — 两者都原生(无 Docker)”

引擎与 claude 都在主机上;systemd 运行引擎,由引擎指挥 claude。工作区位于 /var/lib/olivares/workspaces

Terminal window
curl -fsSL https://raw.githubusercontent.com/olivaresai/olivares/main/scripts/install-agentops.sh | sh

它会自动检测原生拓扑,安装经过验证的引擎二进制文件(受 cosign 关卡控制的 install.sh), 从签名的 apt/dnf/apk 仓库安装 claude(带密钥指纹验证——或用 OLIVARES_CLAUDE_INSTALL=byo 跳过), 创建无登录权限的 olivares 服务用户和工作区目录,并放入经过加固的 systemd override + 环境变量示例。 它不会自动启动治理平面——是否运行由你明确决定。

安装程序接入了什么(以及为什么)

Section titled “安装程序接入了什么(以及为什么)”
  • packaging/systemd/olivares.service.d/agentops.conf —— 一个 drop-in,为被指挥的 claude 提供一个可写的 HOME 用于 ~/.claude(保留在 /var/lib/olivares 之下,因此 ProtectHome=true 仍保护真实用户),确保工作区目录存在,并仅放开一项沙箱属性:MemoryDenyWriteExecuteclaude 运行时会做 JIT 编译,需要 W→X 内存)。基础单元中的所有其他加固指令依然有效。
  • /etc/olivares/agentops.env —— 会话运行时配置(令牌文件、TTL、可选的网关基础 URL、 可选的自带 claude 路径)。

随后,刻意地:

Terminal window
sudo nano /etc/olivares/agentops.env # wire the short-lived inference token (refresher)
sudo systemctl enable --now olivares # loopback-only by default

在任一同址拓扑中步骤相同。对 CLI 进行认证,注册共享工作区,启动:

Terminal window
export OLIVARES_SERVER_URL=https://127.0.0.1:8443
export OLIVARES_TOKEN=<your-api-token>
export OLIVARES_TENANT=<your-tenant-id>
# 1) register the shared workspace (the session's working dir; jailed file API on top)
olivares agent workspace add /var/lib/olivares/workspaces/project-x --name project-x --mode rw
# 2) launch a governed session over the stream-json transport
olivares agent session create --transport stream-json \
--permission-mode acceptEdits --model opus \
--workspace <workspace-ref> --isolation native
# 3) attach to its live, bridged I/O (lossless replay from a cursor); send input; stop
olivares agent session attach <run-ref>
olivares agent session input <run-ref> --line '{"type":"user","message":{"role":"user","content":"…"}}'
olivares agent session stop <run-ref>

每一次转换(created → launched → … → stopped)都被锚定在签名的审计账本中olivares agent session events <run-ref>);工作区文件 API (olivares agent workspace files|get|put|…)受 jail 限制并被审计。这一切的可复现性契约是 scripts/smoke-agentops.sh, 它对一个隔离的伪造 claude 拉起原生联合部署,并断言会话端到端可被治理。


这两种拓扑将治理者与被治理者跨容器边界拆分开。要清醒地认识其代价。

拓扑 3 — Olivares 在 Docker 中,Claude 在主机上

Section titled “拓扑 3 — Olivares 在 Docker 中,Claude 在主机上”

不存在干净的受治理路径:容器化的引擎无法掌握主机命名空间中某个进程的 stdio,而受治理的传输是 stdio。 要触及主机上的 claude 就得共享主机 PID 命名空间并把挂载映射进引擎容器——这是一次范围很大、刻意为之的 去隔离,违背了把引擎封装起来的初衷。请改为同址部署:把两者都放进组合镜像(那就是拓扑 1), 或都原生运行(拓扑 2)。这是一个真实的限制,是被明说出来而非被掩盖的。

拓扑 4 — Olivares 原生,Claude 在每会话容器中

Section titled “拓扑 4 — Olivares 原生,Claude 在每会话容器中”

这是每会话全新容器隔离的天然归宿:每个会话都获得一个全新的、经过加固的 claude 容器 (工作区 bind 挂载、只读根、非 root、cap-drop),由引擎通过 Docker API 创建并拆除,stdio 经由 Docker attach/hijack 桥接。数据模型接缝已经建模了它(--isolation container 是一个有效值, 而它将要消费的执行器挂载原语已经交付)——但其背后的 runner 尚未接入,因此原生 runner 今天会拒绝该值 (见上文的提示)。

这是一项已记录的后续工作,并未在本次发布中交付。 驱动同级容器意味着授予引擎 Docker-API 访问权限 (理想情况下通过一个最小权限的 socket 代理)——本次发布有意回避的一个信任面,转而采用无 socket 的组合镜像。 选择这一拓扑就是选择更强的治理者/被治理者隔离,代价是那项 Docker-API 授权;它将在现有的 isolation=container 接缝之后到来。在那之前,安全的默认选项是同址部署。


  • 默认仅回环。 主机端口仅在 127.0.0.1 上发布。在容器中,引擎在容器内部监听 0.0.0.0, 因此主机端口映射才是暴露边界——在没有你自己的 TLS 终结认证代理的情况下,绝不要把它发布到非回环的 主机地址上。原生/systemd 的默认绑定是回环。要刻意地暴露。
  • 非 root,最小权限。 uid/gid 65532、只读根文件系统、cap_drop: ALLno-new-privileges(Docker)/ 完整的 Protect*/Restrict* 集合,减去那一项已记录的 W^X 放宽(systemd)。
  • 最小数据、白名单环境。 子进程 claude 仅继承一个明确的白名单(PATH、HOME、locale……)外加内存中的 推理令牌——没有 OLIVARES_* 签名密钥,没有可能遮蔽所铸造凭据的环境态 ANTHROPIC_*/CLAUDE_CODE_*
  • 经过验证的供应链。 引擎经 cosign 签名(验证它 / 按摘要固定);claude 从 Anthropic 的签名仓库安装, 密钥指纹被固定。安装程序拒绝运行未经验证的引擎,除非你显式选择退出。
  • 锚定的审计。 每一次生命周期转换和每一次工作区变更都通过 PayloadHash 被封存在哈希链式(hash-chained)、 签名的账本中——文件的字节与帧的内容从不被持久化。