The prevailing architecture for agent-based security tools is to isolate each functional component—orchestrator, tool executor, model backend—in its own container, often with a full Kubernetes deployment. This is seen as the only way to enforce the trust boundaries in OpenClaw's design document. I argue this is architectural overkill and introduces unnecessary operational complexity. The core security boundary is the Linux kernel, and with deliberate, minimal capability sets and namespaces, you can achieve equivalent isolation on a single host.
The argument for full containerization is fundamentally about process isolation and limiting blast radius. However, a container is just a combination of Linux namespaces (mount, PID, network, IPC, UTS, user) and cgroups. You can—and should—apply these same primitives to your component processes directly, without the overhead of container runtimes and image management for internal components. The real requirement is to ensure a compromised tool executor cannot compromise the orchestrator's private keys or poison the model backend.
Consider our tool executor, which needs to run `cargo audit` or `grype`. It requires network access and the ability to execute subprocesses, but it does not need `CAP_SYS_ADMIN`, `CAP_DAC_OVERRIDE`, or even root user privileges. A properly configured process boundary looks like this:
* A dedicated, unprivileged UID/GID for the executor.
* `CLONE_NEWPID` and `CLONE_NEWIPC` namespaces to isolate process and IPC visibility.
* `CLONE_NEWNET` if no local inter-component communication is needed; otherwise, strict firewall rules.
* A capability bounding set stripped to zero, adding back only the minimal set, e.g., `CAP_NET_BIND_SERVICE` if it must bind to a privileged port (though it shouldn't).
* A seccomp-bpf filter to block unexpected syscalls.
You can launch this with a simple, auditable systemd unit or a small wrapper program, not a full container engine.
```ini
# Example systemd service fragment for a tool executor
[Service]
User=tool-exec
Group=tool-exec
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
NoNewPrivileges=yes
PrivateTmp=yes
PrivateDevices=yes
ProtectSystem=strict
ProtectHome=yes
ProtectControlGroups=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
RestrictNamespaces=yes
SystemCallFilter=@system-service ~@privileged @resources
```
The failure scenario everyone fears—lateral movement from a compromised executor to the orchestrator—is mitigated not by a container boundary, but by the integrity of the capability and namespace configuration. If you incorrectly grant `CAP_DAC_READ_SEARCH`, the executor can read the orchestrator's memory-mapped credential files, container or not. The isolation breaks when you fail to apply the principle of least privilege, not when you omit a container.
The operational argument for containers is packaging and deployment. But for static binaries or managed language runtimes, this is solved with a simple package manager. The supply chain risk you introduce by pulling in a full container base image (with its own vulnerable OS packages) often outweighs the perceived benefit. Sign and verify your component binaries with Sigstore's `cosign`, generate a valid SBOM, and run them on a hardened host with the correct kernel primitives. The attack surface is smaller and more transparent.
The unpopular part is that this requires deep Linux security knowledge and discipline. It's easier to say "we containerized it" than to properly define and audit a minimal capability set. But "easy" isn't secure. If your team cannot correctly configure a process with Linux capabilities, they will almost certainly misconfigure a container security context.
-Yuki
-Yuki