I've been running OpenClaw's components in separate VMs on a Proxmox cluster, but I wanted to tighten things up further at the container level. The orchestrator and tool executor are the two components that *really* shouldn't have the same level of system access. While network segmentation is your first line of defense, seccomp-bpf is a solid last-ditch filter for syscalls.
Here's my approach for creating restrictive seccomp profiles for each component. The goal is to block any syscall that isn't strictly necessary for their operation, reducing the attack surface if one gets compromised.
**Orchestrator Profile (openclaw-orchestrator.json)**
The orchestrator mainly needs to talk to the network, manage some in-memory state, and spawn the tool executor. It doesn't need filesystem writes outside its own logs.
```json
{
"defaultAction": "SCMP_ACT_ERRNO",
"architectures": ["SCMP_ARCH_X86_64"],
"syscalls": [
{"names": ["epoll_wait", "accept", "read", "write"], "action": "SCMP_ACT_ALLOW"},
{"names": ["socket", "connect", "bind", "listen"], "action": "SCMP_ACT_ALLOW"},
{"names": ["clone", "waitpid", "kill"], "action": "SCMP_ACT_ALLOW"},
{"names": ["brk", "mmap", "munmap", "mprotect"], "action": "SCMP_ACT_ALLOW"},
{"names": ["clock_gettime", "getpid", "gettid"], "action": "SCMP_ACT_ALLOW"}
]
}
```
Key restrictions here: no `execve` (it shouldn't be executing random binaries), no `ptrace`, no `setuid` families.
**Tool Executor Profile (openclaw-tool-executor.json)**
This one is trickier. It needs to execute various tools (like `curl`, `nmap` in the security context) via subprocesses, which requires `execve`. But we can heavily restrict what it does afterwards.
```json
{
"defaultAction": "SCMP_ACT_ERRNO",
"architectures": ["SCMP_ARCH_X86_64"],
"syscalls": [
{"names": ["execve", "wait4", "clone"], "action": "SCMP_ACT_ALLOW"},
{"names": ["read", "write", "open", "close", "fstat"], "action": "SCMP_ACT_ALLOW"},
{"names": ["socket", "connect", "getpeername", "getsockname"], "action": "SCMP_ACT_ALLOW"},
{"names": ["brk", "mmap", "munmap"], "action": "SCMP_ACT_ALLOW"},
{"names": ["getuid", "getgid", "getpid", "arch_prctl"], "action": "SCMP_ACT_ALLOW"}
]
}
```
Notably, I'm blocking `ptrace`, `personality`, `setns`, and `unshare`. The tool executor shouldn't be modifying namespaces or debugging other processes.
**Deployment Notes**
* Apply these with Docker using `--security-opt seccomp=/path/to/profile.json`.
* In Kubernetes, use the `seccompProfile` field in your Pod securityContext.
* **Test thoroughly!** Start with an audit (`SCMP_ACT_LOG`) to catch any missing syscalls for your specific toolset before moving to `SCMP_ACT_ERRNO`. A blocked syscall will manifest as a cryptic permission error.
The boundary between these two components is critical. If the orchestrator is compromised, you don't want it to be able to spawn a shell. If the tool executor is compromised, you want to limit its ability to escalate or pivot. These profiles are a baseline—you'll need to adjust based on the specific tools you're allowing the executor to run.
Has anyone else built similar profiles? I'm particularly curious about handling edge cases where a tool (like a network scanner) needs a more unusual syscall.
-- Ray
Self-host or die.