rproxy, the proxy in front of each app, asks servewaf and fails open (closes #171)
check / check (push) Failing after 14m17s
check / check (push) Failing after 14m17s
`smallwebwaf rproxy` reads the first 64 KiB of each body, asks servewaf, and passes what servewaf allows to the app within its own size and time limits. It reports each request servewaf answered. SWRP_DEFAULT_DISPOSITION decides when servewaf gives no answer. Duplication: internal/rproxy copies passing-on code from internal/proxy until #172 removes the originals. Rule suppressed: gosec G704 on servewaf's URL, a setting. Rule suppressed: gosec G705 on the answer written to the visitor. Judgement call: the SWRP_ size and time limits take off; SWRP_TIMEOUT_MS does not. Model: opus-5-5
This commit is contained in:
@@ -51,3 +51,9 @@ curl -H "Authorization: Bearer $TOKEN" \
|
||||
|
||||
`smallwebwaf servewaf` answers these endpoints at its own address. No check runs
|
||||
on those requests (see "`servewaf`" in [`SPEC.md`](../SPEC.md)).
|
||||
|
||||
## `rproxy`
|
||||
|
||||
`smallwebwaf rproxy` answers only the health check, at its own address. It asks
|
||||
`servewaf` about any other request under `/_smallwebwaf/` (see "`rproxy`" in
|
||||
[`SPEC.md`](../SPEC.md)).
|
||||
|
||||
+34
-1
@@ -3,6 +3,7 @@
|
||||
The fields of the JSON object `smallwebwaf` writes for each request. "Request
|
||||
log" in [`SPEC.md`](../SPEC.md) says when a line is written and how the log is
|
||||
sent to a syslog server. A field that does not apply to a request is left out.
|
||||
`smallwebwaf rproxy` writes a shorter line, which "`rproxy`'s line" below gives.
|
||||
|
||||
## Example
|
||||
|
||||
@@ -12,7 +13,7 @@ sent to a syslog server. A field that does not apply to a request is left out.
|
||||
|
||||
## Every line
|
||||
|
||||
Every line has:
|
||||
Every line but `rproxy`'s has:
|
||||
|
||||
- `type`: `request` (the process's own messages have `process`);
|
||||
- the standard web log fields;
|
||||
@@ -180,3 +181,35 @@ For an allowed request, the report's counting also changes these fields:
|
||||
- `counts`: the byte totals now include this request's;
|
||||
- `limit_hit`, `offence` and `ban_expires`: set when the report's bytes broke a
|
||||
byte limit.
|
||||
|
||||
## `rproxy`'s line
|
||||
|
||||
`smallwebwaf rproxy` writes one short line for each request. `request_id` joins
|
||||
it to `servewaf`'s two. It has these fields and no others:
|
||||
|
||||
- `type`: `request`.
|
||||
- `time`: when the request arrived, RFC 3339 with milliseconds, in UTC.
|
||||
- `request_id`: the id `rproxy` made for the request when it arrived.
|
||||
- `client_ip`: the visitor's address.
|
||||
- `host` and `method`.
|
||||
- `path` and `query`: as the visitor sent them.
|
||||
- `status`: what the visitor got, `0` if nothing.
|
||||
- `request_bytes`: the bytes of the visitor's body that `rproxy` read, with what
|
||||
a WebSocket carried from the visitor.
|
||||
- `response_bytes`: the bytes of the answer's body, with what a WebSocket
|
||||
carried from the app.
|
||||
- `duration_request`: milliseconds from the request's headers being read until
|
||||
the app had been sent the whole request, or the answer started if that was
|
||||
sooner. It includes the wait for `servewaf`.
|
||||
- `duration_response`: milliseconds from then until the end of the answer.
|
||||
- `disposition`: what was done with the request: `allow`, `deny` or `close`. It
|
||||
is `servewaf`'s answer, or the value of `SWRP_DEFAULT_DISPOSITION`. It is left
|
||||
out when `servewaf` was not asked, as for the health check.
|
||||
- `default_disposition`: `true` when `SWRP_DEFAULT_DISPOSITION` gave
|
||||
`disposition`, and otherwise left out.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
{"type":"request","time":"2026-10-03T12:00:00.123Z","request_id":"7Q2NHZ4KJ3VXW5YB6R3MEFTD2A","client_ip":"203.0.113.9","host":"app.example","method":"GET","path":"/","query":"","status":200,"request_bytes":0,"response_bytes":5120,"duration_request":1.204,"duration_response":3.104,"disposition":"allow"}
|
||||
```
|
||||
|
||||
+38
-1
@@ -340,7 +340,10 @@ A few limits are fixed rather than settings:
|
||||
- at most 1,000 DNS blocklist queries are under way at once;
|
||||
- at most 20,000 anomaly counters are kept;
|
||||
- each alert destination's queue holds at most 1,000 alerts;
|
||||
- `servewaf` holds at most 10,000 answered requests awaiting their reports.
|
||||
- `servewaf` holds at most 10,000 answered requests awaiting their reports;
|
||||
- `rproxy` takes a request line and headers of at most 32 KiB, closes a
|
||||
kept-open connection idle for 120 seconds, and reads at most 1 MiB of the body
|
||||
of `servewaf`'s answer.
|
||||
|
||||
## `servewaf`
|
||||
|
||||
@@ -358,3 +361,37 @@ at start still shows them.
|
||||
request to an app. `SWWAF_WAF_BODY_LIMIT` has an effect up to 64 KiB less one
|
||||
byte, whatever its value. A question carries no more of a body than 64 KiB (see
|
||||
"`servewaf`" in [`SPEC.md`](../SPEC.md)).
|
||||
|
||||
## `rproxy`
|
||||
|
||||
`smallwebwaf rproxy` reads the settings below and no others, and nothing else
|
||||
reads them. They are read once at start, and an invalid value stops the start.
|
||||
None can be given as a file, since `rproxy` never touches disk. "`rproxy`" in
|
||||
[`SPEC.md`](../SPEC.md) says what they do.
|
||||
|
||||
A time here is a whole number of milliseconds above zero, such as `2000`.
|
||||
|
||||
- `SWRP_WAF_BACKEND` (required, no default): `servewaf`'s URL. An `http` or
|
||||
`https` URL with a host and an optional port, and nothing more.
|
||||
- `SWRP_TIMEOUT_MS` (default `2000`): how long `rproxy` waits for `servewaf`'s
|
||||
answer, to a question and to a report. A time; never `off`.
|
||||
- `SWRP_DEFAULT_DISPOSITION` (default `allow`): what is done with a request
|
||||
`servewaf` gives no answer about. `allow` passes it to the app, and `deny`
|
||||
answers `503`.
|
||||
- `SWRP_MAX_REQUEST_SIZE` (default `100M`): the largest request body. A size or
|
||||
`off`.
|
||||
- `SWRP_MAX_RESPONSE_SIZE` (default `1G`): the largest response body. A size or
|
||||
`off`.
|
||||
- `SWRP_MAX_REQUEST_TIME_MS` (default `60000`): how long the visitor may take to
|
||||
send its request line and headers. It then also bounds, from the end of the
|
||||
headers, the time until the app has been sent the whole request. A time or
|
||||
`off`.
|
||||
- `SWRP_MAX_RESPONSE_TIME_MS` (default `1800000`): how long the answer may take,
|
||||
from the end of the request to its last byte reaching the visitor. A time or
|
||||
`off`.
|
||||
- `SWRP_LISTEN_ADDR` (default `:8080`): where `rproxy` listens, such as `:9000`.
|
||||
- `SWRP_UPSTREAM_URL` (default `http://127.0.0.1:8081`): the app. An `http` or
|
||||
`https` URL with a host and an optional port, and nothing more.
|
||||
- `SWRP_TRUSTED_PROXIES` (default `10.0.0.0/8,172.16.0.0/12,192.168.0.0/16`):
|
||||
the netblocks whose `X-Forwarded-For` is believed. Set but empty, it trusts
|
||||
nothing.
|
||||
|
||||
Reference in New Issue
Block a user