Docker Web Application Firewall (WAF) to protect against Brute Force Attacks
1.3K
Source Code: git.tjdev.de/DrMaxNix/banjo
Docker Web Application Firewall (WAF) to protect against Brute Force Attacks
429 Too Many Requests page to this client instead of forwarding calls to the application containerNote
If your first thought after reading this is, that adding another proxy to the stack will increase latency, you are totally correct! I have measured the RTT of a stack with and without Banjo: Banjo adds about 0.2ms (that's 200µs) of latency. For most use cases, this should be completely fine an not really noticeable.
Caution
As the Banjo container and your application don't know the client's IP address (they only see the address of the container before them), the first link in the chain (eg. your reverse proxy) must forward the client's IP address to following containers using the `X-Forwarded-For` HTTP header. Banjo expects this header to be set; a missing or wrong `X-Forwarded-For` header value will lead to unexpected behavior!
As described above, the application container's log must be proxied into the Banjo container. For this purpose, there is a banjo_logproxy script, which will replace the application container's entrypoint ("init script"). The banjo_logproxy script will then call the real init script (the original entrypoint) and forward all of its output not only to the docker log, but also into a named fifo pipe, which will then be mounted into the Banjo container.
Determine the original entrypoint of your application container (replace exampleorg/exampleimage with your application's image name):
$ docker inspect -f '{{ .Config.Entrypoint }}' exampleorg/exampleimage
You will see something like this, where /usr/bin/entrypoint is the original entrypoint:
[/usr/bin/entrypoint]
Now mount the banjo_logproxy script into your application's container and set it as the new entry point. Make sure to replace /usr/bin/entrypoint with the output from above!
services:
# ...
app:
# ...
volumes:
# ...
- ./banjo_logproxy:/banjo_logproxy:ro
- banjo_logproxy_data:/banjo_logproxy_data
entrypoint: /banjo_logproxy /usr/bin/entrypoint
volumes:
banjo_logproxy_data:
Tip
This assumes the `banjo_logproxy` file is placed in the same directory as the `docker-compose.yml` file. Make sure to change this accordingly. The `banjo_logproxy` script can be found in the root of this repo.
Add the Banjo service to your docker-compose.yml, configure the regex pattern and point it to your application container:
services:
banjo:
image: drmaxnix/banjo
restart: unless-stopped
environment:
LOGMATCH_REGEX: '/Login failed: (?<ip>[0-9a-f\.\:]+)/'
APPLICATION_HOST: "app"
volumes:
- ./data/banjo:/opt/banjo-data
- banjo_logproxy_data:/banjo_logproxy_data
ports:
- 127.0.0.1:80:80
# ...
volumes:
banjo_logproxy_data:
Tip
Above example will store _iplist_ files in the `./data/banjo` directory. These files help Banjo restore its ban-list after a container restart. Feel free to change this to your needs.
Now point your reverse proxy at port 80 of the Banjo container.
Important
Make sure, you don't point your reverse proxy directly at the application container and check that your application container has no publicly accessible http/https ports (eg. remove `ports` entries from `docker-compose.yml`)
docker-compose.yml Exampleservices:
banjo:
image: drmaxnix/banjo
restart: unless-stopped
environment:
LOGMATCH_REGEX: '/Login failed: (?<ip>[0-9a-f\.\:]+)/'
APPLICATION_HOST: "app"
volumes:
- ./data/banjo:/opt/banjo-data
- banjo_logproxy_data:/banjo_logproxy_data
ports:
- 127.0.0.1:80:80
app:
# ...
volumes:
# ...
- ./banjo_logproxy:/banjo_logproxy:ro
- banjo_logproxy_data:/banjo_logproxy_data
entrypoint: /banjo_logproxy /usr/bin/entrypoint
volumes:
banjo_logproxy_data:
Following configuration options are available by setting environment variables:
| Option | Type | Default | Description |
|---|---|---|---|
| DEBUG | bool | false | Whether debug logging should be enabled (not recommended for production usage) |
| LOGMATCH_ENABLED | bool | true | Whether the logmatch module should be enabled |
| LOGMATCH_FILE | string | /banjo_logproxy_data/log | Path to named pipe where log can be streamed from |
| LOGMATCH_REGEX🔸 | regex | Regex pattern to use for finding failed login attempts in the log; the IP address to be banned must be matched either as the first capturing group, or a group named ip | |
| LOGMATCH_REGEX_* | regex | empty | Additional patterns (eg. LOGMATCH_REGEX_FOO) |
| LOGMATCH_FINDTIME | duration | 12h | Interval hits are counted within |
| LOGMATCH_THRESHOLD | int | 10 | Hit count threshold after which address is being banned |
| LOGMATCH_BANTIME | duration | 6h | Duration of a ban |
| APPLICATION_HOST🔸 | host/ip | Hostname or ip address of application to forward requests to | |
| APPLICATION_PORT | int | 80 | Port number of application to forward requests to |
Options marked with
🔸are required
Explanation of types:
| Type | Description | Example(s) |
|---|---|---|
| bool | a boolean value, either true or false | true |
| string | one or more character(s) | TestTest 123 %$&/(&%$) |
| regex | string of the form /pattern/, where pattern is a valid regex pattern | /[a-z0-9]+/ |
| duration | either a number of seconds, or a number followed by a unit, which can be one of [smhd] for seconds, minutes, hours and days respectively | 15m = 15 minutes = 900 seconds |
| int | a number contained in ℤ | 1337 |
| host/ip | a hostname, domain name, or IPv4/IPv6 address | appapp.example.com198.51.100.492001:db8::a17d:661e |
Additional value restrictions may be applied on a semantic level (eg. port number must be in range 1-65535)
Content type
Image
Digest
sha256:26e50b12d…
Size
9 MB
Last updated
over 1 year ago
docker pull drmaxnix/banjo