Read every setting through viper and rename the settings (closes #211)
check / check (push) Failing after 3m27s
check / check (push) Failing after 3m27s
Every setting of discriminator and rproxy is read through viper, in place of the os.LookupEnv function Main passed down. NewViper turns AutomaticEnv and AllowEmptyEnv on, so a setting that is set but empty reads as set. A setting may also be given as a file, the _FILE form, which rproxy's settings now have too; rproxy still writes nothing to disk. The settings are renamed. Discriminator's take the prefix SWW_WAF_, rproxy's take SWW_RPROXY_, and the shared SWW_COMMAND keeps SWW_. The Core Rule Set's settings take SWW_WAF_CORE_RULE_SET_ rather than SWW_WAF_WAF_. Every place a name appeared changed: the code, the viper keys, tests, documents, examples, the README's settings table and the image files. Model: deepseek-v4-pro
This commit is contained in:
1 parent
beb503b233
commit
68da92f414
89 files changed
+2027
-1916
No files matched your search
+219
-213
@@ -4,9 +4,9 @@ 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.
|
||||
|
||||
The settings that start with `SWW_` are `discriminator`'s. Those that start with
|
||||
`SWRP_` are `rproxy`'s, and are under "`rproxy`" below. `SWW_COMMAND` chooses
|
||||
between the two (see "The image's command" below).
|
||||
The settings that start with `SWW_WAF_` are `discriminator`'s. Those that start
|
||||
with `SWW_RPROXY_` are `rproxy`'s, and are under "`rproxy`" below. `SWW_COMMAND`
|
||||
chooses between the two (see "The image's command" below).
|
||||
|
||||
## Forms of values
|
||||
|
||||
@@ -28,251 +28,256 @@ between the two (see "The image's command" below).
|
||||
|
||||
## Core
|
||||
|
||||
- `SWW_LISTEN_ADDR` (default `:8080`): where `discriminator` listens: `:` and a
|
||||
port, such as `:9000`. Leave the host out (see "Ports" in
|
||||
- `SWW_WAF_LISTEN_ADDR` (default `:8080`): where `discriminator` listens: `:`
|
||||
and a port, such as `:9000`. Leave the host out (see "Ports" in
|
||||
[`SPEC.md`](../SPEC.md)).
|
||||
- `SWW_INSTANCE_NAME` (default: the container's host name): the `instance` name
|
||||
in each line `discriminator` logs, and in each alert and metric, such as
|
||||
- `SWW_WAF_INSTANCE_NAME` (default: the container's host name): the `instance`
|
||||
name in each line `discriminator` logs, and in each alert and metric, such as
|
||||
`fsn1/discriminator`. Valid UTF-8. No control character while
|
||||
`SWW_ALERT_NTFY_URL` is set. 1 to 48 printable ASCII characters without a
|
||||
space while `SWW_LOG_REMOTE_URL` is set and `SWW_LOG_REMOTE_APP_NAME` is not.
|
||||
- `SWW_MODE` (default `enforce`): `enforce` or `observe`.
|
||||
- `SWW_IPV6_GROUP_PREFIX` (default `64`): the prefix length of an IPv6 client's
|
||||
group, from 32 to 128.
|
||||
- `SWW_MAX_TRACKED_CLIENTS` (default `20000`): the most clients kept, a whole
|
||||
number above zero.
|
||||
- `SWW_MAX_BANS` (default `5000`): how many of its own bans `discriminator`
|
||||
`SWW_WAF_ALERT_NTFY_URL` is set. 1 to 48 printable ASCII characters without a
|
||||
space while `SWW_WAF_LOG_REMOTE_URL` is set and `SWW_WAF_LOG_REMOTE_APP_NAME`
|
||||
is not.
|
||||
- `SWW_WAF_MODE` (default `enforce`): `enforce` or `observe`.
|
||||
- `SWW_WAF_IPV6_GROUP_PREFIX` (default `64`): the prefix length of an IPv6
|
||||
client's group, from 32 to 128.
|
||||
- `SWW_WAF_MAX_TRACKED_CLIENTS` (default `20000`): the most clients kept, a
|
||||
whole number above zero.
|
||||
- `SWW_WAF_MAX_BANS` (default `5000`): how many of its own bans `discriminator`
|
||||
keeps, a whole number above zero.
|
||||
|
||||
## Tokens
|
||||
|
||||
- `SWW_ADMIN_TOKEN` (default unset): the token for the ban endpoints and
|
||||
- `SWW_WAF_ADMIN_TOKEN` (default unset): the token for the ban endpoints and
|
||||
`/_sww/clients/<ip>`. At least 32 characters.
|
||||
- `SWW_METRICS_TOKEN` (default unset): the token for `/_sww/metrics`. At least
|
||||
32 characters.
|
||||
- `SWW_WAF_METRICS_TOKEN` (default unset): the token for `/_sww/metrics`. At
|
||||
least 32 characters.
|
||||
|
||||
## State files
|
||||
|
||||
- `SWW_STATE_DIR` (default `/var/lib/sww`): the directory of the state files, an
|
||||
absolute path that exists and can be written.
|
||||
- `SWW_STATE_WRITE_DELAY` (default `10s`): how long `bans.json` waits to be
|
||||
- `SWW_WAF_STATE_DIR` (default `/var/lib/sww`): the directory of the state
|
||||
files, an absolute path that exists and can be written.
|
||||
- `SWW_WAF_STATE_WRITE_DELAY` (default `10s`): how long `bans.json` waits to be
|
||||
written after a ban is made, lifted or made permanent. A duration.
|
||||
- `SWW_STATE_COUNTER_INTERVAL` (default `15m`): how often every state file is
|
||||
written. A duration.
|
||||
- `SWW_WAF_STATE_COUNTER_INTERVAL` (default `15m`): how often every state file
|
||||
is written. A duration.
|
||||
|
||||
## Logging
|
||||
|
||||
- `SWW_LOG_LEVEL` (default `info`): the least severe of `discriminator`'s own
|
||||
messages that are written: `debug`, `info`, `warn` or `error`.
|
||||
- `SWW_LOG_REQUEST_HEADERS` (default
|
||||
- `SWW_WAF_LOG_LEVEL` (default `info`): the least severe of `discriminator`'s
|
||||
own messages that are written: `debug`, `info`, `warn` or `error`.
|
||||
- `SWW_WAF_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`.
|
||||
- `SWW_LOG_REMOTE_URL` (default unset): a syslog server that also gets every
|
||||
- `SWW_WAF_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.
|
||||
- `SWW_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.
|
||||
- `SWW_LOG_REMOTE_BUFFER` (default `10000`): the most lines held while they wait
|
||||
to be sent, a whole number above zero.
|
||||
- `SWW_LOG_REMOTE_FACILITY` (default `local0`): the syslog facility: `kern`,
|
||||
- `SWW_WAF_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.
|
||||
- `SWW_WAF_LOG_REMOTE_BUFFER` (default `10000`): the most lines held while they
|
||||
wait to be sent, a whole number above zero.
|
||||
- `SWW_WAF_LOG_REMOTE_FACILITY` (default `local0`): the syslog facility: `kern`,
|
||||
`user`, `mail`, `daemon`, `auth`, `syslog`, `lpr`, `news`, `uucp`, `cron`,
|
||||
`authpriv`, `ftp`, or `local0` to `local7`.
|
||||
- `SWW_LOG_REMOTE_APP_NAME` (default: `SWW_INSTANCE_NAME`): the app name in each
|
||||
syslog record, 1 to 48 printable ASCII characters without a space.
|
||||
- `SWW_WAF_LOG_REMOTE_APP_NAME` (default: `SWW_WAF_INSTANCE_NAME`): the app name
|
||||
in each syslog record, 1 to 48 printable ASCII characters without a space.
|
||||
|
||||
## Metrics
|
||||
|
||||
- `SWW_METRICS_TOP_N` (default `50`): how many AS numbers and how many countries
|
||||
get series of their own. A whole number above zero.
|
||||
- `SWW_WAF_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
|
||||
|
||||
- `SWW_ALLOW_NETS` (default empty): netblocks you trust, such as your monitoring
|
||||
(see step 3 in [`SPEC.md`](../SPEC.md)).
|
||||
- `SWW_RATE_LIMIT_EXEMPT_NETS` (default empty): netblocks whose clients are
|
||||
- `SWW_WAF_ALLOW_NETS` (default empty): netblocks you trust, such as your
|
||||
monitoring (see step 3 in [`SPEC.md`](../SPEC.md)).
|
||||
- `SWW_WAF_RATE_LIMIT_EXEMPT_NETS` (default empty): netblocks whose clients are
|
||||
exempt from rate limiting and the byte limits.
|
||||
- `SWW_DENY_NETS` (default empty): netblocks whose clients are refused (see step
|
||||
3 in [`SPEC.md`](../SPEC.md)).
|
||||
- `SWW_WAF_DENY_NETS` (default empty): netblocks whose clients are refused (see
|
||||
step 3 in [`SPEC.md`](../SPEC.md)).
|
||||
|
||||
## Request rate limits, per client
|
||||
|
||||
- `SWW_RATE_LIMIT_PER_MINUTE` (default `120`, 2 a second): the most requests a
|
||||
client may make in a minute. A count or `off`. The default leaves room for a
|
||||
- `SWW_WAF_RATE_LIMIT_PER_MINUTE` (default `120`, 2 a second): the most requests
|
||||
a client may make in a minute. A count or `off`. The default leaves room for a
|
||||
person opening two pages at once with an empty cache, up to 60 files each.
|
||||
- `SWW_RATE_LIMIT_PER_HOUR` (default `1500`): the most requests a client may
|
||||
- `SWW_WAF_RATE_LIMIT_PER_HOUR` (default `1500`): the most requests a client may
|
||||
make in an hour. A count or `off`. It is the main limit against scrapers. A
|
||||
person reading a site for an hour, a page every 20 seconds, makes about 900. A
|
||||
scraper making one request every 2 seconds makes 1,800 an hour, more than the
|
||||
limit.
|
||||
- `SWW_RATE_LIMIT_PER_DAY` (default `6000`): the most requests a client may make
|
||||
in a day. A count or `off`. The default is four hours at the hour limit. A
|
||||
scraper making one request every 10 seconds makes 8,640 a day, more than the
|
||||
- `SWW_WAF_RATE_LIMIT_PER_DAY` (default `6000`): the most requests a client may
|
||||
make in a day. A count or `off`. The default is four hours at the hour limit.
|
||||
A scraper making one request every 10 seconds makes 8,640 a day, more than the
|
||||
limit.
|
||||
- A CI runner asks its code forge for work all day and can pass the limits. Put
|
||||
the runners' addresses in `SWW_RATE_LIMIT_EXEMPT_NETS`. Do the same for a
|
||||
the runners' addresses in `SWW_WAF_RATE_LIMIT_EXEMPT_NETS`. Do the same for a
|
||||
network where many people share one address, such as an office.
|
||||
- Counting cannot catch a client that stays under all three limits (see "Request
|
||||
rate limits, per client" in [`SPEC.md`](../SPEC.md)).
|
||||
- `SWW_RATE_LIMIT_EXEMPT_PATHS` (default empty): path prefixes exempt from rate
|
||||
limiting and the byte limits, such as `/assets/`.
|
||||
- `SWW_WAF_RATE_LIMIT_EXEMPT_PATHS` (default empty): path prefixes exempt from
|
||||
rate limiting and the byte limits, such as `/assets/`.
|
||||
|
||||
## Byte limits, per client
|
||||
|
||||
- `SWW_BYTES_LIMIT_PER_MINUTE` (default `off`), `SWW_BYTES_LIMIT_PER_HOUR`
|
||||
(default `50G`) and `SWW_BYTES_LIMIT_PER_DAY` (default `100G`): the most bytes
|
||||
counted for a client in each window. A size or `off`.
|
||||
- `SWW_BYTES_COUNT` (default `both`): which body bytes the byte limits count:
|
||||
`response`, `request` or `both`.
|
||||
- `SWW_WAF_BYTES_LIMIT_PER_MINUTE` (default `off`),
|
||||
`SWW_WAF_BYTES_LIMIT_PER_HOUR` (default `50G`) and
|
||||
`SWW_WAF_BYTES_LIMIT_PER_DAY` (default `100G`): the most bytes counted for a
|
||||
client in each window. A size or `off`.
|
||||
- `SWW_WAF_BYTES_COUNT` (default `both`): which body bytes the byte limits
|
||||
count: `response`, `request` or `both`.
|
||||
|
||||
## Lookup of AS number and country
|
||||
|
||||
- `SWW_LOOKUP_SOURCE` (default `geojs`): `geojs`, `file` or `off`. `off` stops
|
||||
the start while a setting that needs a lookup is set:
|
||||
- `SWW_WAF_LOOKUP_SOURCE` (default `geojs`): `geojs`, `file` or `off`. `off`
|
||||
stops the start while a setting that needs a lookup is set:
|
||||
- the two country lists;
|
||||
- `SWW_ADD_LOOKUP_HEADERS`;
|
||||
- the four biased threshold lists and `SWW_ASN_LIMIT_PERCENT_URL`;
|
||||
- `SWW_UNKNOWN_LIMIT_PERCENT` below `100`;
|
||||
- `SWW_WAF_ADD_LOOKUP_HEADERS`;
|
||||
- the four biased threshold lists and `SWW_WAF_ASN_LIMIT_PERCENT_URL`;
|
||||
- `SWW_WAF_UNKNOWN_LIMIT_PERCENT` below `100`;
|
||||
- an anomaly threshold per AS number.
|
||||
- `SWW_LOOKUP_DB_PATH` (default empty): the IPinfo Lite database file, in its
|
||||
`.mmdb` form, for `SWW_LOOKUP_SOURCE=file`.
|
||||
- `SWW_LOOKUP_TIMEOUT` (default `800ms`): how long a request waits for its
|
||||
- `SWW_WAF_LOOKUP_DB_PATH` (default empty): the IPinfo Lite database file, in
|
||||
its `.mmdb` form, for `SWW_WAF_LOOKUP_SOURCE=file`.
|
||||
- `SWW_WAF_LOOKUP_TIMEOUT` (default `800ms`): 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`.
|
||||
- `SWW_ADD_LOOKUP_HEADERS` (default `false`): `true` has `rproxy` pass the app
|
||||
the client's AS number in `X-Client-ASN` and its country in
|
||||
- `SWW_WAF_ADD_LOOKUP_HEADERS` (default `false`): `true` has `rproxy` pass the
|
||||
app the client's AS number in `X-Client-ASN` and its country in
|
||||
`X-Client-Country`.
|
||||
|
||||
## Country lists
|
||||
|
||||
- `SWW_DENIED_COUNTRIES` (default empty): countries whose clients are refused,
|
||||
such as `cn,ru,kp`.
|
||||
- `SWW_EXCLUSIVELY_ALLOWED_COUNTRIES` (default empty): when set, the only
|
||||
- `SWW_WAF_DENIED_COUNTRIES` (default empty): countries whose clients are
|
||||
refused, such as `cn,ru,kp`.
|
||||
- `SWW_WAF_EXCLUSIVELY_ALLOWED_COUNTRIES` (default empty): when set, the only
|
||||
countries whose clients get through, such as `us,de`. A country on both lists
|
||||
stops the start.
|
||||
|
||||
## Biased thresholds
|
||||
|
||||
- `SWW_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
|
||||
- `SWW_WAF_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.
|
||||
- `SWW_COUNTRY_LIMIT_PERCENT` (default empty): the same by country, such as
|
||||
- `SWW_WAF_COUNTRY_LIMIT_PERCENT` (default empty): the same by country, such as
|
||||
`cn:25,ru:50`.
|
||||
- `SWW_ASN_BYTES_PERCENT` and `SWW_COUNTRY_BYTES_PERCENT` (default empty): the
|
||||
same, for the byte limits alone.
|
||||
- `SWW_UNKNOWN_LIMIT_PERCENT` (default `100`): the percentage for a client the
|
||||
lookup cannot place.
|
||||
- `SWW_ASN_LIMIT_PERCENT_URL` (default unset): the `http` or `https` URL of a
|
||||
text file with one AS number and percentage on each line, such as
|
||||
`AS64496:50`. A URL that is also in `SWW_BLOCKLIST_URLS` is refused.
|
||||
- `SWW_WAF_ASN_BYTES_PERCENT` and `SWW_WAF_COUNTRY_BYTES_PERCENT` (default
|
||||
empty): the same, for the byte limits alone.
|
||||
- `SWW_WAF_UNKNOWN_LIMIT_PERCENT` (default `100`): the percentage for a client
|
||||
the lookup cannot place.
|
||||
- `SWW_WAF_ASN_LIMIT_PERCENT_URL` (default unset): the `http` or `https` URL of
|
||||
a text file with one AS number and percentage on each line, such as
|
||||
`AS64496:50`. A URL that is also in `SWW_WAF_BLOCKLIST_URLS` is refused.
|
||||
|
||||
## Attack detection
|
||||
|
||||
- `SWW_RULES_DIR` (default `/etc/sww/rules.d`): the directory of the rule files.
|
||||
- `SWW_RULES_ENABLED` (default `true`): `false` reads no rule file.
|
||||
- `SWW_TRAP_PATHS` (default empty): paths only scanners ask for, such as
|
||||
- `SWW_WAF_RULES_DIR` (default `/etc/sww/rules.d`): the directory of the rule
|
||||
files.
|
||||
- `SWW_WAF_RULES_ENABLED` (default `true`): `false` reads no rule file.
|
||||
- `SWW_WAF_TRAP_PATHS` (default empty): paths only scanners ask for, such as
|
||||
`/wp-login.php,/xmlrpc.php`. Each starts with `/` and holds no `?`.
|
||||
- `SWW_WAF_MODE` (default `block`): `off`, `detect` or `block`.
|
||||
- `SWW_WAF_PARANOIA_LEVEL` (default `1`): the Core Rule Set's paranoia level,
|
||||
from 1 to 4.
|
||||
- `SWW_WAF_ANOMALY_THRESHOLD` (default `5`): the score at which a request is a
|
||||
match. A whole number above zero, or `off`.
|
||||
- `SWW_WAF_DISABLED_RULES` (default
|
||||
- `SWW_WAF_CORE_RULE_SET_MODE` (default `block`): `off`, `detect` or `block`.
|
||||
- `SWW_WAF_CORE_RULE_SET_PARANOIA_LEVEL` (default `1`): the Core Rule Set's
|
||||
paranoia level, from 1 to 4.
|
||||
- `SWW_WAF_CORE_RULE_SET_ANOMALY_THRESHOLD` (default `5`): the score at which a
|
||||
request is a match. A whole number above zero, or `off`.
|
||||
- `SWW_WAF_CORE_RULE_SET_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.
|
||||
- `SWW_WAF_EXEMPT_PATHS` (default empty): path prefixes the Core Rule Set does
|
||||
not inspect.
|
||||
- `SWW_WAF_BODY_LIMIT` (default `off`): `off`, or how much of a request body the
|
||||
Core Rule Set reads, a size of at most `64K`. A question carries no more of a
|
||||
body than 64 KiB, and the Core Rule Set reads at most 64 KiB less one byte of
|
||||
it, whatever the value (see "The answer" in [`SPEC.md`](../SPEC.md)).
|
||||
- `SWW_CORE_RULE_SET_EXCLUSIONS_FILE` (default unset): a file of Core Rule Set
|
||||
exclusions, written as Coraza directives. It is loaded before the Core Rule
|
||||
Set's rules, so it holds only `SecAction` and `SecRule` lines that exclude
|
||||
with `ctl:ruleRemoveTargetById` or `ctl:ruleRemoveById`. A file that cannot be
|
||||
read or does not parse stops the start, whatever `SWW_WAF_MODE` is. So does a
|
||||
file that names a number from 900000 to 900999 outside a comment, alone or in
|
||||
a range. So does a directive that removes or changes rules as the file loads,
|
||||
such as `SecRuleRemoveById`, since none of the Core Rule Set's rules is loaded
|
||||
yet. It has no `_FILE` form.
|
||||
- `SWW_ERROR_BURST_THRESHOLD` (default `30`): the most refusals of one client in
|
||||
a minute (see "Attack detection" in `SPEC.md`). A count or `off`.
|
||||
- `SWW_WAF_CORE_RULE_SET_EXEMPT_PATHS` (default empty): path prefixes the Core
|
||||
Rule Set does not inspect.
|
||||
- `SWW_WAF_CORE_RULE_SET_BODY_LIMIT` (default `off`): `off`, or how much of a
|
||||
request body the Core Rule Set reads, a size of at most `64K`. A question
|
||||
carries no more of a body than 64 KiB, and the Core Rule Set reads at most 64
|
||||
KiB less one byte of it, whatever the value (see "The answer" in
|
||||
[`SPEC.md`](../SPEC.md)).
|
||||
- `SWW_WAF_CORE_RULE_SET_EXCLUSIONS_FILE` (default unset): a file of Core Rule
|
||||
Set exclusions, written as Coraza directives. It is loaded before the Core
|
||||
Rule Set's rules, so it holds only `SecAction` and `SecRule` lines that
|
||||
exclude with `ctl:ruleRemoveTargetById` or `ctl:ruleRemoveById`. A file that
|
||||
cannot be read or does not parse stops the start, whatever
|
||||
`SWW_WAF_CORE_RULE_SET_MODE` is. So does a file that names a number from
|
||||
900000 to 900999 outside a comment, alone or in a range. So does a directive
|
||||
that removes or changes rules as the file loads, such as `SecRuleRemoveById`,
|
||||
since none of the Core Rule Set's rules is loaded yet. It has no `_FILE` form.
|
||||
- `SWW_WAF_ERROR_BURST_THRESHOLD` (default `30`): the most refusals of one
|
||||
client in a minute (see "Attack detection" in `SPEC.md`). A count or `off`.
|
||||
|
||||
## Ban lengths, response and scope
|
||||
|
||||
- `SWW_BAN_RESPONSE` (default `403`): `403`, `429` or `close`.
|
||||
- `SWW_LIMIT_BAN_DURATION` (default `1h`): the ban for a first broken limit. A
|
||||
duration.
|
||||
- `SWW_LIMIT_BAN_REPEAT_WINDOW` (default `24h`): the time after a ban ends
|
||||
- `SWW_WAF_BAN_RESPONSE` (default `403`): `403`, `429` or `close`.
|
||||
- `SWW_WAF_LIMIT_BAN_DURATION` (default `1h`): the ban for a first broken limit.
|
||||
A duration.
|
||||
- `SWW_WAF_LIMIT_BAN_REPEAT_WINDOW` (default `24h`): the time after a ban ends
|
||||
within which breaking a limit again lengthens the next ban. A duration.
|
||||
- `SWW_MAX_BAN_DURATION` (default `7d`): the longest ban for a broken limit; one
|
||||
that would be longer is permanent. A duration.
|
||||
- `SWW_ATTACK_BAN_DURATION` (default `7d`): the ban for a first clear sign of
|
||||
attack. A duration.
|
||||
- `SWW_BAN_SCOPE_V4_PREFIX` (default `32`): how much a ban on an IPv4 client
|
||||
- `SWW_WAF_MAX_BAN_DURATION` (default `7d`): the longest ban for a broken limit;
|
||||
one that would be longer is permanent. A duration.
|
||||
- `SWW_WAF_ATTACK_BAN_DURATION` (default `7d`): the ban for a first clear sign
|
||||
of attack. A duration.
|
||||
- `SWW_WAF_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
|
||||
|
||||
- `SWW_BLOCKLIST_URLS` (default empty): blocklists to fetch, such as
|
||||
- `SWW_WAF_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.
|
||||
- `SWW_BLOCKLIST_REFRESH` (default `24h`): how long a list waits after its last
|
||||
try before it is fetched again. A duration of `1h` or more.
|
||||
- `SWW_BLOCKLIST_ACTION` (default `deny`): `deny`, `limit:<percent>` or `log`.
|
||||
- `SWW_DNSBL_ZONES` (default empty): the DNS blocklists to ask, such as
|
||||
- `SWW_WAF_BLOCKLIST_REFRESH` (default `24h`): how long a list waits after its
|
||||
last try before it is fetched again. A duration of `1h` or more.
|
||||
- `SWW_WAF_BLOCKLIST_ACTION` (default `deny`): `deny`, `limit:<percent>` or
|
||||
`log`.
|
||||
- `SWW_WAF_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.
|
||||
- `SWW_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.
|
||||
- `SWW_ABUSEIPDB_KEY` (default unset): the key of your AbuseIPDB account. A
|
||||
- `SWW_WAF_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.
|
||||
- `SWW_WAF_ABUSEIPDB_KEY` (default unset): the key of your AbuseIPDB account. A
|
||||
control character in it is refused.
|
||||
- `SWW_ABUSEIPDB_MIN_SCORE` (default `75`): the least abuse confidence score,
|
||||
from 0 to 100, that is a hit.
|
||||
- `SWW_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.
|
||||
- `SWW_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
|
||||
`SWW_BLOCKLIST_URLS`, or that is `SWW_ASN_LIMIT_PERCENT_URL`.
|
||||
- `SWW_CROWDSEC_LAPI_KEY` (default unset): the key the engine gave for
|
||||
- `SWW_WAF_ABUSEIPDB_MIN_SCORE` (default `75`): the least abuse confidence
|
||||
score, from 0 to 100, that is a hit.
|
||||
- `SWW_WAF_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.
|
||||
- `SWW_WAF_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
|
||||
`SWW_WAF_BLOCKLIST_URLS`, or that is `SWW_WAF_ASN_LIMIT_PERCENT_URL`.
|
||||
- `SWW_WAF_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.
|
||||
- `SWW_REPUTATION_ACTION` (default `limit:25`): `deny`, `limit:<percent>` or
|
||||
- `SWW_WAF_REPUTATION_ACTION` (default `limit:25`): `deny`, `limit:<percent>` or
|
||||
`log`, for DNS blocklist and AbuseIPDB hits.
|
||||
- `SWW_REPUTATION_CACHE_TTL` (default `24h`): how long a zone's verdict or
|
||||
- `SWW_WAF_REPUTATION_CACHE_TTL` (default `24h`): how long a zone's verdict or
|
||||
AbuseIPDB's score is used. A duration.
|
||||
- `SWW_REPUTATION_TIMEOUT` (default `2s`): how long a query to a zone or a check
|
||||
with AbuseIPDB may take. A duration.
|
||||
- `SWW_WAF_REPUTATION_TIMEOUT` (default `2s`): how long a query to a zone or a
|
||||
check with AbuseIPDB may take. A duration.
|
||||
|
||||
## Alerting
|
||||
|
||||
- `SWW_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.
|
||||
- `SWW_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.
|
||||
- `SWW_ALERT_SLACK_WEBHOOK_URL` (default unset): the Slack incoming webhook that
|
||||
receives each alert as a message, checked as the webhook URL is.
|
||||
- `SWW_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.
|
||||
- `SWW_ALERT_NTFY_TOKEN` (default unset): an ntfy access token. A control
|
||||
- `SWW_WAF_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.
|
||||
- `SWW_WAF_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.
|
||||
- `SWW_WAF_ALERT_SLACK_WEBHOOK_URL` (default unset): the Slack incoming webhook
|
||||
that receives each alert as a message, checked as the webhook URL is.
|
||||
- `SWW_WAF_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.
|
||||
- `SWW_WAF_ALERT_NTFY_TOKEN` (default unset): an ntfy access token. A control
|
||||
character in it is refused.
|
||||
- `SWW_ALERT_EVENTS` (default
|
||||
- `SWW_WAF_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.
|
||||
- `SWW_ALERT_COOLDOWN` (default `15m`): how long after an alert is sent its
|
||||
- `SWW_WAF_ALERT_COOLDOWN` (default `15m`): how long after an alert is sent its
|
||||
repeats are held back. A duration or `off`.
|
||||
- `SWW_ALERT_MAX_PER_HOUR` (default `60`): the most alerts sent in an hour. A
|
||||
whole number above zero, or `off`.
|
||||
- `SWW_WAF_ALERT_MAX_PER_HOUR` (default `60`): the most alerts sent in an hour.
|
||||
A whole number above zero, or `off`.
|
||||
|
||||
## Anomaly thresholds
|
||||
|
||||
@@ -280,25 +285,25 @@ 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:
|
||||
|
||||
- `SWW_ANOMALY_CLIENT_REQUESTS_PER_MINUTE`;
|
||||
- `SWW_ANOMALY_CLIENT_REQUESTS_PER_HOUR`;
|
||||
- `SWW_ANOMALY_CLIENT_BYTES_PER_MINUTE`;
|
||||
- `SWW_ANOMALY_CLIENT_BYTES_PER_HOUR`.
|
||||
- `SWW_WAF_ANOMALY_CLIENT_REQUESTS_PER_MINUTE`;
|
||||
- `SWW_WAF_ANOMALY_CLIENT_REQUESTS_PER_HOUR`;
|
||||
- `SWW_WAF_ANOMALY_CLIENT_BYTES_PER_MINUTE`;
|
||||
- `SWW_WAF_ANOMALY_CLIENT_BYTES_PER_HOUR`.
|
||||
|
||||
The other scopes' names have another prefix before the same four endings, such
|
||||
as `REQUESTS_PER_MINUTE`:
|
||||
|
||||
- `SWW_ANOMALY_NET_...`: per netblock around a client. Two settings give the
|
||||
- `SWW_WAF_ANOMALY_NET_...`: per netblock around a client. Two settings give the
|
||||
netblock's length:
|
||||
- `SWW_ANOMALY_NET_V4_PREFIX` (default `24`, from 0 to 32) for an IPv4
|
||||
- `SWW_WAF_ANOMALY_NET_V4_PREFIX` (default `24`, from 0 to 32) for an IPv4
|
||||
client;
|
||||
- `SWW_ANOMALY_NET_V6_PREFIX` (default `48`, from 0 to 128) for an IPv6
|
||||
- `SWW_WAF_ANOMALY_NET_V6_PREFIX` (default `48`, from 0 to 128) for an IPv6
|
||||
client.
|
||||
- `SWW_ANOMALY_ASN_...`: per AS number.
|
||||
- `SWW_ANOMALY_TOTAL_...`: the whole service.
|
||||
- `SWW_WATCH_...`: each netblock in `SWW_WATCH_NETS`, as a whole.
|
||||
`SWW_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
|
||||
- `SWW_WAF_ANOMALY_ASN_...`: per AS number.
|
||||
- `SWW_WAF_ANOMALY_TOTAL_...`: the whole service.
|
||||
- `SWW_WAF_WATCH_...`: each netblock in `SWW_WAF_WATCH_NETS`, as a whole.
|
||||
`SWW_WAF_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
|
||||
@@ -319,7 +324,7 @@ Then mount its directory into the container read-only, and name the file:
|
||||
docker run \
|
||||
-v /srv/app/tokens:/etc/sww/tokens:ro \
|
||||
-e SWW_COMMAND=discriminator \
|
||||
-e SWW_METRICS_TOKEN_FILE=/etc/sww/tokens/metrics \
|
||||
-e SWW_WAF_METRICS_TOKEN_FILE=/etc/sww/tokens/metrics \
|
||||
...
|
||||
```
|
||||
|
||||
@@ -343,51 +348,52 @@ A few limits are fixed rather than settings:
|
||||
|
||||
## `discriminator`'s answer and `rproxy`'s wait
|
||||
|
||||
`SWW_LOOKUP_TIMEOUT` is the longest a question waits on an outside source. Keep
|
||||
it well under `rproxy`'s `SWRP_TIMEOUT_MS`, as the default is. No question waits
|
||||
for `SWW_REPUTATION_TIMEOUT`, since the DNS blocklists and AbuseIPDB are asked
|
||||
in the background (see "Answering in time" under "`discriminator`" in
|
||||
[`SPEC.md`](../SPEC.md)).
|
||||
`SWW_WAF_LOOKUP_TIMEOUT` is the longest a question waits on an outside source.
|
||||
Keep it well under `rproxy`'s `SWW_RPROXY_TIMEOUT_MS`, as the default is. No
|
||||
question waits for `SWW_WAF_REPUTATION_TIMEOUT`, since the DNS blocklists and
|
||||
AbuseIPDB are asked in the background (see "Answering in time" under
|
||||
"`discriminator`" in [`SPEC.md`](../SPEC.md)).
|
||||
|
||||
## `rproxy`
|
||||
|
||||
`sww rproxy` reads the settings below and no others. 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.
|
||||
start, and an invalid value stops the start. Any can be given as a file, as a
|
||||
`SWW_WAF_` setting can. "`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): `discriminator`'s URL. An `http` or
|
||||
`https` URL with a host and an optional port, and nothing more. `rproxy`
|
||||
speaks HTTP/1.1 to it.
|
||||
- `SWRP_TIMEOUT_MS` (default `2000`): how long `rproxy` waits for
|
||||
- `SWW_RPROXY_WAF_BACKEND` (required, no default): `discriminator`'s URL. An
|
||||
`http` or `https` URL with a host and an optional port, and nothing more.
|
||||
`rproxy` speaks HTTP/1.1 to it.
|
||||
- `SWW_RPROXY_TIMEOUT_MS` (default `2000`): how long `rproxy` waits for
|
||||
`discriminator`'s answer, to a question and to a report. A time; never `off`.
|
||||
- `SWRP_DEFAULT_DISPOSITION` (default `allow`): what is done with a request when
|
||||
`discriminator` cannot be connected to, does not answer at all, or does not
|
||||
answer within `SWRP_TIMEOUT_MS`. `allow` passes it to the app, and `deny`
|
||||
answers `503`. It does not apply to an answer `discriminator` gives, such as
|
||||
an error.
|
||||
- `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. A client outside these netblocks cannot claim another address. Where
|
||||
other containers reach `rproxy` directly, or visitors on a private network
|
||||
reach traefik, they can name another address in the header. Narrowing the
|
||||
setting to traefik's own network closes that gap.
|
||||
- `SWW_RPROXY_DEFAULT_DISPOSITION` (default `allow`): what is done with a
|
||||
request when `discriminator` cannot be connected to, does not answer at all,
|
||||
or does not answer within `SWW_RPROXY_TIMEOUT_MS`. `allow` passes it to the
|
||||
app, and `deny` answers `503`. It does not apply to an answer `discriminator`
|
||||
gives, such as an error.
|
||||
- `SWW_RPROXY_MAX_REQUEST_SIZE` (default `100M`): the largest request body. A
|
||||
size or `off`.
|
||||
- `SWW_RPROXY_MAX_RESPONSE_SIZE` (default `1G`): the largest response body. A
|
||||
size or `off`.
|
||||
- `SWW_RPROXY_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`.
|
||||
- `SWW_RPROXY_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`.
|
||||
- `SWW_RPROXY_LISTEN_ADDR` (default `:8080`): where `rproxy` listens, such as
|
||||
`:9000`.
|
||||
- `SWW_RPROXY_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.
|
||||
- `SWW_RPROXY_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. A client
|
||||
outside these netblocks cannot claim another address. Where other containers
|
||||
reach `rproxy` directly, or visitors on a private network reach traefik, they
|
||||
can name another address in the header. Narrowing the setting to traefik's own
|
||||
network closes that gap.
|
||||
|
||||
## The image's command
|
||||
|
||||
@@ -399,14 +405,14 @@ check checks: `rproxy` or `discriminator` (see "Deployment" in
|
||||
|
||||
Nothing reads these names any more:
|
||||
|
||||
- `SWW_UPSTREAM_URL` is `SWRP_UPSTREAM_URL`.
|
||||
- `SWW_TRUSTED_PROXIES` is `SWRP_TRUSTED_PROXIES`.
|
||||
- `SWW_REQUEST_MAX_BYTES` is `SWRP_MAX_REQUEST_SIZE`.
|
||||
- `SWW_RESPONSE_MAX_BYTES` is `SWRP_MAX_RESPONSE_SIZE`.
|
||||
- `SWW_CLIENT_REQUEST_TIMEOUT` and `SWW_UPSTREAM_REQUEST_TIMEOUT` are
|
||||
`SWRP_MAX_REQUEST_TIME_MS`, in milliseconds.
|
||||
- `SWW_CLIENT_RESPONSE_TIMEOUT` and `SWW_UPSTREAM_RESPONSE_TIMEOUT` are
|
||||
`SWRP_MAX_RESPONSE_TIME_MS`, in milliseconds.
|
||||
- `SWW_CLIENT_IDLE_TIMEOUT` and `SWW_CLIENT_REQUEST_HEADER_MAX_BYTES` have no
|
||||
setting. `rproxy` closes a kept-open connection idle for 120 seconds, and
|
||||
takes a request line and headers of at most 32 KiB.
|
||||
- `SWW_WAF_UPSTREAM_URL` is `SWW_RPROXY_UPSTREAM_URL`.
|
||||
- `SWW_WAF_TRUSTED_PROXIES` is `SWW_RPROXY_TRUSTED_PROXIES`.
|
||||
- `SWW_WAF_REQUEST_MAX_BYTES` is `SWW_RPROXY_MAX_REQUEST_SIZE`.
|
||||
- `SWW_WAF_RESPONSE_MAX_BYTES` is `SWW_RPROXY_MAX_RESPONSE_SIZE`.
|
||||
- `SWW_WAF_CLIENT_REQUEST_TIMEOUT` and `SWW_WAF_UPSTREAM_REQUEST_TIMEOUT` are
|
||||
`SWW_RPROXY_MAX_REQUEST_TIME_MS`, in milliseconds.
|
||||
- `SWW_WAF_CLIENT_RESPONSE_TIMEOUT` and `SWW_WAF_UPSTREAM_RESPONSE_TIMEOUT` are
|
||||
`SWW_RPROXY_MAX_RESPONSE_TIME_MS`, in milliseconds.
|
||||
- `SWW_WAF_CLIENT_IDLE_TIMEOUT` and `SWW_WAF_CLIENT_REQUEST_HEADER_MAX_BYTES`
|
||||
have no setting. `rproxy` closes a kept-open connection idle for 120 seconds,
|
||||
and takes a request line and headers of at most 32 KiB.
|
||||
Reference in new issue
Block a user