docs(runtime): document hardening contract and runtime override (#152)

Surfaces the multi-tenant container hardening contract introduced in the
prior commit so operators and integrators know what is enforced and why.

- application.yml: declare `cameleer.server.runtime.dockerruntime`
  alongside the other runtime properties (empty = auto-detect runsc).
- HOWTO.md: add the override row to the Runtime config table.
- SERVER-CAPABILITIES.md: new "Multi-Tenant Runtime Sandboxing" section
  describing the cap_drop, no-new-privileges, AppArmor, read-only rootfs,
  pids_limit, /tmp tmpfs, and runsc auto-detect contract — plus the
  on-disk state caveat that motivates issue #153.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-25 21:06:10 +02:00
parent 8e9ad47077
commit f6b76b2d5e
3 changed files with 24 additions and 0 deletions

View File

@@ -34,6 +34,24 @@ Each server instance serves exactly one tenant. Multiple tenants share infrastru
---
## Multi-Tenant Runtime Sandboxing
When the server orchestrates tenant containers (SaaS / managed mode), every container is launched with an unconditional hardening contract — Java 17 has no `SecurityManager`, so isolation must live below the JVM. Camel ships components that turn a header into shell (`camel-exec`, `camel-bean`, `camel-groovy`, `camel-mvel`, `camel-velocity`), so tenant JARs are treated as hostile by default.
| Layer | What is enforced |
|---|---|
| Capabilities | `cap_drop` every Linux capability the SDK enumerates (effectively ALL — outbound TCP needs none). |
| Privilege escalation | `no-new-privileges` — setuid binaries cannot escalate. |
| MAC profile | `apparmor=docker-default`. The Docker daemon's default seccomp profile is applied implicitly. |
| Filesystem | `read_only` rootfs. `/tmp` is a 256m tmpfs (`rw,nosuid``noexec` is intentionally **not** set so JNI native libs from Netty/Snappy/LZ4/Zstd can `dlopen`). |
| Resource caps | `pids_limit=512` per container; CPU and memory limits per tenant config. |
| Container runtime | Auto-detects gVisor (`runsc`) via `docker info` and uses it when registered with the daemon. Override with `CAMELEER_SERVER_RUNTIME_DOCKERRUNTIME` (e.g. `kata`, or `runc` to force the default). |
| Network | Per-tenant Docker bridge `cameleer-tenant-{slug}` + per-env discovery network `cameleer-env-{tenantId}-{envSlug}`. Tenants cannot reach each other's containers. |
**Implication for tenants writing on-disk state**: with `read_only` rootfs, anything that needs durable disk (Kafka Streams RocksDB stores, Hibernate L2 cache, log files outside stdout) must be on a writeable volume. Per-app `containerConfig.writeableVolumes` support is tracked separately — see issue #153.
---
## Agent Protocol
### Lifecycle