diff --git a/README.md b/README.md index a72b3b4..062df59 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,6 @@ Non-exhaustive list of features : - Block TOR, proxies, bad user-agents, countries, ... - Block known bad IP with DNSBL and CrowdSec - Prevent bruteforce attacks with rate limiting -- Detect bad files with ClamAV - Easy to configure with environment variables or web UI - Automatic configuration with container labels - Docker Swarm support @@ -357,8 +356,6 @@ docker service create --name anotherapp \ ## Web UI -**This feature exposes, for now, a security risk because you need to mount the docker socket inside a container exposing a web application. You can test it but you should not use it in servers facing the internet.** - A dedicated image, *bunkerized-nginx-ui*, lets you manage bunkerized-nginx instances and services configurations through a web user interface. This feature is still in beta, feel free to open a new issue if you find a bug and/or you have an idea to improve it. First we need a volume that will store the configurations : @@ -383,6 +380,7 @@ docker run -p 80:8080 \ -e AUTO_LETS_ENCRYPT=yes \ -e REDIRECT_HTTP_TO_HTTPS=yes \ -e DISABLE_DEFAULT_SERVER=yes \ + -e admin.domain.com_USE_MODSECURITY=no \ -e admin.domain.com_SERVE_FILES=no \ -e admin.domain.com_USE_AUTH_BASIC=yes \ -e admin.domain.com_AUTH_BASIC_USER=admin \ @@ -394,7 +392,7 @@ docker run -p 80:8080 \ bunkerity/bunkerized-nginx ``` -The `AUTH_BASIC` environment variables let you define a login/password that must be provided before accessing to the web UI. At the moment, there is no authentication mechanism integrated into bunkerized-nginx-ui. +The `AUTH_BASIC` environment variables let you define a login/password that must be provided before accessing to the web UI. At the moment, there is no authentication mechanism integrated into bunkerized-nginx-ui so **using auth basic with a strong password coupled with a "hard to guess" URI is strongly recommended**. We can now create the bunkerized-nginx-ui container that will host the web UI behind bunkerized-nginx : diff --git a/docs/environment_variables.md b/docs/environment_variables.md index 9f95a1d..9a52926 100644 --- a/docs/environment_variables.md +++ b/docs/environment_variables.md @@ -87,6 +87,18 @@ Default value : *8443* Context : *global* The HTTPS port number used by nginx inside the container. +`WORKER_CONNECTIONS` +Values : *\* +Default value : 1024 +Context : *global* +Sets the value of the [worker_connections](https://nginx.org/en/docs/ngx_core_module.html#worker_connections) directive. + +`WORKER_RLIMIT_NOFILE` +Values : *\* +Default value : 2048 +Context : *global* +Sets the value of the [worker_rlimit_nofile](https://nginx.org/en/docs/ngx_core_module.html#worker_rlimit_nofile) directive. + ### Information leak `SERVER_TOKENS` @@ -182,7 +194,7 @@ You can set multiple url/host by adding a suffix number to the variable name lik Values : *yes* | *no* Default value : *no* Context : *global*, *multisite* -Set this environment variable to *yes* if you're using bunkerized-nginx behind a reverse proxy. This means you will see the real client address instead of the proxy one inside your logs. Modsecurity, fail2ban and others security tools will also then work correctly. +Set this environment variable to *yes* if you're using bunkerized-nginx behind a reverse proxy. This means you will see the real client address instead of the proxy one inside your logs. Ssecurity tools will also then work correctly. `PROXY_REAL_IP_FROM` Values : *\* @@ -501,6 +513,12 @@ Context : *global*, *multisite* If set to yes, the [OWASP ModSecurity Core Rule Set](https://coreruleset.org/) will be used. It provides generic rules to detect common web attacks. You can customize the CRS (i.e. : add WordPress exclusions) by adding custom .conf files into the /modsec-crs-confs/ directory inside the container (i.e : through a volume). Files inside this directory are included before the CRS rules. If you need to tweak (i.e. : SecRuleUpdateTargetById) put .conf files inside the /modsec-confs/ which is included after the CRS rules. +`MODSECURITY_SEC_AUDIT_ENGINE` +Values : *On* | *Off* | *RelevantOnly* +Default value : *RelevantOnly* +Context : *global*, *multisite* +Sets the value of the [SecAuditEngine directive](https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual-%28v2.x%29#SecAuditEngine) of ModSecurity. + ## Security headers `X_FRAME_OPTIONS` @@ -859,82 +877,6 @@ Default value : *60* Context : *global* The duration time (in seconds) before the counter of "suspicious" HTTP is reset. -## ClamAV - -`USE_CLAMAV_UPLOAD` -Values : *yes* | *no* -Default value : *yes* -Context : *global*, *multisite* -If set to yes, ClamAV will scan every file uploads and block the upload if the file is detected. - -`USE_CLAMAV_SCAN` -Values : *yes* | *no* -Default value : *yes* -Context : *global* -If set to yes, ClamAV will scan all the files inside the container every day. - -`CLAMAV_SCAN_REMOVE` -Values : *yes* | *no* -Default value : *yes* -Context : *global* -If set to yes, ClamAV will automatically remove the detected files. - -## Cron jobs - -`AUTO_LETS_ENCRYPT_CRON` -Values : *\* -Default value : *15 0 \* \* \** -Context : *global* -Cron expression of how often certbot will try to renew the certificates. - -`BLOCK_USER_AGENT_CRON` -Values : *\* -Default value : *30 0 \* \* \* \** -Context : *global* -Cron expression of how often the blacklist of user agent is updated. - -`BLOCK_TOR_EXIT_NODE_CRON` -Values : *\* -Default value : *0 \*/1 \* \* \* \** -Context : *global* -Cron expression of how often the blacklist of tor exit node is updated. - -`BLOCK_PROXIES_CRON` -Values : *\* -Default value : *0 3 \* \* \* \** -Context : *global* -Cron expression of how often the blacklist of proxies is updated. - -`BLOCK_ABUSERS_CRON` -Values : *\* -Default value : *0 2 \* \* \* \** -Context : *global* -Cron expression of how often the blacklist of abusers is updated. - -`BLOCK_REFERRER_CRON` -Values : *\* -Default value : *45 0 \* \* \* \** -Context : *global* -Cron expression of how often the blacklist of referrer is updated. - -`GEOIP_CRON` -Values : *\* -Default value : *0 4 2 \* \** -Context : *global* -Cron expression of how often the GeoIP database is updated. - -`USE_CLAMAV_SCAN_CRON` -Values : *\* -Default value : *30 1 \* \* \** -Context : *global* -Cron expression of how often ClamAV will scan all the files inside the container. - -`CLAMAV_UPDATE_CRON` -Values : *\* -Default value : *0 1 \* \* \** -Context : *global* -Cron expression of how often ClamAV will update its database. - ## misc `SWARM_MODE` diff --git a/docs/introduction.md b/docs/introduction.md index 79f8af9..8602e18 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -17,7 +17,6 @@ Non-exhaustive list of features : - Block TOR, proxies, bad user-agents, countries, ... - Block known bad IP with DNSBL and CrowdSec - Prevent bruteforce attacks with rate limiting -- Detect bad files with ClamAV - Easy to configure with environment variables or web UI - Automatic configuration with container labels - Docker Swarm support diff --git a/docs/security_tuning.md b/docs/security_tuning.md index f6d6a9a..d0d8616 100644 --- a/docs/security_tuning.md +++ b/docs/security_tuning.md @@ -53,6 +53,12 @@ $ docker run -p 80:8080 \ Please note that if you have one or more intermediate certificate(s) in your chain of trust, you will need to provide the bundle to `CUSTOM_HTTPS_CERT` (more info [here](https://nginx.org/en/docs/http/configuring_https_servers.html#chains)). +You can reload the certificate(s) (e.g. : in case of a renewal) by sending the SIGHUP/HUP signal to the container bunkerized-nginx will catch the signal and send a reload order to nginx : + +```shell +docker kill --signal=SIGHUP my-container +``` + ### Self-signed certificate This method is not recommended in production but can be used to quickly deploy HTTPS for testing purposes. Just use the `GENERATE_SELF_SIGNED_SSL=yes` environment variable and bunkerized-nginx will generate a self-signed certificate for you : @@ -133,7 +139,7 @@ CrowdSec is not enabled by default because it's more than an external blacklists - `CROWDSEC_HOST=` : full URL to your CrowdSec instance API - `CROWDSEC_KEY=` : bouncer key given from **cscli bouncer add MyBouncer** -If you want to give it a try, you have a concrete example on how to use CrowdSec with bunkerized-nginx [here](https://github.com/bunkerity/bunkerized-nginx/tree/master/examples/crowdsec). +You will also need to share the logs generated by bunkerized-nginx with your CrowdSec instance. One approach is to send the logs to a syslog server which is writing the logs to the file system and then CrowdSec can easily read the logs. If you want to give it a try, you have a concrete example on how to use CrowdSec with bunkerized-nginx [here](https://github.com/bunkerity/bunkerized-nginx/tree/master/examples/crowdsec). ### User-Agents @@ -244,6 +250,8 @@ docker run --network mynet \ ## Container hardening +You will find a ready to use docker-compose.yml file focused on container hardening [here](https://github.com/bunkerity/bunkerized-nginx/tree/master/examples/hardened). + ### Drop capabilities By default, *bunkerized-nginx* runs as non-root user inside the container and should not use any of the default [capabilities](https://docs.docker.com/engine/security/#linux-kernel-capabilities) allowed by Docker. You can safely remove all capabilities to harden the container : @@ -258,6 +266,13 @@ Bunkerized-nginx should never tries to gain additional privileges through setuid docker run ... --security-opt no-new-privileges ... bunkerity/bunkerized-nginx ``` +### Read-only +Since the locations where bunkerized-nginx needs to write are known, we can run the container with a read-only root file system and only allow writes to specific locations by adding volumes and a tmpfs mount : + +```shell +docker run ... --read-only --tmpfs /tmp -v cache-vol:/cache -v conf-vol:/etc/nginx -v /path/to/web/files:/www:ro -v /where/to/store/certificates:/etc/letsencrypt bunkerity/bunkerized-nginx +``` + ### User namespace remap Another hardening trick is [user namespace remapping](https://docs.docker.com/engine/security/userns-remap/) : it allows you to map the UID/GID of users inside a container to another UID/GID on the host. For example, you can map the user nginx with UID/GID 101 inside the container to a non-existent user with UID/GID 100101 on the host. diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 8e47356..e2f76e2 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -4,7 +4,7 @@ When troubleshooting, the logs are your best friends. We try our best to provide user-friendly logs to help you understand what happened. Please note that we don't store the logs inside the container, they are all displayed on stdout/stderr so Docker can capture them. They can be displayed using the [docker logs](https://docs.docker.com/engine/reference/commandline/logs/) command. -You can edit the `LOG_LEVEL` environment variable to increase or decrease the verbosity of logs with the following values : `debug`, `info`, `notice`, `warn`, `error`, `crit`, `alert` or `emerg`. +You can edit the `LOG_LEVEL` environment variable to increase or decrease the verbosity of logs with the following values : `debug`, `info`, `notice`, `warn`, `error`, `crit`, `alert` or `emerg` (with `debug` being the most verbose level). ## Permissions @@ -22,9 +22,13 @@ Some additional resources : - [Handling false positive](https://www.netnea.com/cms/apache-tutorial-8_handling-false-positives-modsecurity-core-rule-set/) - [Adding exceptions and tuning](https://coreruleset.org/docs/exceptions.html) +## Bad behavior + +The [bad behavior](https://bunkerized-nginx.readthedocs.io/en/latest/security_tuning.html#bad-behaviors-detection) feature comes with a set of status codes considered as "suspicious". You may need to tweak the corresponding list to avoid false positives within your application. + ## Whitelisting -It's a common case that a bot gets flagged as suspicious and can't access your website. Instead of disabling the corresponding security feature(s) we recommend a whitelist approach. Here is a list of environment variables you can use : +It's a common case that a bot gets flagged as suspicious and can't access your website. Instead of disabling the corresponding security feature(s) we recommend a whitelisting approach. Here is a list of environment variables you can use : - `WHITELIST_IP_LIST` - `WHITELIST_REVERSE_LIST` diff --git a/settings.json b/settings.json index 52c7f25..4d7f148 100644 --- a/settings.json +++ b/settings.json @@ -375,38 +375,6 @@ } ] }, - "ClamAV": { - "id": "clamav", - "params": [ - { - "context": "multisite", - "default": "yes", - "env": "USE_CLAMAV_UPLOAD", - "id": "use-clamav-upload", - "label": "Use clamav upload", - "regex": "^(yes|no)$", - "type": "checkbox" - }, - { - "context": "global", - "default": "yes", - "env": "USE_CLAMAV_SCAN", - "id": "use-clamav-scan", - "label": "Use clamav scan", - "regex": "^(yes|no)$", - "type": "checkbox" - }, - { - "context": "global", - "default": "yes", - "env": "CLAMAV_SCAN_REMOVE", - "id": "clamav-scan-remove", - "label": "Clamav scan remove", - "regex": "^(yes|no)$", - "type": "checkbox" - } - ] - }, "Compression": { "id": "compression", "params": [