-
Notifications
You must be signed in to change notification settings - Fork 7
Latest commit
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
ronly — read-only sandbox for untrustworthy agents Drop into a shell session where everything looks normal but destructive operations are blocked at the kernel level. Linux only. Runs rootless via user namespaces on any kernel 4.6+ (Debian 11+, RHEL 8+, Ubuntu 16.04+). Falls back to privileged mode if user namespaces are unavailable. $ kubectl exec -it debug-pod -- ronly ronly: using user namespaces (--rootless) root@debug-pod:~# top -bn1 | head -5 top - 14:23:01 up 42 days, load average: 2.31, 1.87 Tasks: 312 total, 1 running, 311 sleeping %Cpu(s): 8.3 us, 2.1 sy, 0.0 ni, 89.1 id MiB Mem: 32168.0 total, 12042.3 free root@debug-pod:~# cat /var/log/syslog | grep error Mar 24 09:14:02 prod payment-svc: connection error root@debug-pod:~# rm /etc/hosts rm: cannot remove '/etc/hosts': Read-only file system root@debug-pod:~# kill 1 bash: kill: (1) - Operation not permitted root@debug-pod:~# docker run nginx ronly: docker run is blocked (read-only session) HOW IT WORKS 1. Read-only filesystem — mount namespace with root bind-mounted read-only. Writes fail with EROFS. Writable tmpfs at /tmp for scratch space. 2. seccomp-bpf — blocks kill, unlink, rename, truncate, mount, reboot. ptrace write ops blocked but read ops allowed (so strace works). ps, top, and /proc show real host processes — kill is blocked by seccomp. 3. Tool shims — ronly copies itself into /tmp under names like "docker" and "kubectl" (one copy, rest are hard links) and prepends that dir to PATH. The shell finds the shim, ronly checks argv[0], and either execs the real binary (read-only subcommands) or exits with an error (write subcommands). Network is not restricted. The agent can make outbound connections. Layer your own network policy if exfiltration is a concern. USAGE ronly [OPTIONS] [COMMAND...] With no arguments, execs $SHELL (or /bin/bash). --rootless force rootless mode (user namespaces) --privileged force privileged mode (requires root) --tmpfs-size SIZE writable /tmp size (default: 64M) --extra-shims DIR additional shim directory --no-shims disable all shims --no-network disable all network access (CLONE_NEWNET) --writable PATH empty writable tmpfs at PATH --help show this help --version show version Two modes exist because not all environments support both. Rootless works on most modern kernels without root, but some hardened systems and container runtimes disable user namespaces. Privileged mode covers those cases. By default ronly tries rootless first and falls back to privileged. It prints which mode it's using to stderr. BUILT-IN SHIMS Some tools talk to sockets/APIs rather than the filesystem, so a read-only mount alone doesn't stop them. docker — ps, logs, inspect, stats, top, images, info, version, events, diff, network ls/inspect, volume ls/inspect kubectl — get, describe, logs, top, explain, version, cluster-info, api-resources, api-versions, config view/current-context/get-contexts, auth can-i/whoami Everything not listed is blocked. Add custom shims with --extra-shims DIR.
About
Resources
Stars
165 stars
Watchers
0 watching