From b76d54aae17e37ec0670b7495a3f2a24c1ee8c98 Mon Sep 17 00:00:00 2001 From: Yuxin Lou Date: Thu, 16 Jul 2026 20:52:13 +0800 Subject: [PATCH] Harden default Docker Compose security --- docker-compose.bwrap.yml | 16 ++++++++++++++++ docker-compose.yml | 5 ----- docs/configuration.md | 2 +- docs/deployment.md | 31 +++++++++++++++++++++++++------ 4 files changed, 42 insertions(+), 12 deletions(-) create mode 100644 docker-compose.bwrap.yml diff --git a/docker-compose.bwrap.yml b/docker-compose.bwrap.yml new file mode 100644 index 00000000..e67e5e0e --- /dev/null +++ b/docker-compose.bwrap.yml @@ -0,0 +1,16 @@ +x-bwrap-security: &bwrap-security + cap_add: + - SYS_ADMIN + security_opt: + - apparmor=unconfined + - seccomp=unconfined + +services: + nanobot-gateway: + <<: *bwrap-security + + nanobot-api: + <<: *bwrap-security + + nanobot-cli: + <<: *bwrap-security diff --git a/docker-compose.yml b/docker-compose.yml index f2e1e22a..4c2c0486 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,11 +6,6 @@ x-common-config: &common-config - ~/.nanobot:/home/nanobot/.nanobot cap_drop: - ALL - cap_add: - - SYS_ADMIN - security_opt: - - apparmor=unconfined - - seccomp=unconfined services: nanobot-gateway: diff --git a/docs/configuration.md b/docs/configuration.md index 9f7d9ce9..08408ffb 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1919,7 +1919,7 @@ For API keys, tokens, and other secrets, see [Environment Variables for Secrets] | `tools.ssrfWhitelist` | `[]` | CIDR ranges exempted from the shared SSRF guard used by web fetches and HTTP/SSE MCP connections. Prefer exact host CIDRs such as `192.168.1.50/32`; broad ranges increase SSRF exposure. | | `channels.*.allowFrom` | omitted | Access control per channel. Omit to use pairing-only mode; set `["*"]` to allow everyone; or list specific user IDs. See [Pairing](#pairing) for details. | -**Docker security**: The official Docker image runs as a non-root user (`nanobot`, UID 1000) with bubblewrap pre-installed. When using `docker-compose.yml`, the container drops all Linux capabilities except `SYS_ADMIN` (required for bwrap's namespace isolation). +**Docker security**: The official Docker image runs as a non-root user (`nanobot`, UID 1000) with bubblewrap pre-installed. The default `docker-compose.yml` drops all Linux capabilities and keeps Docker's default AppArmor/seccomp profiles enabled. If you enable `"tools.exec.sandbox": "bwrap"` inside Docker, start Compose with `docker-compose.bwrap.yml` as an additional override so bubblewrap can create nested namespaces. ## Pairing diff --git a/docs/deployment.md b/docs/deployment.md index f7565ade..9647e7af 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -74,6 +74,20 @@ docker compose logs -f nanobot-gateway # view logs docker compose down # stop ``` +The default Compose file drops all Linux capabilities and keeps Docker's default +AppArmor/seccomp profiles enabled. If you explicitly set +`"tools.exec.sandbox": "bwrap"` in `~/.nanobot/config.json`, add the bwrap +override file when starting containers: + +```bash +docker compose -f docker-compose.yml -f docker-compose.bwrap.yml up -d nanobot-gateway +docker compose -f docker-compose.yml -f docker-compose.bwrap.yml run --rm nanobot-cli agent -m "Hello!" +``` + +The override grants `CAP_SYS_ADMIN` and disables AppArmor/seccomp confinement for +the container so bubblewrap can create its nested namespaces. Use it only when the +bwrap sandbox is enabled. + ### Docker ```bash @@ -87,12 +101,17 @@ docker run -v ~/.nanobot:/home/nanobot/.nanobot --rm nanobot onboard vim ~/.nanobot/config.json # Run gateway (connects to enabled channels, e.g. Telegram/Discord/Mochat). -# Mirrors the security caps and port mappings declared in docker-compose.yml: -# - `--cap-drop ALL --cap-add SYS_ADMIN` + unconfined apparmor/seccomp are required -# when `tools.exec.sandbox: "bwrap"` is enabled (bwrap needs CAP_SYS_ADMIN for -# user namespaces). Without them, `bwrap` exits with `clone3: Operation not permitted`. -# - `-p 8765:8765` exposes the WebSocket channel / WebUI alongside the gateway health -# endpoint on 18790. +# `-p 8765:8765` exposes the WebSocket channel / WebUI alongside the gateway +# health endpoint on 18790. +docker run \ + --cap-drop ALL \ + -v ~/.nanobot:/home/nanobot/.nanobot \ + -p 18790:18790 -p 8765:8765 \ + nanobot gateway + +# If `tools.exec.sandbox: "bwrap"` is enabled, run with the extra permissions +# bubblewrap needs for nested namespaces. Without them, `bwrap` may exit with +# `clone3: Operation not permitted`. docker run \ --cap-drop ALL --cap-add SYS_ADMIN \ --security-opt apparmor=unconfined \