check / check (push) Waiting to run
The old README opened with project history and one list of a hundred settings. The new one leads with what smallwebwaf is, what it protects against, how to build and deploy it, what happens to a request, the settings most deployments touch, how to check it works, the entrypoints, the rationale and the design, as REPO_POLICIES.md requires. The reference lists, every setting, the rule file format, the endpoints, the request log's fields, the alert events, the metrics, the state files, the image and the gitea notes, move to files under docs/, each linked from the README, with SPEC.md as the one place for behaviour. Every statement was checked against the code on next. Model: fable-5-1
327 lines
16 KiB
Markdown
327 lines
16 KiB
Markdown
# Settings
|
|
|
|
Every setting, its default and the values it takes, in the groups of "Settings"
|
|
in [`SPEC.md`](../SPEC.md). That section gives the conventions, the settings
|
|
that take `off`, the `_FILE` form, and what each group does and why. A setting
|
|
set to a value its entry does not allow stops the start.
|
|
|
|
## Forms of values
|
|
|
|
- A duration is Go's syntax, with `d` for days: `90s`, `15m`, `24h`, `7d`. Zero
|
|
and negative durations are refused.
|
|
- A size is a number of bytes with an optional `K`, `M` or `G`, which are powers
|
|
of 1024, so `1K` is 1024 bytes. Examples: `512K`, `100M`, `5G`.
|
|
- A count is a whole number of requests, such as `1000`.
|
|
- A list is comma separated, with spaces around items ignored. An empty item is
|
|
refused.
|
|
- A netblock is an address and a prefix length, such as `10.0.0.0/8`. A bare
|
|
address stands for itself alone.
|
|
- A country is a two-letter code of ISO 3166-1, in either case: `de` and `DE`
|
|
are the same. `xk` stands for Kosovo. A code that is not a country is refused,
|
|
such as `nk` (North Korea is `kp`) or the withdrawn `su`.
|
|
- An AS number is `AS` and the number, in either case, such as `AS64496`.
|
|
- A percentage is a whole number from 0 to 100.
|
|
- A path prefix starts with `/`, such as `/assets/`.
|
|
|
|
## Core
|
|
|
|
- `SWWAF_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.
|
|
- `SWWAF_LISTEN_ADDR` (default `:8080`): where `smallwebwaf` listens, an
|
|
optional host and a port. The host stays empty.
|
|
- `SWWAF_INSTANCE_NAME` (default: the container's host name): the `instance`
|
|
name in every log line, alert and metric, such as `fsn1app1/gitea`. Valid
|
|
UTF-8. No control character while `SWWAF_ALERT_NTFY_URL` is set. 1 to 48
|
|
printable ASCII characters without a space while `SWWAF_LOG_REMOTE_URL` is set
|
|
and `SWWAF_LOG_REMOTE_APP_NAME` is not.
|
|
- `SWWAF_MODE` (default `enforce`): `enforce` or `observe`.
|
|
- `SWWAF_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.
|
|
- `SWWAF_IPV6_GROUP_PREFIX` (default `64`): the prefix length of an IPv6
|
|
client's group, from 32 to 128.
|
|
- `SWWAF_MAX_TRACKED_CLIENTS` (default `20000`): the most clients kept, a whole
|
|
number above zero.
|
|
- `SWWAF_MAX_BANS` (default `5000`): the most bans `smallwebwaf` made that are
|
|
kept, a whole number above zero.
|
|
|
|
## Tokens
|
|
|
|
- `SWWAF_ADMIN_TOKEN` (default unset): the token for the ban endpoints and
|
|
`/_smallwebwaf/clients/<ip>`. At least 32 characters.
|
|
- `SWWAF_METRICS_TOKEN` (default unset): the token for `/_smallwebwaf/metrics`.
|
|
At least 32 characters.
|
|
|
|
## State files
|
|
|
|
- `SWWAF_STATE_DIR` (default `/var/lib/smallwebwaf`): the directory of the state
|
|
files, an absolute path that exists and can be written.
|
|
- `SWWAF_STATE_WRITE_DELAY` (default `10s`): how long `bans.json` waits to be
|
|
written after a ban is made, lifted or made permanent. A duration.
|
|
- `SWWAF_STATE_COUNTER_INTERVAL` (default `15m`): how often every state file is
|
|
written. A duration.
|
|
|
|
## Logging
|
|
|
|
- `SWWAF_LOG_LEVEL` (default `info`): the least severe of `smallwebwaf`'s own
|
|
messages that are written: `debug`, `info`, `warn` or `error`.
|
|
- `SWWAF_LOG_REQUEST_HEADERS` (default
|
|
`accept,accept-language,accept-encoding,content-type,origin,range`): the
|
|
request headers recorded in the log line, in either case. `Host` and
|
|
`Transfer-Encoding` are refused; the host is the field `host`.
|
|
- `SWWAF_LOG_REMOTE_URL` (default unset): a syslog server that also gets every
|
|
line written to stdout: `syslog+udp://`, `syslog+tcp://` or `syslog+tls://`,
|
|
each with a host and a port and nothing more.
|
|
- `SWWAF_LOG_REMOTE_TLS_CA_FILE` (default unset): a file of PEM certificates
|
|
that a `syslog+tls` server's certificate must chain to, instead of the host's
|
|
own. A file that cannot be read, or holds no certificate, is refused.
|
|
- `SWWAF_LOG_REMOTE_BUFFER` (default `10000`): the most lines held while they
|
|
wait to be sent, a whole number above zero.
|
|
- `SWWAF_LOG_REMOTE_FACILITY` (default `local0`): the syslog facility: `kern`,
|
|
`user`, `mail`, `daemon`, `auth`, `syslog`, `lpr`, `news`, `uucp`, `cron`,
|
|
`authpriv`, `ftp`, or `local0` to `local7`.
|
|
- `SWWAF_LOG_REMOTE_APP_NAME` (default: `SWWAF_INSTANCE_NAME`): the app name in
|
|
each syslog record, 1 to 48 printable ASCII characters without a space.
|
|
|
|
## Metrics
|
|
|
|
- `SWWAF_METRICS_TOP_N` (default `50`): how many AS numbers and how many
|
|
countries get series of their own. A whole number above zero.
|
|
|
|
## Static lists
|
|
|
|
- `SWWAF_ALLOW_NETS` (default empty): netblocks whose clients are refused only
|
|
for a size or time limit or a missing or wrong token, such as your monitoring.
|
|
- `SWWAF_RATE_LIMIT_EXEMPT_NETS` (default empty): netblocks whose clients are
|
|
exempt from rate limiting and the byte limits.
|
|
- `SWWAF_DENY_NETS` (default empty): netblocks whose clients are always refused.
|
|
|
|
## Request rate limits, per client
|
|
|
|
- `SWWAF_RATE_LIMIT_PER_MINUTE` (default `1000`), `SWWAF_RATE_LIMIT_PER_HOUR`
|
|
(default `10000`) and `SWWAF_RATE_LIMIT_PER_DAY` (default `50000`): the most
|
|
requests a client may make in each window. A count or `off`.
|
|
- `SWWAF_RATE_LIMIT_EXEMPT_PATHS` (default empty): path prefixes exempt from
|
|
rate limiting and the byte limits, such as `/assets/`.
|
|
|
|
## Byte limits, per client
|
|
|
|
- `SWWAF_BYTES_LIMIT_PER_MINUTE` (default `10G`), `SWWAF_BYTES_LIMIT_PER_HOUR`
|
|
(default `20G`) and `SWWAF_BYTES_LIMIT_PER_DAY` (default `50G`): the most
|
|
bytes counted for a client in each window. A size or `off`.
|
|
- `SWWAF_BYTES_COUNT` (default `both`): which body bytes the byte limits count:
|
|
`response`, `request` or `both`.
|
|
|
|
## Size and time limits
|
|
|
|
- `SWWAF_CLIENT_REQUEST_TIMEOUT` (default `60s`): how long a client may take to
|
|
send its request line and headers, and then, from the end of the headers, its
|
|
body. A duration or `off`.
|
|
- `SWWAF_CLIENT_REQUEST_HEADER_MAX_BYTES` (default `32K`): the largest request
|
|
line and headers. A size over `4K`; never `off`.
|
|
- `SWWAF_CLIENT_IDLE_TIMEOUT` (default `120s`): how long a kept-open connection
|
|
may wait for its next request before it is closed. A duration or `off`.
|
|
- `SWWAF_CLIENT_RESPONSE_TIMEOUT` (default `30m`): how long the answer may take
|
|
to reach the client, from the end of the request to the last byte. A duration
|
|
or `off`.
|
|
- `SWWAF_UPSTREAM_REQUEST_TIMEOUT` (default `60s`): how long connecting to the
|
|
app and sending it the whole request may take. A duration or `off`.
|
|
- `SWWAF_UPSTREAM_RESPONSE_TIMEOUT` (default `30m`): how long the app may take
|
|
to send its whole answer. A duration or `off`.
|
|
- `SWWAF_REQUEST_MAX_BYTES` (default `100M`): the largest request body. A size
|
|
or `off`.
|
|
- `SWWAF_RESPONSE_MAX_BYTES` (default `5G`): the largest response body. A size
|
|
or `off`.
|
|
|
|
## Lookup of AS number and country
|
|
|
|
- `SWWAF_LOOKUP_SOURCE` (default `geojs`): `geojs`, `file` or `off`.
|
|
- `SWWAF_LOOKUP_DB_PATH` (default empty): the IPinfo Lite database file, in its
|
|
`.mmdb` form, for `SWWAF_LOOKUP_SOURCE=file`.
|
|
- `SWWAF_LOOKUP_TIMEOUT` (default `1s`): how long a request waits for its
|
|
client's first answer from GeoJS, and how long a request to GeoJS may take. A
|
|
duration; never `off`.
|
|
- `SWWAF_ADD_LOOKUP_HEADERS` (default `false`): `true` passes the app the
|
|
client's AS number in `X-Client-ASN` and its country in `X-Client-Country`.
|
|
|
|
## Country lists
|
|
|
|
- `SWWAF_DENIED_COUNTRIES` (default empty): countries whose clients are refused,
|
|
such as `cn,ru,kp`.
|
|
- `SWWAF_EXCLUSIVELY_ALLOWED_COUNTRIES` (default empty): when set, the only
|
|
countries whose clients get through, such as `us,de`. A country on both lists
|
|
is refused.
|
|
|
|
## Biased thresholds
|
|
|
|
- `SWWAF_ASN_LIMIT_PERCENT` (default empty): a list of AS numbers, each with `:`
|
|
and a percentage, such as `AS14061:50,AS16276:50,AS45102:25`. An AS number
|
|
listed twice is refused.
|
|
- `SWWAF_COUNTRY_LIMIT_PERCENT` (default empty): the same by country, such as
|
|
`cn:25,ru:50`.
|
|
- `SWWAF_ASN_BYTES_PERCENT` and `SWWAF_COUNTRY_BYTES_PERCENT` (default empty):
|
|
the same, for the byte limits alone.
|
|
- `SWWAF_UNKNOWN_LIMIT_PERCENT` (default `100`): the percentage for a client the
|
|
lookup cannot place.
|
|
- `SWWAF_ASN_LIMIT_PERCENT_URL` (default unset): the `http` or `https` URL of a
|
|
text file of `AS<number>:<percent>` lines, one to a line. A URL that is also
|
|
in `SWWAF_BLOCKLIST_URLS` is refused.
|
|
|
|
## Attack detection
|
|
|
|
- `SWWAF_RULES_DIR` (default `/etc/smallwebwaf/rules.d`): the directory of the
|
|
rule files.
|
|
- `SWWAF_RULES_ENABLED` (default `true`): `false` reads no rule file.
|
|
- `SWWAF_TRAP_PATHS` (default empty): paths only scanners ask for, such as
|
|
`/wp-login.php,/xmlrpc.php`. Each starts with `/` and holds no `?`.
|
|
- `SWWAF_WAF_MODE` (default `block`): `off`, `detect` or `block`.
|
|
- `SWWAF_WAF_PARANOIA_LEVEL` (default `1`): the Core Rule Set's paranoia level,
|
|
from 1 to 4.
|
|
- `SWWAF_WAF_ANOMALY_THRESHOLD` (default `5`): the score at which a request is a
|
|
match. A whole number above zero, or `off`.
|
|
- `SWWAF_WAF_DISABLED_RULES` (default
|
|
`920340,920420,920440,920640,930130,930140`): the ids of Core Rule Set rules
|
|
to switch off. Each a whole number above zero. An id from 900000 to 900999 is
|
|
refused: those are the rules that set the Core Rule Set up, and
|
|
`smallwebwaf`'s own.
|
|
- `SWWAF_WAF_EXEMPT_PATHS` (default empty): path prefixes the Core Rule Set does
|
|
not inspect.
|
|
- `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`.
|
|
|
|
## Ban lengths, response and scope
|
|
|
|
- `SWWAF_BAN_RESPONSE` (default `403`): `403`, `429` or `close`.
|
|
- `SWWAF_LIMIT_BAN_DURATION` (default `1h`): the ban for a first broken limit. A
|
|
duration.
|
|
- `SWWAF_LIMIT_BAN_REPEAT_WINDOW` (default `24h`): the time after a ban ends
|
|
within which breaking a limit again lengthens the next ban. A duration.
|
|
- `SWWAF_MAX_BAN_DURATION` (default `7d`): the longest ban for a broken limit;
|
|
one that would be longer is permanent. A duration.
|
|
- `SWWAF_ATTACK_BAN_DURATION` (default `7d`): the ban for a first clear sign of
|
|
attack. A duration.
|
|
- `SWWAF_BAN_SCOPE_V4_PREFIX` (default `32`): how much a ban on an IPv4 client
|
|
covers: the prefix length of its netblock, from 0 to 32.
|
|
|
|
## Reputation
|
|
|
|
- `SWWAF_BLOCKLIST_URLS` (default empty): blocklists to fetch, such as
|
|
`https://www.spamhaus.org/drop/drop.txt`. Each an `http` or `https` URL
|
|
without a user or a fragment. A URL listed twice is refused.
|
|
- `SWWAF_BLOCKLIST_REFRESH` (default `24h`): how long a list waits after its
|
|
last try before it is fetched again. A duration of `1h` or more.
|
|
- `SWWAF_BLOCKLIST_ACTION` (default `deny`): `deny`, `limit:<percent>` or `log`.
|
|
- `SWWAF_DNSBL_ZONES` (default empty): the DNS blocklists to ask, such as
|
|
`dnsbl.dronebl.org`. Each a DNS name of at most 189 characters. A Spamhaus
|
|
zone carries its key, as in `<key>.xbl.dq.spamhaus.net`. A zone listed twice
|
|
is refused, whatever its case or key.
|
|
- `SWWAF_DNSBL_RESOLVER` (default unset): the resolver to ask the zones through,
|
|
such as `192.0.2.53` or `[2001:db8::53]:5353`. An IP address with an optional
|
|
port, 53 when none is given. Unset, the host's resolver is used.
|
|
- `SWWAF_ABUSEIPDB_KEY` (default unset): the key of your AbuseIPDB account. A
|
|
control character in it is refused.
|
|
- `SWWAF_ABUSEIPDB_MIN_SCORE` (default `75`): the least abuse confidence score,
|
|
from 0 to 100, that is a hit.
|
|
- `SWWAF_ABUSEIPDB_DAILY_BUDGET` (default `900`): the most checks made in a day,
|
|
a whole number above zero. AbuseIPDB's free accounts may make 1,000.
|
|
- `SWWAF_CROWDSEC_LAPI_URL` (default unset): the local API of a CrowdSec engine
|
|
you run, such as `http://172.17.0.1:8080`. An `http` or `https` URL without a
|
|
user or a fragment; its decision list is at `v1/decisions` under it. Set
|
|
without the key, it is refused. So is a decision list URL that is also in
|
|
`SWWAF_BLOCKLIST_URLS`, or that is `SWWAF_ASN_LIMIT_PERCENT_URL`.
|
|
- `SWWAF_CROWDSEC_LAPI_KEY` (default unset): the key the engine gave for
|
|
`smallwebwaf`, as `cscli bouncers add smallwebwaf` prints it. Set without the
|
|
URL, it is refused.
|
|
- `SWWAF_REPUTATION_ACTION` (default `limit:25`): `deny`, `limit:<percent>` or
|
|
`log`, for DNS blocklist and AbuseIPDB hits.
|
|
- `SWWAF_REPUTATION_CACHE_TTL` (default `24h`): how long a zone's verdict or
|
|
AbuseIPDB's score is used. A duration.
|
|
- `SWWAF_REPUTATION_TIMEOUT` (default `2s`): how long a query to a zone or a
|
|
check with AbuseIPDB may take. A duration.
|
|
|
|
## Alerting
|
|
|
|
- `SWWAF_ALERT_WEBHOOK_URL` (default unset): the webhook that receives each
|
|
alert as a JSON object. An `http` or `https` URL without a user or a fragment.
|
|
- `SWWAF_ALERT_WEBHOOK_HEADERS` (default empty): headers sent with each post,
|
|
such as `Authorization:Bearer 0123456789abcdef`. A list of name, `:` and
|
|
value. A value cannot hold a comma.
|
|
- `SWWAF_ALERT_SLACK_WEBHOOK_URL` (default unset): the Slack incoming webhook
|
|
that receives each alert as a message, checked as the webhook URL is.
|
|
- `SWWAF_ALERT_NTFY_URL` (default unset): the ntfy topic that receives each
|
|
alert, as the topic's full URL, such as `https://ntfy.sh/my-alerts`, checked
|
|
as the webhook URL is.
|
|
- `SWWAF_ALERT_NTFY_TOKEN` (default unset): an ntfy access token. A control
|
|
character in it is refused.
|
|
- `SWWAF_ALERT_EVENTS` (default
|
|
`ban,permanent_ban,waf_block,anomaly,reputation_hit,source_failure,file_error`):
|
|
the event types alerts are sent for, from those in [`alerts.md`](alerts.md)
|
|
but `summary`. Any other name is refused.
|
|
- `SWWAF_ALERT_COOLDOWN` (default `15m`): how long a repeat of an alert is held
|
|
back. A duration or `off`.
|
|
- `SWWAF_ALERT_MAX_PER_HOUR` (default `60`): the most alerts sent in an hour. A
|
|
whole number above zero, or `off`.
|
|
|
|
## Anomaly thresholds
|
|
|
|
Each scope has four thresholds: the most requests and the most bytes counted in
|
|
a minute and in an hour. Requests are counts, bytes are sizes. Each is `off` by
|
|
default. The four thresholds per client are:
|
|
|
|
- `SWWAF_ANOMALY_CLIENT_REQUESTS_PER_MINUTE`;
|
|
- `SWWAF_ANOMALY_CLIENT_REQUESTS_PER_HOUR`;
|
|
- `SWWAF_ANOMALY_CLIENT_BYTES_PER_MINUTE`;
|
|
- `SWWAF_ANOMALY_CLIENT_BYTES_PER_HOUR`.
|
|
|
|
The other scopes' names have another prefix before the same four endings, such
|
|
as `REQUESTS_PER_MINUTE`:
|
|
|
|
- `SWWAF_ANOMALY_NET_...`: per netblock around a client. Two settings give the
|
|
netblock's length:
|
|
- `SWWAF_ANOMALY_NET_V4_PREFIX` (default `24`, from 0 to 32) for an IPv4
|
|
client;
|
|
- `SWWAF_ANOMALY_NET_V6_PREFIX` (default `48`, from 0 to 128) for an IPv6
|
|
client.
|
|
- `SWWAF_ANOMALY_ASN_...`: per AS number. Needs a lookup source.
|
|
- `SWWAF_ANOMALY_TOTAL_...`: the whole service.
|
|
- `SWWAF_WATCH_...`: each netblock in `SWWAF_WATCH_NETS`, as a whole.
|
|
`SWWAF_WATCH_NETS` (default empty) is a list of name, `=` and netblock, such
|
|
as `office=203.0.113.0/24,scraper-x=198.51.100.0/22`. An item without `=` or a
|
|
name, or with a bad netblock, is refused. So is a name used twice.
|
|
|
|
## Settings given as files
|
|
|
|
Add `_FILE` to a setting's name to read its value from a file:
|
|
`SWWAF_METRICS_TOKEN_FILE` names the file that holds `SWWAF_METRICS_TOKEN`. To
|
|
keep a token from the app, make the file on the host, owned by uid 65532 with
|
|
mode `0400`:
|
|
|
|
```sh
|
|
mkdir -p /srv/app/tokens
|
|
openssl rand -hex 32 > /srv/app/tokens/metrics
|
|
chown 65532:65532 /srv/app/tokens/metrics
|
|
chmod 0400 /srv/app/tokens/metrics
|
|
```
|
|
|
|
Mount its directory into the container read-only, and name the file:
|
|
|
|
```sh
|
|
docker run \
|
|
-v /srv/app/tokens:/etc/smallwebwaf/tokens:ro \
|
|
-e SWWAF_METRICS_TOKEN_FILE=/etc/smallwebwaf/tokens/metrics \
|
|
...
|
|
```
|
|
|
|
## Fixed limits
|
|
|
|
A few limits are fixed rather than settings:
|
|
|
|
- at most 100,000 GeoJS answers are kept;
|
|
- at most 100,000 DNS blocklist verdicts and 100,000 AbuseIPDB scores are kept;
|
|
- 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.
|