diff --git a/README.md b/README.md index 20b760c..5f0fe1c 100644 --- a/README.md +++ b/README.md @@ -313,7 +313,9 @@ exec chpst -u app:app /usr/local/bin/app \ - Port 8080 is the only one the app must leave free: the health check, the metrics and ban management are all on it, under `/_smallwebwaf/`. The image's health check passes while `smallwebwaf` answers and the app accepts - connections. + connections. `SWWAF_LISTEN_ADDR` can move `smallwebwaf` to another port, which + the app then leaves free instead; the health check follows it, and traefik's + labels must point at it. - `smallwebwaf` keeps its state files in `/var/lib/smallwebwaf`. Mount a volume there to keep bans and client history when a deploy replaces the container; without one, it still starts. diff --git a/SPEC.md b/SPEC.md index 918ed49..ecdb974 100644 --- a/SPEC.md +++ b/SPEC.md @@ -1170,8 +1170,9 @@ The image holds: - The `smallwebwaf` binary, and a user of its own, `smallwebwaf` (uid and gid 65532). - The service directory `/etc/service/smallwebwaf`, whose `run` script waits one - second (`sleep 1`), makes `SWWAF_STATE_DIR` belong to the `smallwebwaf` user, - and starts `smallwebwaf` as that user with runit's `chpst`. + second (`sleep 1`), makes `SWWAF_STATE_DIR` and every file in it belong to the + `smallwebwaf` user, and starts `smallwebwaf` as that user with runit's + `chpst`. - The directory `/var/lib/smallwebwaf` for the state files, and `/etc/smallwebwaf/rules.d` with the default rule file (see "Rule files"). - Port 8080 declared (`EXPOSE 8080`), and the health check described below @@ -1261,18 +1262,21 @@ The two processes: status into its directory under `/etc/service`. The health check: the image's `HEALTHCHECK` passes while `smallwebwaf` answers -`GET /_smallwebwaf/healthz` on `127.0.0.1:8080` and the app accepts connections -at the address in `SWWAF_UPSTREAM_URL`, and fails when either does not. The -container therefore shows as healthy only while both processes are up. An app -with a health check of its own can replace the image's `HEALTHCHECK` with one -that checks both. +`GET /_smallwebwaf/healthz` on `127.0.0.1`, at the port in `SWWAF_LISTEN_ADDR`, +and the app accepts connections at the address in `SWWAF_UPSTREAM_URL`, and +fails when either does not. The container therefore shows as healthy only while +both processes are up. An app with a health check of its own can replace the +image's `HEALTHCHECK` with one that checks both. Ports: `smallwebwaf` listens on port 8080 on every address and on no other port; its health check, metrics and ban management are all on that listener, under -`/_smallwebwaf/` (see "Admin endpoints"). The app must leave port 8080 free. It -listens on `127.0.0.1:8081` only, so that nothing outside the container reaches -it except through `smallwebwaf`: an app that listens on every address can be -reached around `smallwebwaf` by anything that reaches the container. +`/_smallwebwaf/` (see "Admin endpoints"). `SWWAF_LISTEN_ADDR` may set another +port: the image's health check takes its port from that setting, and traefik's +port label (`traefik.http.services..loadbalancer.server.port`) must name +the same port. The app must leave that port free. It listens on `127.0.0.1:8081` +only, so that nothing outside the container reaches it except through +`smallwebwaf`: an app that listens on every address can be reached around +`smallwebwaf` by anything that reaches the container. State: `smallwebwaf` keeps its state files in `/var/lib/smallwebwaf` (`SWWAF_STATE_DIR`), a directory of its own beside the app's data, which the app @@ -1280,13 +1284,21 @@ keeps in directories of its own, such as `/var/lib/app`. Without a volume there, the files live in the container: they survive a restart of the container and are lost when a deploy replaces it. A volume mounted at `/var/lib/smallwebwaf`, named or a host directory, keeps them across deploys; the `run` script of -`smallwebwaf` makes it belong to the `smallwebwaf` user, so a host directory -mounted there needs no change of owner. It is a volume of its own, separate from -the app's, holds a few tens of MiB at most with the defaults (see "Persistent -state"), and needs no backup beyond whatever the host already does. The image -declares no volume, since every app image built on it would inherit it. -Milestone 2 (https://git.eeqj.de/sneak/smallwebwaf/issues/14) writes no state -files and needs no volume. +`smallwebwaf` makes it and every file in it belong to the `smallwebwaf` user, so +a host directory mounted there needs no change of owner, and files an earlier +owner left in it can be read and replaced. It is a volume of its own, separate +from the app's, holds a few tens of MiB at most with the defaults (see +"Persistent state"), and needs no backup beyond whatever the host already does. +The image declares no volume, since every app image built on it would inherit +it. Milestone 2 (https://git.eeqj.de/sneak/smallwebwaf/issues/14) writes no +state files and needs no volume. + +Tokens: a token given as a file (`SWWAF_ADMIN_TOKEN_FILE`, +`SWWAF_METRICS_TOKEN_FILE`) is out of the app's reach only while the +`smallwebwaf` user alone can read the file. The operator makes the file on the +host, owned by uid 65532, the `smallwebwaf` user, with mode `0400`, and mounts +the directory that holds it into the container read-only; the container sees the +same owner and mode. Forwarded headers: the app's TCP peer is `smallwebwaf` on `127.0.0.1`, and the `X-Forwarded-For` the app receives ends with traefik's address, which @@ -1305,7 +1317,8 @@ and runs the one container as it runs any app, with the app's traefik labels, environment variables and volumes. The labels route to port 8080 (`traefik.http.services..loadbalancer.server.port=8080`), any `SWWAF_` settings go with the app's environment variables, and the volume for -`/var/lib/smallwebwaf` goes beside the app's own. +`/var/lib/smallwebwaf` goes beside the app's own, as does the directory that +holds any token file. - The endpoints of `smallwebwaf` are reached through traefik like any other request, for example `https://app.example.invalid/_smallwebwaf/metrics` for a @@ -1504,7 +1517,7 @@ settings go with the app's environment variables, and the volume for stops the start. The app starts with the same environment variables as `smallwebwaf`, so it can read a token given as one; a token given as a file that only the `smallwebwaf` user can read (`SWWAF_ADMIN_TOKEN_FILE`, - `SWWAF_METRICS_TOKEN_FILE`) is out of the app's reach. + `SWWAF_METRICS_TOKEN_FILE`) is out of the app's reach (see "Deployment"). - GeoJS, the default lookup source: every new visitor's address goes to a third party, and a swarm of fresh addresses, when lookups peak, is when GeoJS may slow down or block `smallwebwaf`. Keeping answers for 7 days and asking about