feat(manifest): add allow-listed per-netns sysctls primitive
Routing apps (a rootless VPN exit) need packet forwarding in their own network namespace, but /proc/sys is read-only inside a rootless container, so it can only be set at create time. Add `app.sysctls`, allow-listed to net.ipv4.ip_forward / net.ipv6.conf.all.forwarding with values "0"/"1", and rejected under host networking where it would change the host. Rendered on all three create paths: podman CLI --sysctl, the libpod spec `sysctl` map, and Quadlet `Sysctl=`. Absent by default and not serialized when empty, so existing manifests and units are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -35,6 +35,7 @@ As of the current `1.8-alpha` workstream:
|
||||
- Manifest-owned generated files exist through `app.files` and have been used for app config material (e.g. strfry, netbird config regeneration).
|
||||
- Local image builds are represented with `container.build`; pulled images are represented with `container.image`.
|
||||
- Data ownership repair is represented with `container.data_uid`.
|
||||
- Per-app network-namespace kernel parameters are represented with `app.sysctls`, allow-listed to packet forwarding (added for rootless VPN exits such as nostr-vpn).
|
||||
- Derived host facts and secret-file-backed environment variables are represented with `container.derived_env` and `container.secret_env`.
|
||||
- Catalog metadata generation is implemented by `scripts/generate-app-catalog.py`.
|
||||
- App-session launch ports/titles and new-tab launch behavior now have a generated TypeScript metadata path from manifests, with manual overrides preserved for companion UIs and aliases that do not have manifest-owned metadata yet.
|
||||
|
||||
@@ -124,6 +124,7 @@ app:
|
||||
| `app.environment` | Static `KEY=value` environment entries |
|
||||
| `app.health_check` | HTTP or TCP health check settings |
|
||||
| `app.devices` | Explicit device paths |
|
||||
| `app.sysctls` | Namespaced packet-forwarding sysctls for the app's own network namespace (allow-listed; not with host networking) |
|
||||
| `app.metadata` | Catalog-facing presentation metadata such as icon, category, tier, repo/source, author, feature bullets, and [launch hints](#browser-iframe-and-companion-launch-modes) |
|
||||
| `app.interfaces.main` | Optional primary UI launch surface with `port`, `protocol`, and `path` |
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@ because a wrong source produces a confident wrong verdict.
|
||||
| `environment` | list of string | — | `- KEY=value` pairs (static). |
|
||||
| `health_check` | HealthCheck | — | `{ type, endpoint/path, interval, timeout, retries }`. `type` is free-form today; `http` is what the monitor exercises. |
|
||||
| `devices` | list of string | — | Host device paths; must start with `/dev/`. |
|
||||
| `sysctls` | map | — | Kernel parameters for the app's **own** network namespace (podman `--sysctl`, Quadlet `Sysctl=`). Allow-list: `net.ipv4.ip_forward`, `net.ipv6.conf.all.forwarding`; values `"0"`/`"1"`. Rejected under host networking. Needed by routing apps because rootless `/proc/sys` is read-only inside the container. |
|
||||
| `interfaces` | map | — | Launch surfaces, keyed by name (`main`): `{ name, description, type, port, protocol, path }`. |
|
||||
| `hooks` | LifecycleHooks | — | Allow-listed lifecycle hooks. See [Hooks](#hooks). |
|
||||
| `upstream` | UpstreamSource | — | Where the app comes from, so release tooling can tell when the pin has fallen behind. See [Upstream tracking](#upstream-tracking). |
|
||||
@@ -116,6 +117,9 @@ Validation (enforced at `AppManifest::validate()`):
|
||||
FOWNER, NET_ADMIN, NET_BIND_SERVICE, NET_RAW, SETGID, SETUID, SYS_ADMIN).
|
||||
- `network_policy` must be exactly `isolated`, `bridge`, or `host`.
|
||||
- No `container:`/`ns:` network modes; devices must be `/dev/*`.
|
||||
- `sysctls` keys must be on `ALLOWED_SYSCTLS` (packet forwarding only) and
|
||||
need the app's own network namespace — never host networking, where they
|
||||
would change the host.
|
||||
- Bind-mount sources are confined to `/var/lib/archipelago` (reviewed
|
||||
exceptions: the rootless podman socket and dbus).
|
||||
- `derived_env` templates may only use the placeholder allow-list;
|
||||
|
||||
@@ -43,6 +43,8 @@ PublishPort=<bind>:<host>:<container>/<proto>
|
||||
Environment=<KEY>=<value> # non-secret env only
|
||||
Secret=<secret_name>,type=env,target=<KEY> # secrets by REFERENCE, never value
|
||||
Volume=<source>:<target><opts>
|
||||
AddDevice=<path> # manifest devices
|
||||
Sysctl=<key>=<value> # manifest sysctls (own netns, allow-listed)
|
||||
ReadOnly=true # when security.readonly_root
|
||||
NoNewPrivileges=true # when security.no_new_privileges
|
||||
HealthCmd=<cmd> # from the health_check block
|
||||
|
||||
Reference in New Issue
Block a user