From 8282404453bd0bf9555d9927c0ac1263958ac34e Mon Sep 17 00:00:00 2001 From: sneak Date: Mon, 26 Oct 2026 00:37:38 +0000 Subject: [PATCH] Seventh review: false statements fixed, README shortened to link the spec - Engine error handling dropped as not built; unknown country and AS number each on its own; observe mode makes no ban of its own. - README no longer restates the request steps, the refusal answers or the design; its step list uses the spec's numbers. - Repeats, misreadable sentences, late verbs and long sentences reworded as the review asks. Model: fable-5-1 --- README.md | 183 ++++++++++++++--------------------------------- SPEC.md | 112 +++++++++++++++-------------- docs/settings.md | 3 +- 3 files changed, 114 insertions(+), 184 deletions(-) diff --git a/README.md b/README.md index 83adf48..4aecf31 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,7 @@ scanners and other abusers before they reach the app. A web application firewall reads each request on its way to a web app and refuses the ones that look like abuse. `smallwebwaf` is also a reverse proxy: it accepts requests on the app's behalf, passes them to the app, and passes the -app's answers back. A request it does not refuse reaches the app as it came, -apart from a few headers (see "Design" below). +app's answers back. It needs no setting. Every setting has a default chosen for a service on the open internet. [`SPEC.md`](SPEC.md) says how `smallwebwaf` behaves and why. The @@ -30,8 +29,8 @@ reference documents under [`docs/`](docs/) are listed under "Documents" below. of your own, or an entry in `SWWAF_TRAP_PATHS`, bans those the same way. - Attacks carried in a request's URL or headers, such as SQL injection and path traversal. The OWASP Core Rule Set is a published set of rules that recognise - common web attacks. Coraza, a Go engine, runs those rules (step 11 under "What - happens to a request" below). A request the rules take for an attack is + common web attacks. Coraza, a Go engine, runs those rules (see "Attack + detection" in [`SPEC.md`](SPEC.md)). A request the rules take for an attack is refused. - Abuse from networks and countries you do not want. You can: - refuse whole netblocks and countries; @@ -142,89 +141,32 @@ while working on it, see "Entrypoints" below. ## What happens to a request -Two terms recur below. A clear sign of attack is a request that matches a rule -whose action is `ban`, or asks for a trap path (steps 9 and 10). An offence is a -request that counts against its client in its history. It is one of: +`smallwebwaf` handles each request in fifteen steps, in this order. Once a step +refuses a request, the steps after it are skipped, apart from step 15, and +nothing of the request reaches the app. "What happens to a request" in +[`SPEC.md`](SPEC.md) gives each step in full, under the same numbers. -- a clear sign of attack; -- a broken limit; -- a refusal by a rule, by the Core Rule Set or for a missing or wrong token. +1. The health check, `GET /_smallwebwaf/healthz`, is answered at once. +2. The client is identified. +3. The static lists, `SWWAF_ALLOW_NETS` and `SWWAF_DENY_NETS`. +4. The bans. +5. The lookup of the client's AS number and country. +6. The country lists. +7. The reputation sources. +8. The client's limit percentage. +9. The rate limits. +10. The trap paths. +11. The rule files. +12. The Core Rule Set. +13. `smallwebwaf`'s own endpoints, under `/_smallwebwaf/`. +14. The request is passed to the app. +15. After the answer: the byte limits, the error burst and the client's history. -`smallwebwaf` handles each request in this order. Once a step refuses a request, -the steps after it are skipped, apart from step 13. Nothing of a refused request -reaches the app. "What happens to a request" in [`SPEC.md`](SPEC.md) gives each -step in full. - -1. `GET /_smallwebwaf/healthz` is answered `200` with `ok` at once, before any - check and without asking the app. -2. The client is worked out. A netblock is a range of addresses, written as an - address and a prefix length: `203.0.113.0/24`. `SWWAF_TRUSTED_PROXIES` lists - the netblocks traefik comes from, by default the private address ranges. For - a TCP peer inside them, `X-Forwarded-For` is read from the right, and the - first address outside those netblocks is the client. A peer outside them is - the client itself. An IPv6 client is its group: the whole netblock around its - address, a /64 by default; `SWWAF_IPV6_GROUP_PREFIX` sets its length. -3. A client in `SWWAF_ALLOW_NETS` skips steps 4 to 11, the byte limits and the - error burst, but still needs a token at step 12. A client in - `SWWAF_DENY_NETS` is refused. -4. A client under a ban is refused. If the ban was made for a clear sign of - attack, this request makes it permanent. -5. The client's AS number and country are looked up, unless - `SWWAF_LOOKUP_SOURCE` is `off`. An AS number names the network an address - belongs to, such as `AS64496`. -6. The country lists are checked. A client from a country in - `SWWAF_DENIED_COUNTRIES` is refused. When - `SWWAF_EXCLUSIVELY_ALLOWED_COUNTRIES` is set, a client from any other country - is refused, and so is a client without a country. Such a refusal is not an - offence. -7. The reputation sources are checked: the blocklists, the CrowdSec decision - list, the DNS blocklists and AbuseIPDB. A client on the CrowdSec decision - list is banned until the decision ends. Any other source refuses the client, - lowers its limits or only notes it, as `SWWAF_BLOCKLIST_ACTION` and - `SWWAF_REPUTATION_ACTION` say. No request waits for a query. -8. Rate limiting counts the request, unless the client or the path is exempt. A - request that takes the client over a limit is refused and bans the client. -9. A request for a path in `SWWAF_TRAP_PATHS` is refused and bans the client, as - a clear sign of attack. -10. The rule files are checked. A `log` rule notes the match. A `block` rule - refuses the request. A `ban` rule refuses it and bans the client, as a clear - sign of attack. -11. The Core Rule Set inspects the request's method, URL and headers, and, once - `SWWAF_WAF_BODY_LIMIT` is set, form, JSON and XML bodies. A request it takes - for an attack is refused while `SWWAF_WAF_MODE` is `block`, the default, and - let through while it is `detect`. It bans no one by itself. -12. A request under `/_smallwebwaf/` is answered here by `smallwebwaf`, after - its token is checked. Any other request is passed to the app. The app's - answer is streamed back within the size and time limits. -13. Once the answer has ended, a request passed to the app has its bytes counted - for the byte limits. If a rule, a trap path, the Core Rule Set or a token - check refused the request, the refusal is counted for the error burst. The - client's history and the anomaly counters are updated. More than - `SWWAF_ERROR_BURST_THRESHOLD` refusals of one client in a minute ban it. - -In `observe` mode (`SWWAF_MODE=observe`), `smallwebwaf` makes no ban of its own. -It refuses a request only for a size or time limit, or for a missing or wrong -token. A request it would otherwise have refused is passed to the app, and its -log line says what `enforce` mode would have done. Observe mode is for trying a -configuration before enforcing it. - -What a refused visitor sees: - -- `SWWAF_BAN_RESPONSE`, by default `403` with the plain text `Forbidden`. It can - be `429` instead, or `close`, which closes the connection, so that traefik - answers `502`. It answers: - - a ban or a broken rate limit; - - a `ban` rule or a trap path; - - `SWWAF_DENY_NETS` and the country lists; - - a reputation source whose action is `deny`. -- `403` for a `block` rule and the Core Rule Set. -- For a size or time limit: - - `431` for headers over their limit; - - `413` for a body over its limit; - - `408` for a client too slow to send its body; - - `502` or `504` when the app passes a limit or cannot be reached. -- `401` from an endpoint of `smallwebwaf`'s own, for a request without its - token. +A refused visitor is answered with `SWWAF_BAN_RESPONSE`, `403` by default (see +"Ban lengths, response and scope" in [`SPEC.md`](SPEC.md)). A `block` rule or a +Core Rule Set match answers `403`. A missing or wrong token gets `401`. A +request over a size or time limit gets the status for that limit, such as `413` +for a body too large (see "Size and time limits" in [`SPEC.md`](SPEC.md)). ## Settings you are likely to touch @@ -233,8 +175,11 @@ Each setting is an environment variable of the app's container, such as [`docs/settings.md`](docs/settings.md) lists every setting, its default and the values it takes. The ones most deployments touch: -- `SWWAF_MODE=observe`: log what would have been refused, refuse almost nothing, - ban no one. For trying a configuration. +- `SWWAF_MODE=observe`: `smallwebwaf` makes no ban of its own, and refuses a + request only for a size or time limit or a missing or wrong token. A request + it would have refused is passed to the app, and its log line says what + `enforce` mode would have done. For trying a configuration before enforcing + it. - `SWWAF_ALLOW_NETS`: netblocks you trust, such as your monitoring. Their clients are refused only for a size or time limit or a missing or wrong token. - `SWWAF_RATE_LIMIT_EXEMPT_NETS`: netblocks exempt from rate limiting and the @@ -376,50 +321,32 @@ nixpkgs fixed at one release. An app's `Dockerfile` installs a package with [`docs/image.md`](docs/image.md) lists what the image holds and how each part is pinned. -- The container's first process is `runsvinit`, which starts runit, a service - supervisor. runit runs the `run` script of each directory under - `/etc/service`, and runs it again a second after its program exits. - `smallwebwaf` runs as the `smallwebwaf` user (uid 65532) and the app as a user - of its own. So the app cannot touch the state files or the process of - `smallwebwaf`. -- `smallwebwaf` listens on port 8080, on every address. traefik sends the app's - requests there. `smallwebwaf` passes them to the app on `127.0.0.1:8081`. The - app listens on `127.0.0.1` only, so nothing reaches it except through - `smallwebwaf`. The health check, the metrics and the ban management are on the - same port, under `/_smallwebwaf/`. A request for that prefix never reaches the - app. -- The app sees what it would see from traefik directly: the same `Host`, the - same `X-Forwarded-Proto`, and `X-Forwarded-For` with traefik's address added - at the end. The app's TCP peer is `smallwebwaf` on `127.0.0.1`. So the app - must trust `127.0.0.1` and `::1` for forwarded headers, besides the private - address ranges. An app that keeps its usual trusted proxies sees every visitor - as `127.0.0.1`. Each request also carries its id in `X-Request-ID`. Any - `X-Client-ASN` or `X-Client-Country` header a client sent is removed. -- Both processes start with the container's environment variables. That is why - every setting of `smallwebwaf` starts with `SWWAF_`. A token given as an - environment variable is readable by the app. A token given as a file that only - the `smallwebwaf` user can read is not (see "Settings given as files" in +- runit, a service supervisor, runs `smallwebwaf` and the app side by side, each + as its own user, and starts either again when it exits. The app cannot touch + the state files or the process of `smallwebwaf`. +- `smallwebwaf` listens on port 8080 and passes requests to the app on + `127.0.0.1:8081`. The app listens on `127.0.0.1` only, so nothing reaches it + except through `smallwebwaf`. `smallwebwaf`'s own endpoints are under + `/_smallwebwaf/`, on the same port. +- The app sees the headers traefik sent, with traefik's address added to + `X-Forwarded-For`, from a TCP peer on `127.0.0.1`. So the app must trust + `127.0.0.1` and `::1` for forwarded headers, besides the private address + ranges. +- Both processes start with the container's environment variables, so every + setting of `smallwebwaf` starts with `SWWAF_`, and the app can read a token + given as one. A token given as a file that only the `smallwebwaf` user can + read is out of its reach (see "Settings given as files" in [`docs/settings.md`](docs/settings.md)). -- The state files live in `/var/lib/smallwebwaf`. Without a volume there, they - survive a restart of the container and are lost when a deploy replaces it. The - `run` script gives that directory and every file in it to the `smallwebwaf` - user at each start, so a host directory mounted there needs no change of - owner. -- The image's health check passes while `smallwebwaf` answers - `GET /_smallwebwaf/healthz` and the app accepts connections. traefik sends a - container no requests until it is healthy. -- When `smallwebwaf` or the app exits, runit starts it again a second later. The - other process keeps running. While either is down, the client gets `502`. A - `smallwebwaf` that stops at start, as on an invalid setting, is started again - every second until the cause is fixed, and logs its message each time. -- `docker stop` has runit send `SIGTERM` to both processes at once. - `smallwebwaf` gives the requests in progress five seconds to finish and writes - its state files. To let them finish, the app must keep answering for five +- The state files live in `/var/lib/smallwebwaf`. A volume mounted there keeps + them across a deploy. +- `docker stop` stops both processes at once. `smallwebwaf` gives the requests + in progress five seconds to finish, so the app must keep answering for five seconds after `SIGTERM`. -"Deployment" in [`SPEC.md`](SPEC.md) has the rest: moving `smallwebwaf` to -another port, the health check's timing, and the forwarded headers. -"Architecture" in [`SPEC.md`](SPEC.md) lists the packages and what each does. +"Deployment" in [`SPEC.md`](SPEC.md) has the rest: the health check, what +happens when a process stops, moving `smallwebwaf` to another port, and the +forwarded headers. "Architecture" in [`SPEC.md`](SPEC.md) lists the packages and +what each does. ## TODO diff --git a/SPEC.md b/SPEC.md index df217d5..90b6c95 100644 --- a/SPEC.md +++ b/SPEC.md @@ -164,8 +164,8 @@ its rules. thresholds are evaluated. In `SWWAF_MODE=observe`, every refusal above is logged as what would have -happened, nothing is refused, and no ban is made. The size and time limits and -the token check still apply. +happened, nothing is refused, and `smallwebwaf` makes no ban of its own. The +size and time limits and the token check still apply. ## Counting method @@ -183,8 +183,8 @@ the token check still apply. GeoJS answers, the reputation verdicts and scores, the DNS queries under way and the anomaly counters have fixed bounds, listed under "Fixed limits" in `docs/settings.md`. Past its bound, the GeoJS answer or anomaly counter used - longest ago goes first, and the verdict or score fetched longest ago. Past - that bound, a zone is asked at the client's next request. + longest ago goes first, and the verdict or score fetched longest ago. Past the + bound on DNS queries under way, a zone is asked at the client's next request. ## Bans @@ -215,9 +215,12 @@ to a ban, each by its own rule: permanent this way. - Once that ban has run out, the netblock is served like any other. Its next clear sign of attack bans it permanently at once. -- A broken limit: a request over a rate limit, a response that takes the - client's byte total past a byte limit, or more than - `SWWAF_ERROR_BURST_THRESHOLD` refusals within a minute. +- A broken limit, one of: + - a request over a rate limit; + - a response that takes the client's byte total past a byte limit; + - more than `SWWAF_ERROR_BURST_THRESHOLD` refusals within a minute. + + The bans for a broken limit: - The first such ban lasts `SWWAF_LIMIT_BAN_DURATION` (default `1h`), with the cause `limit`. So does one that comes more than `SWWAF_LIMIT_BAN_REPEAT_WINDOW` (default `24h`) after the last such ban @@ -233,7 +236,7 @@ to a ban, each by its own rule: A Core Rule Set match refuses only the request it matched, with `403` and without a ban, because the Core Rule Set has false positives. A `block` rule does the same. Those refusals count toward the error burst, so a client that -keeps setting them off is banned under the second rule. +keeps setting them off is banned for a broken limit. A client on the CrowdSec decision list is banned until the decision ends, with the cause `crowdsec`. Only a client that sends a request is banned, so a long @@ -328,8 +331,8 @@ Conventions: - `SWWAF_ADMIN_TOKEN` switches on the ban endpoints and `/_smallwebwaf/clients/`. The metrics are off until `SWWAF_METRICS_TOKEN` is set, since without a token they would be open to anyone on the internet. - The two are separate, so a scraper that holds the metrics token cannot manage - bans. + The two are separate, so the metrics collector, which holds the metrics token, + cannot manage bans. - A token is a long random value, since the endpoints can be reached from the internet. One shorter than 32 characters stops the start. The app starts with the same environment variables as `smallwebwaf`, so it can read a token set as @@ -453,8 +456,8 @@ service that keeps its visitors' addresses on its own host. Addresses are asked about together, up to 200 in one request (`https://get.geojs.io/v1/ip/geo.json?ip=a,b,c`), one request at a time, which keeps the number of requests to GeoJS low. Each answer's `country_code`, `asn` - and `organization_name` are read. An answer without a `country_code`, or with - the `asn` `64512`, counts as unknown. + and `organization_name` are read. An answer without a `country_code` leaves + the country unknown, and the `asn` `64512` leaves the AS number unknown. - Each answer is kept for seven days, in memory and in `lookups.json`. Answers are kept apart from the table of clients, so that an answer outlasts a client dropped from that table. The answer reaches the client's history and ban notes @@ -528,12 +531,12 @@ service's abuse comes from. fetched and kept like a blocklist (see "Reputation"). Where it and `SWWAF_ASN_LIMIT_PERCENT` both give a percentage, the lower applies. - A client's limit percentage is the lowest of those that apply to it: its AS - number's, its country's, or a reputation hit's `limit:`. A client the - lookup cannot place gets `SWWAF_UNKNOWN_LIMIT_PERCENT` in place of an AS - number's or a country's. The percentage is 100 if none applies. Clients given - a lower percentage are banned after fewer requests, first for a while and - then, for repeated abuse, permanently. The log line of each counted request, - and the notes of each ban, say which setting lowered the limit. + number's, its country's, or a reputation hit's `limit:`. A client + without a country gets `SWWAF_UNKNOWN_LIMIT_PERCENT` in place of a country's. + The percentage is 100 if none applies. Clients given a lower percentage are + banned after fewer requests, first for a while and then, for repeated abuse, + permanently. The log line of each counted request, and the notes of each ban, + say which setting lowered the limit. - No budget is shared by a whole country or AS number. One abuser could use it up and lock out everyone else there: a denial of service nobody chose, and the one this tool exists to prevent. Refusing a whole country is left to the @@ -544,15 +547,14 @@ service's abuse comes from. By default the Core Rule Set reads the method, the URL with its query string, and the headers of every request. That is where automated attacks show: injection in query strings, path traversal, attacks carried in headers, -scanners' user agents. It reads no request body. On a code forge, the example -deployment, bodies carry what people write and publish, such as issue text and +scanners' user agents. It reads no request body. In front of a code forge such +as gitea, bodies carry what people write and publish, such as issue text and files saved in the web editor. The Core Rule Set takes the shell commands and code in them for attacks. The default gives up refusing an attack carried in a body. The rule files, the limits and the bans still apply to the client that sends it. -- The Core Rule Set skips a path under `SWWAF_WAF_EXEMPT_PATHS`. An engine error - on a request forwards the request, and is logged and counted. +- The Core Rule Set skips a path under `SWWAF_WAF_EXEMPT_PATHS`. - `SWWAF_WAF_PARANOIA_LEVEL` and `SWWAF_WAF_ANOMALY_THRESHOLD` are the Core Rule Set's own two tuning values, at its own defaults. Each level up runs more rules, which find more attacks and take more ordinary requests for attacks. @@ -633,12 +635,12 @@ every app, and no setting undoes them: - `ref`, `sha`, `branch` and `workflow`; - `artifactName` and `redirect_to`. - gitea puts file paths, branch and workflow names, and the page to return to - after signing in into them. It reads these values as names in a repository + gitea puts into them file paths, branch and workflow names, and the page to + return to after signing in. It reads these values as names in a repository or in its own records, or as a page of its own site, never as a command. Any name on those lists can be an ordinary file or branch, such as `.gitignore` - or `docker-build`. In these parameters, anything only these three rules - catch reaches the app, commands such as `|cat /etc/passwd` included. Path + or `docker-build`. In these parameters, what only these three rules would + catch reaches the app, such as the command `|cat /etc/passwd`. Path traversal, SQL and script injection, and PHP, Java and Node.js code are still refused there. Every other parameter keeps all three rules. An app that uses one of these parameters as a file on the server, or passes it to a @@ -647,8 +649,8 @@ every app, and no setting undoes them: 5. Two cookies are left out, and `Referer` keeps fewer rules: - The Core Rule Set reads the request without the `gitea_flash` and `redirect_to` cookies. gitea puts a message naming what was just done into - `gitea_flash`. It puts the page to return to after signing in into - `redirect_to`. The Core Rule Set takes file names in them, such as + `gitea_flash`. It puts into `redirect_to` the page to return to after + signing in. The Core Rule Set takes file names in them, such as `package.json`, for attacks. A browser sends such a cookie with every request until gitea replaces it. gitea cannot replace it while those requests are refused, so one refusal would keep the browser out of the @@ -772,7 +774,8 @@ too close together. client gets a quarter of every request and byte limit rather than a refusal. - Verdicts and scores are kept for `SWWAF_REPUTATION_CACHE_TTL`, in memory and in `reputation.json`. A source that is down or over quota gives no verdict. - The service continues, with one `source_failure` alert per cooldown. + The service continues. Each failure raises a `source_failure` alert (see + "Alerting"). ### Alerting @@ -861,11 +864,11 @@ and the default file. wrong for every app, with its path rules anchored at the site root. In front of gitea, `/.env` is a probe, while `///src/branch/main/.env.example` is a file in a repository that - any visitor may open. `ban` rules of your own follow the same rule. Anything - app-specific, such as a rule banning WordPress probes in front of gitea, - belongs in a file the app's Dockerfile adds or the deployer mounts. A - directory mounted over `SWWAF_RULES_DIR` replaces the default file; single - files mounted into it add to it. + any visitor may open. Anchor the paths of your own `ban` rules at the site + root too. Anything app-specific, such as a rule banning WordPress probes in + front of gitea, belongs in a file the app's Dockerfile adds or the deployer + mounts. A directory mounted over `SWWAF_RULES_DIR` replaces the default file; + single files mounted into it add to it. - Rules meant to be edited while `smallwebwaf` runs belong in a mounted directory, not a mounted file. Many editors save a file by replacing it, and a container keeps seeing the old one when the file alone is mounted. The lookup @@ -874,11 +877,11 @@ and the default file. ## Persistent state -All state lives in memory, and the files in `SWWAF_STATE_DIR` hold a copy of all -of it, so an orderly stop loses nothing (the remote log is the exception; see -"Request log"). The files are meant for people as well: an admin can read or -edit them at any time, and the running `smallwebwaf` takes the edit in. -`docs/state-files.md` lists the files, what each holds, and their sizes. +All state lives in memory, and the files in `SWWAF_STATE_DIR` hold a copy of it, +so an orderly stop loses nothing. The files are meant for people as well: an +admin can read or edit them at any time, and the running `smallwebwaf` takes the +edit in. `docs/state-files.md` lists the files, what each holds, and their +sizes. - Each file holds one kind of state, as JSON with: - a top-level `version` number; @@ -1019,14 +1022,14 @@ what the image holds and how each part is pinned. digest. - nixpkgs comes from a release file on `releases.nixos.org`, named with its hash, not from a GitHub archive, whose bytes can change. Root uses Nix - directly; no Nix daemon runs, and since `nix-bin` creates no build users, - `build-users-group =` in `/etc/nix/nix.conf` lets root build without them. - Root's Nix profile is last on the `PATH`, so that no package hides the image's - own commands; busybox's `sv`, for one, looks for services elsewhere. An app - built on the image gets the same packages each time. Security fixes from - Ubuntu and nixpkgs come with a newer `smallwebwaf` image, which an app takes - by changing the digest in its `FROM` line. The image moves to each new nixpkgs - release, every six months. + directly; no Nix daemon runs. `nix-bin` creates no build users, so + `/etc/nix/nix.conf` sets `build-users-group =`, which lets root build without + them. Root's Nix profile is last on the `PATH`, so that no package hides the + image's own commands; busybox's `sv`, for one, looks for services elsewhere. + An app built on the image gets the same packages each time. Security fixes + from Ubuntu and nixpkgs come with a newer `smallwebwaf` image, which an app + takes by changing the digest in its `FROM` line. The image moves to each new + nixpkgs release, every six months. - runit supervises the two processes, with `runsvinit` as the entrypoint, as the owner's code style guide asks for service containers. No package carries `runsvinit`, so the image builds it from its archived source, unchanged since @@ -1075,10 +1078,10 @@ It sets no `ENTRYPOINT` or `USER` of its own. The container must start - an unwritable `SWWAF_STATE_DIR`; - a `SWWAF_RULES_DIR` that does not exist or cannot be read; - a `SWWAF_LISTEN_ADDR` it cannot listen on. -- A `smallwebwaf` that stops at start is therefore started again every second, - logging its message each time, until the cause is fixed; the health check - fails meanwhile. Once running, a failing GeoJS, reputation source or alert - destination, or a broken edit, never takes the protected service down. +- A `smallwebwaf` that stops at start logs its message at each try until the + cause is fixed; the health check fails meanwhile. Once running, a failing + GeoJS, reputation source or alert destination, or a broken edit, never takes + the protected service down. - `docker stop` sends `SIGTERM` to `runsvinit`, which has runit stop both services at once, each with `SIGTERM`, and exits once they have stopped. `smallwebwaf` stops taking requests, gives those in progress five seconds to @@ -1147,9 +1150,10 @@ all: `10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,127.0.0.1/32,::1/128`. ### upaas -An app deployed by upaas takes this shape with no change to upaas. upaas builds -the app's Dockerfile and runs the one container as it runs any app. The traefik -labels route to port 8080, and any `SWWAF_` settings go with the app's +An app deployed by upaas, which rebuilds and restarts an app's Docker container +when its repository changes, takes this shape with no change to upaas. upaas +builds the app's Dockerfile and runs the one container as it runs any app. The +traefik labels route to port 8080, and any `SWWAF_` settings go with the app's environment variables. The volume for `/var/lib/smallwebwaf` and the directory of any token file go beside the app's own volumes. gitea is built on the image like any other app; `docs/gitea.md` records what the defaults do in front of it, diff --git a/docs/settings.md b/docs/settings.md index 2e32250..3ed2db3 100644 --- a/docs/settings.md +++ b/docs/settings.md @@ -196,8 +196,7 @@ that take `off`, the `_FILE` form, and what each group does and why. - `SWWAF_WAF_BODY_LIMIT` (default `off`): `off`, or how much of a request body the Core Rule Set reads, a size of at most `1G`. - `SWWAF_ERROR_BURST_THRESHOLD` (default `30`): the most refusals of one client - in a minute for a rule match, a trap path, a Core Rule Set match or a failed - token check. A count or `off`. + in a minute (see "Attack detection" in `SPEC.md`). A count or `off`. ## Ban lengths, response and scope