mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
[#1308] Add support for CRS v4 plugins via custom configurations but also via the new MODSECURITY_CRS_PLUGIN_URLS setting that automatically downloads and handles updates of CRS compatible plugins
This commit is contained in:
parent
bb0dc15dec
commit
676d65267e
29 changed files with 539 additions and 167 deletions
|
|
@ -356,7 +356,7 @@ Each job has the following fields :
|
|||
|
||||
### Configurations
|
||||
|
||||
You can add custom NGINX configurations by adding a folder named **confs** with content similar to the [custom configurations](quickstart-guide.md#custom-configurations). Each subfolder inside the **confs** will contain [jinja2](https://jinja.palletsprojects.com) templates that will be generated and loaded at the corresponding context (`http`, `server-http`, `default-server-http`, `stream`, `server-stream`, `modsec` and `modsec-crs`).
|
||||
You can add custom NGINX configurations by adding a folder named **confs** with content similar to the [custom configurations](quickstart-guide.md#custom-configurations). Each subfolder inside the **confs** will contain [jinja2](https://jinja.palletsprojects.com) templates that will be generated and loaded at the corresponding context (`http`, `server-http`, `default-server-http`, `stream`, `server-stream`, `modsec`, `modsec-crs`, `crs-plugins-before` and `crs-plugins-after`).
|
||||
|
||||
Here is an example for a configuration template file inside the **confs/server-http** folder named **example.conf** :
|
||||
|
||||
|
|
|
|||
|
|
@ -1115,6 +1115,8 @@ Here are the available types of custom configurations:
|
|||
- **modsec**: Configurations applied after the OWASP Core Rule Set is loaded, or used when the Core Rule Set is not loaded.
|
||||
- **stream**: Configurations at the Stream level of NGINX.
|
||||
- **server-stream**: Configurations at the Stream/Server level of NGINX.
|
||||
- **crs-plugins-before**: Configurations applied before the OWASP Core Rule Set plugins are loaded.
|
||||
- **crs-plugins-after**: Configurations applied after the OWASP Core Rule Set plugins are loaded.
|
||||
|
||||
Custom configurations can be applied globally or specifically for a particular server, depending on the applicable context and whether the [multisite mode](concepts.md#multisite-mode) is enabled.
|
||||
|
||||
|
|
@ -1134,7 +1136,7 @@ Some integrations provide more convenient ways to apply configurations, such as
|
|||
The settings to use must follow the pattern `<SITE>_CUSTOM_CONF_<TYPE>_<NAME>` :
|
||||
|
||||
- `<SITE>` : optional primary server name if multisite mode is enabled and the config must be applied to a specific service
|
||||
- `<TYPE>` : the type of config, accepted values are `HTTP`, `DEFAULT_SERVER_HTTP`, `SERVER_HTTP`, `MODSEC`, `MODSEC_CRS`, `STREAM` and `SERVER_STREAM`
|
||||
- `<TYPE>` : the type of config, accepted values are `HTTP`, `SERVER_STREAM`, `STREAM`, `DEFAULT_SERVER_HTTP`, `SERVER_HTTP`, `MODSEC_CRS`, `MODSEC`, `CRS_PLUGINS_BEFORE` and `CRS_PLUGINS_AFTER`
|
||||
- `<NAME>` : the name of config without the .conf suffix
|
||||
|
||||
Here is a dummy example using a docker-compose file :
|
||||
|
|
@ -1205,7 +1207,7 @@ Some integrations provide more convenient ways to apply configurations, such as
|
|||
|
||||
The labels to use must follow the pattern `bunkerweb.CUSTOM_CONF_<TYPE>_<NAME>` :
|
||||
|
||||
- `<TYPE>` : the type of config, accepted values are `SERVER_HTTP`, `MODSEC`, `MODSEC_CRS` and `SERVER_STREAM`
|
||||
- `<TYPE>` : the type of config, accepted values are `SERVER_STREAM`, `SERVER_HTTP`, `MODSEC_CRS`, `MODSEC`, `CRS_PLUGINS_BEFORE` and `CRS_PLUGINS_AFTER`
|
||||
- `<NAME>` : the name of config without the .conf suffix
|
||||
|
||||
Here is a dummy example using a docker-compose file :
|
||||
|
|
@ -1269,7 +1271,7 @@ Some integrations provide more convenient ways to apply configurations, such as
|
|||
|
||||
When creating a Config, you will need to add special labels :
|
||||
|
||||
* **bunkerweb.CONFIG_TYPE** : must be set to a valid custom configuration type (http, server-http, default-server-http, modsec, modsec-crs, stream or server-stream)
|
||||
* **bunkerweb.CONFIG_TYPE** : must be set to a valid custom configuration type (`server-stream`, `server-http`, `modsec-crs`, `modsec`, `crs-plugins-before` or `crs-plugins-after`)
|
||||
* **bunkerweb.CONFIG_SITE** : set to a server name to apply configuration to that specific server (optional, will be applied globally if unset)
|
||||
|
||||
Here is the example :
|
||||
|
|
@ -1293,7 +1295,7 @@ Some integrations provide more convenient ways to apply configurations, such as
|
|||
|
||||
When creating a ConfigMap, you will need to add special labels :
|
||||
|
||||
* **bunkerweb.io/CONFIG_TYPE** : must be set to a valid custom configuration type (http, server-http, default-server-http, modsec, modsec-crs, stream or server-stream)
|
||||
* **bunkerweb.io/CONFIG_TYPE** : must be set to a valid custom configuration type (`server-stream`, `server-http`, `modsec-crs`, `modsec`, `crs-plugins-before` or `crs-plugins-after`)
|
||||
* **bunkerweb.io/CONFIG_SITE** : set to a server name to apply configuration to that specific server (optional, will be applied globally if unset)
|
||||
|
||||
Here is the example :
|
||||
|
|
|
|||
|
|
@ -244,19 +244,24 @@ STREAM support :x:
|
|||
|
||||
ModSecurity is integrated and enabled by default alongside the OWASP Core Rule Set within BunkerWeb. Here is the list of related settings :
|
||||
|
||||
| Setting | Default | Description |
|
||||
| :-----------------------: | :-----: | :---------------------------------------------------------------------------------------------------- |
|
||||
| `USE_MODSECURITY` | `yes` | When set to `yes`, ModSecurity will be enabled. |
|
||||
| `USE_MODSECURITY_CRS` | `yes` | When set to `yes` and `USE_MODSECURITY` is also set to `yes`, the OWASP Core Rule Set will be loaded. |
|
||||
| `MODSECURITY_CRS_VERSION` | `3` | Version of the OWASP Core Rule Set to use with ModSecurity (3, 4 or nightly). |
|
||||
| Setting | Default | Description |
|
||||
| --------------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `USE_MODSECURITY` | `yes` | Enable ModSecurity WAF. |
|
||||
| `USE_MODSECURITY_CRS` | `yes` | Enable OWASP Core Rule Set. |
|
||||
| `USE_MODSECURITY_CRS_PLUGINS` | `yes` | Enable OWASP Core Rule Set plugins. |
|
||||
| `MODSECURITY_CRS_VERSION` | `4` | Version of the OWASP Core Rule Set to use with ModSecurity (3, 4 or nightly). |
|
||||
| `MODSECURITY_CRS_PLUGIN_URLS` | | List of OWASP CRS plugins URLs (direct download to .zip or .tar file) to download and install (URLs are separated with space). (Not compatible with CRS version 3) |
|
||||
| `MODSECURITY_SEC_AUDIT_ENGINE` | `RelevantOnly` | SecAuditEngine directive of ModSecurity. |
|
||||
| `MODSECURITY_SEC_RULE_ENGINE` | `On` | SecRuleEngine directive of ModSecurity. |
|
||||
| `MODSECURITY_SEC_AUDIT_LOG_PARTS` | `ABCFHZ` | SecAuditLogParts directive of ModSecurity. |
|
||||
|
||||
!!! warning "ModSecurity and the OWASP Core Rule Set"
|
||||
**We strongly recommend keeping both ModSecurity and the OWASP Core Rule Set enabled**. The only downsides are the false positives that may occur. But they can be fixed with some efforts and the CRS team maintains a list of exclusions for common applications (e.g., WordPress, Nextcloud, Drupal, Cpanel, ...).
|
||||
|
||||
You can choose between the following versions of the OWASP Core Rule Set :
|
||||
|
||||
- **3** : The version [v3.3.5](https://github.com/coreruleset/coreruleset/releases/tag/v3.3.5) of the OWASP Core Rule Set (***default***)
|
||||
- **4** : The version [v4.2.0](https://github.com/coreruleset/coreruleset/releases/tag/v4.2.0) of the OWASP Core Rule Set
|
||||
- **3** : The version [v3.3.5](https://github.com/coreruleset/coreruleset/releases/tag/v3.3.5) of the OWASP Core Rule Set
|
||||
- **4** : The version [v4.4.0](https://github.com/coreruleset/coreruleset/releases/tag/v4.4.0) of the OWASP Core Rule Set (***default***)
|
||||
- **nightly** : The latest [nightly](https://github.com/coreruleset/coreruleset/releases/tag/nightly) build of the OWASP Core Rule Set which is updated every day
|
||||
|
||||
!!! example "OWASP Core Rule Set's nightly build"
|
||||
|
|
@ -268,6 +273,8 @@ Tuning ModSecurity and the CRS can be done using [custom configurations](quickst
|
|||
|
||||
- modsec-crs : before the OWASP Core Rule Set is loaded
|
||||
- modsec : after the OWASP Core Rule Set is loaded (also used if CRS is not loaded)
|
||||
- crs-plugins-before : before the CRS plugins are loaded
|
||||
- crs-plugins-after : after the CRS plugins are loaded
|
||||
|
||||
For example, you can add a custom configuration with type `modsec-crs` to add CRS exclusions :
|
||||
|
||||
|
|
@ -289,6 +296,20 @@ SecRule REQUEST_FILENAME "/wp-admin/options.php" "id:2,ctl:ruleRemoveByTag=attac
|
|||
SecRule REQUEST_FILENAME "^/wp-json/yoast" "id:3,ctl:ruleRemoveById=930120"
|
||||
```
|
||||
|
||||
!!! info "Order of execution"
|
||||
ModSecurity order of execution is as follows :
|
||||
|
||||
1. *OWASP* CRS configuration
|
||||
2. Custom plugins configuration (`crs-plugins-before`)
|
||||
3. Custom plugins rules **before CRS rules** (`crs-plugins-before`)
|
||||
4. Downloaded plugins configuration
|
||||
5. Downloaded plugins rules **before CRS rules**
|
||||
6. Custom CRS rules (`modsec-crs`)
|
||||
6. *OWASP* CRS rules
|
||||
7. Custom plugins rules **after CRS rules** (`crs-plugins-after`)
|
||||
8. Downloaded plugins rules **after CRS rules**
|
||||
9. Custom rules (`modsec`)
|
||||
|
||||
## Bad behavior
|
||||
|
||||
STREAM support :white_check_mark:
|
||||
|
|
|
|||
151
docs/settings.md
151
docs/settings.md
|
|
@ -15,42 +15,42 @@ When settings are considered as "multiple", it means that you can have multiple
|
|||
|
||||
STREAM support :warning:
|
||||
|
||||
| Setting | Default | Context |Multiple| Description |
|
||||
|------------------------------|------------------------------------------------------------------------------------------------------------------------|---------|--------|--------------------------------------------------------------------------------------------|
|
||||
|`IS_LOADING` |`no` |global |no |Internal use : set to yes when BW is loading. |
|
||||
|`NGINX_PREFIX` |`/etc/nginx/` |global |no |Where nginx will search for configurations. |
|
||||
|`HTTP_PORT` |`8080` |global |no |HTTP port number which bunkerweb binds to. |
|
||||
|`HTTPS_PORT` |`8443` |global |no |HTTPS port number which bunkerweb binds to. |
|
||||
|`MULTISITE` |`no` |global |no |Multi site activation. |
|
||||
|`SERVER_NAME` |`www.example.com` |multisite|no |List of the virtual hosts served by bunkerweb. |
|
||||
|`WORKER_PROCESSES` |`auto` |global |no |Number of worker processes. |
|
||||
|`WORKER_RLIMIT_NOFILE` |`2048` |global |no |Maximum number of open files for worker processes. |
|
||||
|`WORKER_CONNECTIONS` |`1024` |global |no |Maximum number of connections per worker. |
|
||||
|`LOG_FORMAT` |`$host $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"`|global |no |The format to use for access logs. |
|
||||
|`LOG_LEVEL` |`notice` |global |no |The level to use for error logs. |
|
||||
|`DNS_RESOLVERS` |`127.0.0.11` |global |no |DNS addresses of resolvers to use. |
|
||||
|`DATASTORE_MEMORY_SIZE` |`64m` |global |no |Size of the internal datastore. |
|
||||
|`CACHESTORE_MEMORY_SIZE` |`64m` |global |no |Size of the internal cachestore. |
|
||||
|`CACHESTORE_IPC_MEMORY_SIZE` |`16m` |global |no |Size of the internal cachestore (ipc). |
|
||||
|`CACHESTORE_MISS_MEMORY_SIZE` |`16m` |global |no |Size of the internal cachestore (miss). |
|
||||
|`CACHESTORE_LOCKS_MEMORY_SIZE`|`16m` |global |no |Size of the internal cachestore (locks). |
|
||||
|`USE_API` |`yes` |global |no |Activate the API to control BunkerWeb. |
|
||||
|`API_HTTP_PORT` |`5000` |global |no |Listen port number for the API. |
|
||||
|`API_LISTEN_IP` |`0.0.0.0` |global |no |Listen IP address for the API. |
|
||||
|`API_SERVER_NAME` |`bwapi` |global |no |Server name (virtual host) for the API. |
|
||||
|`API_WHITELIST_IP` |`127.0.0.0/8` |global |no |List of IP/network allowed to contact the API. |
|
||||
|`AUTOCONF_MODE` |`no` |global |no |Enable Autoconf Docker integration. |
|
||||
|`SWARM_MODE` |`no` |global |no |Enable Docker Swarm integration. |
|
||||
|`KUBERNETES_MODE` |`no` |global |no |Enable Kubernetes integration. |
|
||||
|`SERVER_TYPE` |`http` |multisite|no |Server type : http or stream. |
|
||||
|`LISTEN_STREAM` |`yes` |multisite|no |Enable listening for non-ssl (passthrough). |
|
||||
|`LISTEN_STREAM_PORT` |`1337` |multisite|no |Listening port for non-ssl (passthrough). |
|
||||
|`LISTEN_STREAM_PORT_SSL` |`4242` |multisite|no |Listening port for ssl (passthrough). |
|
||||
|`USE_UDP` |`no` |multisite|no |UDP listen instead of TCP (stream). |
|
||||
|`USE_IPV6` |`no` |global |no |Enable IPv6 connectivity. |
|
||||
|`IS_DRAFT` |`no` |multisite|no |Internal use : set to yes when the service is in draft mode. |
|
||||
|`TIMERS_LOG_LEVEL` |`debug` |global |no |Log level for timers. |
|
||||
|`OVERRIDE_INSTANCES` | |global |no |List of BunkerWeb instances separated with spaces (format : fqdn-or-ip:5000 fqdn-or-ip:5000)|
|
||||
| Setting | Default | Context |Multiple| Description |
|
||||
|------------------------------|------------------------------------------------------------------------------------------------------------------------|---------|--------|---------------------------------------------------------------------------------------------------|
|
||||
|`IS_LOADING` |`no` |global |no |Internal use : set to yes when BW is loading. |
|
||||
|`NGINX_PREFIX` |`/etc/nginx/` |global |no |Where nginx will search for configurations. |
|
||||
|`HTTP_PORT` |`8080` |global |no |HTTP port number which bunkerweb binds to. |
|
||||
|`HTTPS_PORT` |`8443` |global |no |HTTPS port number which bunkerweb binds to. |
|
||||
|`MULTISITE` |`no` |global |no |Multi site activation. |
|
||||
|`SERVER_NAME` |`www.example.com` |multisite|no |List of the virtual hosts served by bunkerweb. |
|
||||
|`WORKER_PROCESSES` |`auto` |global |no |Number of worker processes. |
|
||||
|`WORKER_RLIMIT_NOFILE` |`2048` |global |no |Maximum number of open files for worker processes. |
|
||||
|`WORKER_CONNECTIONS` |`1024` |global |no |Maximum number of connections per worker. |
|
||||
|`LOG_FORMAT` |`$host $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"`|global |no |The format to use for access logs. |
|
||||
|`LOG_LEVEL` |`notice` |global |no |The level to use for error logs. |
|
||||
|`DNS_RESOLVERS` |`127.0.0.11` |global |no |DNS addresses of resolvers to use. |
|
||||
|`DATASTORE_MEMORY_SIZE` |`64m` |global |no |Size of the internal datastore. |
|
||||
|`CACHESTORE_MEMORY_SIZE` |`64m` |global |no |Size of the internal cachestore. |
|
||||
|`CACHESTORE_IPC_MEMORY_SIZE` |`16m` |global |no |Size of the internal cachestore (ipc). |
|
||||
|`CACHESTORE_MISS_MEMORY_SIZE` |`16m` |global |no |Size of the internal cachestore (miss). |
|
||||
|`CACHESTORE_LOCKS_MEMORY_SIZE`|`16m` |global |no |Size of the internal cachestore (locks). |
|
||||
|`USE_API` |`yes` |global |no |Activate the API to control BunkerWeb. |
|
||||
|`API_HTTP_PORT` |`5000` |global |no |Listen port number for the API. |
|
||||
|`API_LISTEN_IP` |`0.0.0.0` |global |no |Listen IP address for the API. |
|
||||
|`API_SERVER_NAME` |`bwapi` |global |no |Server name (virtual host) for the API. |
|
||||
|`API_WHITELIST_IP` |`127.0.0.0/8` |global |no |List of IP/network allowed to contact the API. |
|
||||
|`AUTOCONF_MODE` |`no` |global |no |Enable Autoconf Docker integration. |
|
||||
|`SWARM_MODE` |`no` |global |no |Enable Docker Swarm integration. |
|
||||
|`KUBERNETES_MODE` |`no` |global |no |Enable Kubernetes integration. |
|
||||
|`SERVER_TYPE` |`http` |multisite|no |Server type : http or stream. |
|
||||
|`LISTEN_STREAM` |`yes` |multisite|no |Enable listening for non-ssl (passthrough). |
|
||||
|`LISTEN_STREAM_PORT` |`1337` |multisite|no |Listening port for non-ssl (passthrough). |
|
||||
|`LISTEN_STREAM_PORT_SSL` |`4242` |multisite|no |Listening port for ssl (passthrough). |
|
||||
|`USE_UDP` |`no` |multisite|no |UDP listen instead of TCP (stream). |
|
||||
|`USE_IPV6` |`no` |global |no |Enable IPv6 connectivity. |
|
||||
|`IS_DRAFT` |`no` |multisite|no |Internal use : set to yes when the service is in draft mode. |
|
||||
|`TIMERS_LOG_LEVEL` |`debug` |global |no |Log level for timers. |
|
||||
|`BUNKERWEB_INSTANCES` |`127.0.0.1` |global |no |List of BunkerWeb instances separated with spaces (format : fqdn-or-ip:5000 http://fqdn-or-ip:5000)|
|
||||
|
||||
|
||||
## Antibot
|
||||
|
|
@ -195,19 +195,19 @@ STREAM support :x:
|
|||
|
||||
Cross-Origin Resource Sharing.
|
||||
|
||||
| Setting | Default | Context |Multiple| Description |
|
||||
|------------------------------|------------------------------------------------------------------------------------|---------|--------|-------------------------------------------------------------------|
|
||||
|`USE_CORS` |`no` |multisite|no |Use CORS |
|
||||
|`CORS_ALLOW_ORIGIN` |`*` |multisite|no |Allowed origins to make CORS requests : PCRE regex or *. |
|
||||
|`CORS_ALLOW_METHODS` |`GET, POST, OPTIONS` |multisite|no |Value of the Access-Control-Allow-Methods header. |
|
||||
|`CORS_ALLOW_HEADERS` |`DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range`|multisite|no |Value of the Access-Control-Allow-Headers header. |
|
||||
|`CORS_ALLOW_CREDENTIALS` |`no` |multisite|no |Send the Access-Control-Allow-Credentials header. |
|
||||
|`CORS_EXPOSE_HEADERS` |`Content-Length,Content-Range` |multisite|no |Value of the Access-Control-Expose-Headers header. |
|
||||
|`CROSS_ORIGIN_OPENER_POLICY` | |multisite|no |Value for the Cross-Origin-Opener-Policy header. |
|
||||
|`CROSS_ORIGIN_EMBEDDER_POLICY`| |multisite|no |Value for the Cross-Origin-Embedder-Policy header. |
|
||||
|`CROSS_ORIGIN_RESOURCE_POLICY`| |multisite|no |Value for the Cross-Origin-Resource-Policy header. |
|
||||
|`CORS_MAX_AGE` |`86400` |multisite|no |Value of the Access-Control-Max-Age header. |
|
||||
|`CORS_DENY_REQUEST` |`yes` |multisite|no |Deny request and don't send it to backend if Origin is not allowed.|
|
||||
| Setting | Default | Context |Multiple| Description |
|
||||
|------------------------------|------------------------------------------------------------------------------------|---------|--------|--------------------------------------------------------------------------------------|
|
||||
|`USE_CORS` |`no` |multisite|no |Use CORS |
|
||||
|`CORS_ALLOW_ORIGIN` |`self` |multisite|no |Allowed origins to make CORS requests : PCRE regex or * or self (for the same origin).|
|
||||
|`CORS_ALLOW_METHODS` |`GET, POST, OPTIONS` |multisite|no |Value of the Access-Control-Allow-Methods header. |
|
||||
|`CORS_ALLOW_HEADERS` |`DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range`|multisite|no |Value of the Access-Control-Allow-Headers header. |
|
||||
|`CORS_ALLOW_CREDENTIALS` |`no` |multisite|no |Send the Access-Control-Allow-Credentials header. |
|
||||
|`CORS_EXPOSE_HEADERS` |`Content-Length,Content-Range` |multisite|no |Value of the Access-Control-Expose-Headers header. |
|
||||
|`CROSS_ORIGIN_OPENER_POLICY` |`same-origin` |multisite|no |Value for the Cross-Origin-Opener-Policy header. |
|
||||
|`CROSS_ORIGIN_EMBEDDER_POLICY`|`require-corp` |multisite|no |Value for the Cross-Origin-Embedder-Policy header. |
|
||||
|`CROSS_ORIGIN_RESOURCE_POLICY`|`same-site` |multisite|no |Value for the Cross-Origin-Resource-Policy header. |
|
||||
|`CORS_MAX_AGE` |`86400` |multisite|no |Value of the Access-Control-Max-Age header. |
|
||||
|`CORS_DENY_REQUEST` |`yes` |multisite|no |Deny request and don't send it to backend if Origin is not allowed. |
|
||||
|
||||
## Client cache
|
||||
|
||||
|
|
@ -332,22 +332,23 @@ STREAM support :x:
|
|||
|
||||
Manage HTTP headers sent to clients.
|
||||
|
||||
| Setting | Default | Context |Multiple| Description |
|
||||
|-------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|--------|----------------------------------------------------------------------------------------------|
|
||||
|`CUSTOM_HEADER` | |multisite|yes |Custom header to add (HeaderName: HeaderValue). |
|
||||
|`REMOVE_HEADERS` |`Server Expect-CT X-Powered-By X-AspNet-Version X-AspNetMvc-Version` |multisite|no |Headers to remove (Header1 Header2 Header3 ...) |
|
||||
|`KEEP_UPSTREAM_HEADERS` |`Content-Security-Policy Permissions-Policy Feature-Policy X-Frame-Options` |multisite|no |Headers to keep from upstream (Header1 Header2 Header3 ... or * for all). |
|
||||
|`STRICT_TRANSPORT_SECURITY` |`max-age=31536000` |multisite|no |Value for the Strict-Transport-Security header. |
|
||||
|`COOKIE_FLAGS` |`* HttpOnly SameSite=Lax` |multisite|yes |Cookie flags automatically added to all cookies (value accepted for nginx_cookie_flag_module).|
|
||||
|`COOKIE_AUTO_SECURE_FLAG` |`yes` |multisite|no |Automatically add the Secure flag to all cookies. |
|
||||
|`CONTENT_SECURITY_POLICY` |`object-src 'none'; form-action 'self'; frame-ancestors 'self';` |multisite|no |Value for the Content-Security-Policy header. |
|
||||
|`CONTENT_SECURITY_POLICY_REPORT_ONLY`|`no` |multisite|no |Send reports for violations of the Content-Security-Policy header instead of blocking them. |
|
||||
|`REFERRER_POLICY` |`strict-origin-when-cross-origin` |multisite|no |Value for the Referrer-Policy header. |
|
||||
|`PERMISSIONS_POLICY` |`accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), cross-origin-isolated=(), display-capture=(), document-domain=(), encrypted-media=(), execution-while-not-rendered=(), execution-while-out-of-viewport=(), fullscreen=(), geolocation=(), gyroscope=(), hid=(), idle-detection=(), magnetometer=(), microphone=(), midi=(), navigation-override=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), serial=(), usb=(), web-share=(), xr-spatial-tracking=()` |multisite|no |Value for the Permissions-Policy header. |
|
||||
|`FEATURE_POLICY` |`accelerometer 'none'; ambient-light-sensor 'none'; autoplay 'none'; battery 'none'; camera 'none'; display-capture 'none'; document-domain 'none'; encrypted-media 'none'; execution-while-not-rendered 'none'; execution-while-out-of-viewport 'none'; fullscreen 'none'; geolocation 'none'; gyroscope 'none'; layout-animation 'none'; legacy-image-formats 'none'; magnetometer 'none'; microphone 'none'; midi 'none'; navigation-override 'none'; payment 'none'; picture-in-picture 'none'; publickey-credentials-get 'none'; speaker-selection 'none'; sync-xhr 'none'; unoptimized-images 'none'; unsized-media 'none'; usb 'none'; screen-wake-lock 'none'; web-share 'none'; xr-spatial-tracking 'none';`|multisite|no |Value for the Feature-Policy header. |
|
||||
|`X_FRAME_OPTIONS` |`SAMEORIGIN` |multisite|no |Value for the X-Frame-Options header. |
|
||||
|`X_CONTENT_TYPE_OPTIONS` |`nosniff` |multisite|no |Value for the X-Content-Type-Options header. |
|
||||
|`X_XSS_PROTECTION` |`1; mode=block` |multisite|no |Value for the X-XSS-Protection header. |
|
||||
| Setting | Default | Context |Multiple| Description |
|
||||
|-------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|--------|------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
|`CUSTOM_HEADER` | |multisite|yes |Custom header to add (HeaderName: HeaderValue). |
|
||||
|`REMOVE_HEADERS` |`Server Expect-CT X-Powered-By X-AspNet-Version X-AspNetMvc-Version Public-Key-Pins` |multisite|no |Headers to remove (Header1 Header2 Header3 ...) |
|
||||
|`KEEP_UPSTREAM_HEADERS` |`Content-Security-Policy Permissions-Policy X-Frame-Options` |multisite|no |Headers to keep from upstream (Header1 Header2 Header3 ... or * for all). |
|
||||
|`STRICT_TRANSPORT_SECURITY` |`max-age=31536000; includeSubDomains; preload` |multisite|no |Value for the Strict-Transport-Security header. |
|
||||
|`COOKIE_FLAGS` |`* HttpOnly SameSite=Lax` |multisite|yes |Cookie flags automatically added to all cookies (value accepted for nginx_cookie_flag_module). |
|
||||
|`COOKIE_AUTO_SECURE_FLAG` |`yes` |multisite|no |Automatically add the Secure flag to all cookies. |
|
||||
|`CONTENT_SECURITY_POLICY` |`object-src 'none'; form-action 'self'; frame-ancestors 'self';` |multisite|no |Value for the Content-Security-Policy header. |
|
||||
|`CONTENT_SECURITY_POLICY_REPORT_ONLY`|`no` |multisite|no |Send reports for violations of the Content-Security-Policy header instead of blocking them. |
|
||||
|`REFERRER_POLICY` |`strict-origin-when-cross-origin` |multisite|no |Value for the Referrer-Policy header. |
|
||||
|`PERMISSIONS_POLICY` |`accelerometer=(), ambient-light-sensor=(), attribution-reporting=(), autoplay=(), battery=(), bluetooth=(), browsing-topics=(), camera=(), compute-pressure=(), display-capture=(), document-domain=(), encrypted-media=(), execution-while-not-rendered=(), execution-while-out-of-viewport=(), fullscreen=(), gamepad=(), geolocation=(), gyroscope=(), hid=(), identity-credentials-get=(), idle-detection=(), local-fonts=(), magnetometer=(), microphone=(), midi=(), otp-credentials=(), payment=(), picture-in-picture=(), publickey-credentials-create=(), publickey-credentials-get=(), screen-wake-lock=(), serial=(), speaker-selection=(), storage-access=(), usb=(), web-share=(), window-management=(), xr-spatial-tracking=()`|multisite|no |Value for the Permissions-Policy header. |
|
||||
|`DISABLE_FLOC` |`yes` |multisite|no |Disable FLoC (Federated Learning of Cohorts) by adding the interest-cohort=() directive to the Permissions-Policy header if it is not already present.|
|
||||
|`X_FRAME_OPTIONS` |`SAMEORIGIN` |multisite|no |Value for the X-Frame-Options header. |
|
||||
|`X_CONTENT_TYPE_OPTIONS` |`nosniff` |multisite|no |Value for the X-Content-Type-Options header. |
|
||||
|`X_XSS_PROTECTION` |`1; mode=block` |multisite|no |Value for the X-XSS-Protection header. |
|
||||
|`X_DNS_PREFETCH_CONTROL` |`off` |multisite|no |Value for the X-DNS-Prefetch-Control header. |
|
||||
|
||||
## Let's Encrypt
|
||||
|
||||
|
|
@ -451,14 +452,16 @@ STREAM support :x:
|
|||
|
||||
Management of the ModSecurity WAF.
|
||||
|
||||
| Setting | Default | Context |Multiple| Description |
|
||||
|---------------------------------|--------------|---------|--------|-----------------------------------------------------------------------------|
|
||||
|`USE_MODSECURITY` |`yes` |multisite|no |Enable ModSecurity WAF. |
|
||||
|`USE_MODSECURITY_CRS` |`yes` |multisite|no |Enable OWASP Core Rule Set. |
|
||||
|`MODSECURITY_CRS_VERSION` |`3` |multisite|no |Version of the OWASP Core Rule Set to use with ModSecurity (3, 4 or nightly).|
|
||||
|`MODSECURITY_SEC_AUDIT_ENGINE` |`RelevantOnly`|multisite|no |SecAuditEngine directive of ModSecurity. |
|
||||
|`MODSECURITY_SEC_RULE_ENGINE` |`On` |multisite|no |SecRuleEngine directive of ModSecurity. |
|
||||
|`MODSECURITY_SEC_AUDIT_LOG_PARTS`|`ABCFHZ` |multisite|no |SecAuditLogParts directive of ModSecurity. |
|
||||
| Setting | Default | Context |Multiple| Description |
|
||||
|---------------------------------|--------------|---------|--------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
|`USE_MODSECURITY` |`yes` |multisite|no |Enable ModSecurity WAF. |
|
||||
|`USE_MODSECURITY_CRS` |`yes` |multisite|no |Enable OWASP Core Rule Set. |
|
||||
|`USE_MODSECURITY_CRS_PLUGINS` |`yes` |multisite|no |Enable OWASP Core Rule Set plugins. |
|
||||
|`MODSECURITY_CRS_VERSION` |`4` |multisite|no |Version of the OWASP Core Rule Set to use with ModSecurity (3, 4 or nightly). |
|
||||
|`MODSECURITY_CRS_PLUGIN_URLS` | |multisite|no |List of OWASP CRS plugins URLs (direct download to .zip or .tar file) to download and install (URLs are separated with space). (Not compatible with CRS version 3)|
|
||||
|`MODSECURITY_SEC_AUDIT_ENGINE` |`RelevantOnly`|multisite|no |SecAuditEngine directive of ModSecurity. |
|
||||
|`MODSECURITY_SEC_RULE_ENGINE` |`On` |multisite|no |SecRuleEngine directive of ModSecurity. |
|
||||
|`MODSECURITY_SEC_AUDIT_LOG_PARTS`|`ABCFHZ` |multisite|no |SecAuditLogParts directive of ModSecurity. |
|
||||
|
||||
## Monitoring <img src='../assets/img/pro-icon.svg' alt='crow pro icon' height='24px' width='24px' style='transform : translateY(3px);'> (PRO)
|
||||
|
||||
|
|
@ -609,6 +612,7 @@ Manage reverse proxy configurations.
|
|||
|`REVERSE_PROXY_READ_TIMEOUT` |`60s` |multisite|yes |Timeout when reading from the proxied resource. |
|
||||
|`REVERSE_PROXY_SEND_TIMEOUT` |`60s` |multisite|yes |Timeout when sending to the proxied resource. |
|
||||
|`REVERSE_PROXY_INCLUDES` | |multisite|yes |Additional configuration to include in the location block, separated with spaces. |
|
||||
|`REVERSE_PROXY_PASS_REQUEST_BODY` |`yes` |multisite|yes |Enable or disable passing the request body to the proxied resource. |
|
||||
|`USE_PROXY_CACHE` |`no` |multisite|no |Enable or disable caching of the proxied resources. |
|
||||
|`PROXY_CACHE_PATH_LEVELS` |`1:2` |global |no |Hierarchy levels of the cache. |
|
||||
|`PROXY_CACHE_PATH_ZONE_SIZE` |`10m` |global |no |Maximum size of cached metadata when caching proxied resources. |
|
||||
|
|
@ -691,4 +695,3 @@ Allow access based on internal and external IP/network/rDNS/ASN whitelists.
|
|||
|`WHITELIST_ASN_URLS` | |global |no |List of URLs, separated with spaces, containing ASN to whitelist. Also supports file:// URLs and and auth basic using http://user:pass@url scheme. |
|
||||
|`WHITELIST_USER_AGENT_URLS`| |global |no |List of URLs, separated with spaces, containing good User-Agent to whitelist. Also supports file:// URLs and and auth basic using http://user:pass@url scheme. |
|
||||
|`WHITELIST_URI_URLS` | |global |no |List of URLs, separated with spaces, containing bad URI to whitelist. Also supports file:// URLs and and auth basic using http://user:pass@url scheme. |
|
||||
|
||||
|
|
|
|||
|
|
@ -16,15 +16,7 @@ class Config:
|
|||
self.__logger = setup_logger("Config", getenv("LOG_LEVEL", "INFO"))
|
||||
self.__instances = []
|
||||
self.__services = []
|
||||
self._supported_config_types = [
|
||||
"http",
|
||||
"stream",
|
||||
"server-http",
|
||||
"server-stream",
|
||||
"default-server-http",
|
||||
"modsec",
|
||||
"modsec-crs",
|
||||
]
|
||||
self._supported_config_types = ("server-http", "server-stream", "modsec", "modsec-crs", "crs-plugins-before", "crs-plugins-after")
|
||||
self.__configs = {config_type: {} for config_type in self._supported_config_types}
|
||||
self.__config = {}
|
||||
|
||||
|
|
@ -131,6 +123,10 @@ class Config:
|
|||
custom_configs = []
|
||||
if "custom_configs" in changes:
|
||||
for config_type in self.__configs:
|
||||
if config_type not in self._supported_config_types:
|
||||
self.__logger.warning(f"Unsupported custom config type: {config_type}")
|
||||
continue
|
||||
|
||||
for file, data in self.__configs[config_type].items():
|
||||
site = None
|
||||
name = file
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class DockerController(Controller):
|
|||
def __init__(self, docker_host):
|
||||
super().__init__("docker")
|
||||
self.__client = DockerClient(base_url=docker_host)
|
||||
self.__custom_confs_rx = re_compile(r"^bunkerweb.CUSTOM_CONF_(SERVER_HTTP|MODSEC_CRS|MODSEC)_(.+)$")
|
||||
self.__custom_confs_rx = re_compile(r"^bunkerweb.CUSTOM_CONF_(SERVER_STREAM|SERVER_HTTP|MODSEC_CRS|MODSEC|CRS_PLUGINS_BEFORE|CRS_PLUGINS_AFTER)_(.+)$")
|
||||
|
||||
def _get_controller_instances(self) -> List[Container]:
|
||||
return self.__client.containers.list(filters={"label": "bunkerweb.INSTANCE"})
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ RUN apk add --no-cache bash && \
|
|||
mkdir -p /data/lib && ln -s /data/lib /var/lib/bunkerweb && \
|
||||
mkdir -p /data/www && ln -s /data/www /var/www/html && \
|
||||
for dir in $(echo "configs plugins") ; do mkdir -p "/data/${dir}" && ln -s "/data/${dir}" "/etc/bunkerweb/${dir}" ; done && \
|
||||
for dir in $(echo "configs/http configs/stream configs/server-http configs/server-stream configs/default-server-http configs/default-server-stream configs/modsec configs/modsec-crs") ; do mkdir "/data/${dir}" ; done && \
|
||||
for dir in $(echo "configs/http configs/stream configs/server-http configs/server-stream configs/default-server-http configs/default-server-stream configs/modsec configs/modsec-crs configs/crs-plugins-before configs/crs-plugins-after") ; do mkdir "/data/${dir}" ; done && \
|
||||
chown -R root:autoconf /data && \
|
||||
chmod -R 770 /data && \
|
||||
chown -R root:autoconf INTEGRATION /var/cache/bunkerweb /var/lib/bunkerweb /etc/bunkerweb /var/tmp/bunkerweb /usr/bin/bwcli && \
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ RUN apk add --no-cache openssl pcre bash python3 yajl geoip libxml2 libgd curl &
|
|||
mkdir -p /etc/bunkerweb /var/tmp/bunkerweb /var/run/bunkerweb /var/log/bunkerweb /var/www/html && \
|
||||
mkdir -p /data/cache && ln -s /data/cache /var/cache/bunkerweb && \
|
||||
for dir in $(echo "pro configs plugins") ; do mkdir -p "/data/${dir}" && ln -s "/data/${dir}" "/etc/bunkerweb/${dir}" ; done && \
|
||||
for dir in $(echo "pro/plugins configs/http configs/stream configs/server-http configs/server-stream configs/default-server-http configs/default-server-stream configs/modsec configs/modsec-crs") ; do mkdir "/data/${dir}" ; done && \
|
||||
for dir in $(echo "pro/plugins configs/http configs/stream configs/server-http configs/server-stream configs/default-server-http configs/default-server-stream configs/modsec configs/modsec-crs configs/crs-plugins-before configs/crs-plugins-after") ; do mkdir "/data/${dir}" ; done && \
|
||||
chown -R root:nginx /data /etc/nginx /var/cache/bunkerweb /etc/bunkerweb /var/tmp/bunkerweb /var/run/bunkerweb /var/log/bunkerweb /usr/bin/bwcli && \
|
||||
chmod -R 770 /data /etc/nginx /var/cache/bunkerweb /etc/bunkerweb /var/tmp/bunkerweb /var/log/bunkerweb /var/run/bunkerweb && \
|
||||
chmod 750 cli/main.py gen/main.py helpers/*.sh entrypoint.sh /usr/bin/bwcli deps/python/bin/* && \
|
||||
|
|
|
|||
|
|
@ -215,7 +215,6 @@ except:
|
|||
status = 2
|
||||
LOGGER.error(f"Exception while running download-plugins.py :\n{format_exc()}")
|
||||
|
||||
for plugin_tmp in TMP_DIR.glob("*"):
|
||||
rmtree(plugin_tmp, ignore_errors=True)
|
||||
rmtree(TMP_DIR, ignore_errors=True)
|
||||
|
||||
sys_exit(status)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
{% set os_path = import("os.path") %}
|
||||
{% set pathlib = import("pathlib") %}
|
||||
{% set json = import("json") %}
|
||||
{% set service_id = SERVER_NAME.split(" ")[0] %}
|
||||
# process rules with disruptive actions
|
||||
SecRuleEngine {{ MODSECURITY_SEC_RULE_ENGINE }}
|
||||
|
||||
|
|
@ -65,32 +67,66 @@ SecAuditLogParts {{ MODSECURITY_SEC_AUDIT_LOG_PARTS }}
|
|||
SecAuditLogType Serial
|
||||
SecAuditLog /var/log/bunkerweb/modsec_audit.log
|
||||
|
||||
{% if USE_MODSECURITY_CRS == "yes" +%}
|
||||
# include OWASP CRS configurations
|
||||
{% if USE_MODSECURITY_CRS == "yes" %}
|
||||
{% if MODSECURITY_CRS_VERSION == "nightly" %}
|
||||
{% if os_path.isfile("/var/cache/bunkerweb/modsecurity/crs/crs-setup-nightly.conf") %}
|
||||
include /var/cache/bunkerweb/modsecurity/crs/crs-setup-nightly.conf
|
||||
{% else %}
|
||||
{% if MODSECURITY_CRS_VERSION == "nightly" %}
|
||||
{% if pathlib.Path("/var/cache/bunkerweb/modsecurity/crs/nightly/crs-setup-nightly.conf").is_file() %}
|
||||
include /var/cache/bunkerweb/modsecurity/crs/nightly/crs-setup-nightly.conf
|
||||
{% else %}
|
||||
# fallback to the default CRS setup as the nightly one is not available
|
||||
include /usr/share/bunkerweb/core/modsecurity/files/crs-setup-v3.conf
|
||||
{% endif %}
|
||||
{% else %}
|
||||
include /usr/share/bunkerweb/core/modsecurity/files/crs-setup-v4.conf
|
||||
{% endif %}
|
||||
{% else %}
|
||||
include /usr/share/bunkerweb/core/modsecurity/files/crs-setup-v{{ MODSECURITY_CRS_VERSION }}.conf
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if USE_MODSECURITY_CRS_PLUGINS == "yes" and MODSECURITY_CRS_VERSION != "3" %}
|
||||
# custom CRS plugins configurations before loading plugins
|
||||
{% if is_custom_conf("/etc/bunkerweb/configs/crs-plugins-before") %}
|
||||
include /etc/bunkerweb/configs/crs-plugins-before/*.conf
|
||||
{% endif %}
|
||||
{% if MULTISITE == "yes" and is_custom_conf("/etc/bunkerweb/configs/crs-plugins-before/" + service_id) %}
|
||||
include /etc/bunkerweb/configs/crs-plugins-before/{{ service_id }}/*.conf
|
||||
{% endif %}
|
||||
{% if is_custom_conf("/etc/nginx/crs-plugins-before") %}
|
||||
include /etc/nginx/crs-plugins-before/*.conf
|
||||
{% endif %}
|
||||
{% if MULTISITE == "yes" and is_custom_conf("/etc/nginx/" + service_id + "/crs-plugins-before/") %}
|
||||
include /etc/nginx/{{ service_id }}/crs-plugins-before/*.conf
|
||||
{% endif %}
|
||||
|
||||
{% with plugins_path = pathlib.Path("/var/cache/bunkerweb/modsecurity/crs/plugins") %}
|
||||
{% with plugins_file = pathlib.Path("/var/cache/bunkerweb/modsecurity/crs-plugins.json") %}
|
||||
{% if plugins_path.is_dir() and plugins_file.is_file() %}
|
||||
{% with service_plugins = json.loads(plugins_file.read_text()) %}
|
||||
# include downloaded CRS plugins configurations and before rules
|
||||
{% for plugin_id in service_plugins.get(service_id, []) %}
|
||||
{% if plugins_path.joinpath(plugin_id).is_dir() %}
|
||||
include /var/cache/bunkerweb/modsecurity/crs/plugins/{{ plugin_id }}/*-config.conf
|
||||
{% if plugins_path.joinpath(plugin_id).glob("*-before.conf") | list %}
|
||||
include /var/cache/bunkerweb/modsecurity/crs/plugins/{{ plugin_id }}/*-before.conf
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
|
||||
# custom CRS configurations before loading rules (e.g. exclusions)
|
||||
{% if is_custom_conf("/etc/bunkerweb/configs/modsec-crs") %}
|
||||
{% if is_custom_conf("/etc/bunkerweb/configs/modsec-crs") %}
|
||||
include /etc/bunkerweb/configs/modsec-crs/*.conf
|
||||
{% endif %}
|
||||
{% if MULTISITE == "yes" and is_custom_conf("/etc/bunkerweb/configs/modsec-crs/" + SERVER_NAME.split(" ")[0]) %}
|
||||
include /etc/bunkerweb/configs/modsec-crs/{{ SERVER_NAME.split(" ")[0] }}/*.conf
|
||||
{% endif %}
|
||||
{% if is_custom_conf("/etc/nginx/modsec-crs") %}
|
||||
{% endif %}
|
||||
{% if MULTISITE == "yes" and is_custom_conf("/etc/bunkerweb/configs/modsec-crs/" + service_id) %}
|
||||
include /etc/bunkerweb/configs/modsec-crs/{{ service_id }}/*.conf
|
||||
{% endif %}
|
||||
{% if is_custom_conf("/etc/nginx/modsec-crs") %}
|
||||
include /etc/nginx/modsec-crs/*.conf
|
||||
{% endif %}
|
||||
{% if MULTISITE == "yes" and is_custom_conf("/etc/nginx/" + SERVER_NAME.split(" ")[0] + "/modsec-crs/") %}
|
||||
include /etc/nginx/{{ SERVER_NAME.split(" ")[0] }}/modsec-crs/*.conf
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if MULTISITE == "yes" and is_custom_conf("/etc/nginx/" + service_id + "/modsec-crs/") %}
|
||||
include /etc/nginx/{{ service_id }}/modsec-crs/*.conf
|
||||
{% endif %}
|
||||
|
||||
# unset REASON env var
|
||||
SecAction "nolog,phase:1,setenv:REASON=none"
|
||||
|
|
@ -105,35 +141,66 @@ SecAction \
|
|||
setvar:'tx.allowed_methods={{ ALLOWED_METHODS.replace("|", " ") }}'"
|
||||
|
||||
# Check if client is whitelisted
|
||||
{% if USE_WHITELIST == "yes" +%}
|
||||
{% if USE_WHITELIST == "yes" +%}
|
||||
SecRule ENV:is_whitelisted "yes" "id:1000,phase:1,allow,nolog,ctl:ruleEngine=Off"
|
||||
{% endif +%}
|
||||
{% endif +%}
|
||||
|
||||
# include OWASP CRS rules
|
||||
{% if MODSECURITY_CRS_VERSION == "nightly" %}
|
||||
{% if os_path.exists("/var/cache/bunkerweb/modsecurity/crs/crs-nightly/rules") %}
|
||||
include /var/cache/bunkerweb/modsecurity/crs/crs-nightly/rules/*.conf
|
||||
{% else %}
|
||||
{% if MODSECURITY_CRS_VERSION == "nightly" %}
|
||||
{% if pathlib.Path("/var/cache/bunkerweb/modsecurity/crs/nightly/crs-nightly/rules").is_dir() %}
|
||||
include /var/cache/bunkerweb/modsecurity/crs/nightly/crs-nightly/rules/*.conf
|
||||
{% else %}
|
||||
# fallback to the default CRS setup as the nightly one is not available
|
||||
include /usr/share/bunkerweb/core/modsecurity/files/coreruleset-v3/rules/*.conf
|
||||
{% endif %}
|
||||
{% else %}
|
||||
include /usr/share/bunkerweb/core/modsecurity/files/coreruleset-v4/rules/*.conf
|
||||
{% endif %}
|
||||
{% else %}
|
||||
include /usr/share/bunkerweb/core/modsecurity/files/coreruleset-v{{ MODSECURITY_CRS_VERSION }}/rules/*.conf
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if USE_MODSECURITY_CRS_PLUGINS == "yes" and MODSECURITY_CRS_VERSION != "3" %}
|
||||
# custom CRS plugins configurations after loading plugins
|
||||
{% if is_custom_conf("/etc/bunkerweb/configs/crs-plugins-after") %}
|
||||
include /etc/bunkerweb/configs/crs-plugins-after/*.conf
|
||||
{% endif %}
|
||||
{% if MULTISITE == "yes" and is_custom_conf("/etc/bunkerweb/configs/crs-plugins-after/" + service_id) %}
|
||||
include /etc/bunkerweb/configs/crs-plugins-after/{{ service_id }}/*.conf
|
||||
{% endif %}
|
||||
{% if is_custom_conf("/etc/nginx/crs-plugins-after") %}
|
||||
include /etc/nginx/crs-plugins-after/*.conf
|
||||
{% endif %}
|
||||
{% if MULTISITE == "yes" and is_custom_conf("/etc/nginx/" + service_id + "/crs-plugins-after/") %}
|
||||
include /etc/nginx/{{ service_id }}/crs-plugins-after/*.conf
|
||||
{% endif %}
|
||||
|
||||
{% with plugins_path = pathlib.Path("/var/cache/bunkerweb/modsecurity/crs/plugins") %}
|
||||
{% with plugins_file = pathlib.Path("/var/cache/bunkerweb/modsecurity/crs-plugins.json") %}
|
||||
{% if plugins_path.is_dir() and plugins_file.is_file() %}
|
||||
{% with service_plugins = json.loads(plugins_file.read_text()) %}
|
||||
# include downloaded CRS plugins after rules
|
||||
{% for plugin_id in service_plugins.get(service_id, []) %}
|
||||
{% if plugins_path.joinpath(plugin_id).is_dir() and plugins_path.joinpath(plugin_id).glob("*-after.conf") | list %}
|
||||
include /var/cache/bunkerweb/modsecurity/crs/plugins/{{ plugin_id }}/*-after.conf
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
{% endif +%}
|
||||
|
||||
# custom rules after loading the CRS
|
||||
{% if is_custom_conf("/etc/bunkerweb/configs/modsec") %}
|
||||
include /etc/bunkerweb/configs/modsec/*.conf
|
||||
{% endif %}
|
||||
{% if MULTISITE == "yes" and is_custom_conf("/etc/bunkerweb/configs/modsec/" + SERVER_NAME.split(" ")[0]) %}
|
||||
include /etc/bunkerweb/configs/modsec/{{ SERVER_NAME.split(" ")[0] }}/*.conf
|
||||
{% if MULTISITE == "yes" and is_custom_conf("/etc/bunkerweb/configs/modsec/" + service_id) %}
|
||||
include /etc/bunkerweb/configs/modsec/{{ service_id }}/*.conf
|
||||
{% endif %}
|
||||
{% if is_custom_conf("/etc/nginx/modsec") %}
|
||||
include /etc/nginx/modsec/*.conf
|
||||
{% endif %}
|
||||
{% if MULTISITE == "yes" and is_custom_conf("/etc/nginx/" + SERVER_NAME.split(" ")[0] + "/modsec") %}
|
||||
include /etc/nginx/{{ SERVER_NAME.split(" ")[0] }}/modsec/*.conf
|
||||
{% if MULTISITE == "yes" and is_custom_conf("/etc/nginx/" + service_id + "/modsec") %}
|
||||
include /etc/nginx/{{ service_id }}/modsec/*.conf
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -22,19 +22,19 @@ from jobs import Job # type: ignore
|
|||
LOGGER = setup_logger("MODSECURITY.coreruleset-nightly", getenv("LOG_LEVEL", "INFO"))
|
||||
status = 0
|
||||
|
||||
CRS_PATH = Path(sep, "var", "cache", "bunkerweb", "modsecurity", "crs")
|
||||
CRS_NIGHTLY_PATH = Path(sep, "var", "cache", "bunkerweb", "modsecurity", "crs", "nightly")
|
||||
|
||||
try:
|
||||
# * Check if we're using the nightly version of the Core Rule Set (CRS)
|
||||
use_nightly_crs = False
|
||||
|
||||
if getenv("MODSECURITY_CRS_VERSION", "3") == "nightly":
|
||||
use_nightly_crs = True
|
||||
elif getenv("MULTISITE", "no") == "yes":
|
||||
if getenv("MULTISITE", "no") == "yes":
|
||||
for first_server in getenv("SERVER_NAME", "").split(" "):
|
||||
if first_server and getenv(f"{first_server}_MODSECURITY_CRS_VERSION", getenv("MODSECURITY_CRS_VERSION", "3")) == "nightly":
|
||||
if first_server and getenv(f"{first_server}_MODSECURITY_CRS_VERSION", getenv("MODSECURITY_CRS_VERSION", "4")) == "nightly":
|
||||
use_nightly_crs = True
|
||||
break
|
||||
elif getenv("MODSECURITY_CRS_VERSION", "4") == "nightly":
|
||||
use_nightly_crs = True
|
||||
|
||||
if not use_nightly_crs:
|
||||
LOGGER.info("Core Rule Set (CRS) nightly is not being used, skipping download...")
|
||||
|
|
@ -90,32 +90,33 @@ try:
|
|||
|
||||
file_content.seek(0)
|
||||
|
||||
rmtree(CRS_PATH, ignore_errors=True)
|
||||
CRS_PATH.mkdir(parents=True, exist_ok=True)
|
||||
rmtree(CRS_NIGHTLY_PATH, ignore_errors=True)
|
||||
CRS_NIGHTLY_PATH.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
LOGGER.info("Extracting Core Rule Set (CRS) nightly tarball...")
|
||||
|
||||
with tar_open(fileobj=file_content, mode="r:gz") as tar_file:
|
||||
try:
|
||||
tar_file.extractall(CRS_PATH, filter="data")
|
||||
tar_file.extractall(CRS_NIGHTLY_PATH, filter="data")
|
||||
except TypeError:
|
||||
tar_file.extractall(CRS_PATH)
|
||||
tar_file.extractall(CRS_NIGHTLY_PATH)
|
||||
|
||||
# * Rename the extracted folder to "crs-nightly"
|
||||
extracted_folder = next(CRS_PATH.iterdir())
|
||||
extracted_folder.rename(CRS_PATH.joinpath("crs-nightly"))
|
||||
extracted_folder = next(CRS_NIGHTLY_PATH.iterdir())
|
||||
extracted_folder.rename(CRS_NIGHTLY_PATH.joinpath("crs-nightly"))
|
||||
|
||||
# * Move and rename the example configuration file to "crs-setup-nightly.conf"
|
||||
example_conf = CRS_PATH.joinpath("crs-nightly", "crs-setup.conf.example")
|
||||
example_conf.rename(CRS_PATH.joinpath("crs-setup-nightly.conf"))
|
||||
example_conf = CRS_NIGHTLY_PATH.joinpath("crs-nightly", "crs-setup.conf.example")
|
||||
example_conf.rename(CRS_NIGHTLY_PATH.joinpath("crs-setup-nightly.conf"))
|
||||
|
||||
cached, err = JOB.cache_dir(CRS_PATH)
|
||||
cached, err = JOB.cache_dir(CRS_NIGHTLY_PATH)
|
||||
if not cached:
|
||||
LOGGER.error(f"Error while saving Core Rule Set (CRS) nightly data to db cache: {err}")
|
||||
else:
|
||||
LOGGER.info("Successfully saved Core Rule Set (CRS) nightly data to db cache.")
|
||||
|
||||
status = 1
|
||||
if status == 0:
|
||||
status = 1
|
||||
except SystemExit as e:
|
||||
status = e.code
|
||||
except:
|
||||
|
|
|
|||
240
src/common/core/modsecurity/jobs/download-crs-plugins.py
Normal file
240
src/common/core/modsecurity/jobs/download-crs-plugins.py
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from io import BytesIO
|
||||
from os import getenv, sep
|
||||
from os.path import join
|
||||
from pathlib import Path
|
||||
from re import MULTILINE, compile as re_compile
|
||||
from sys import exit as sys_exit, path as sys_path
|
||||
from typing import Dict, Set
|
||||
from uuid import uuid4
|
||||
from json import dumps
|
||||
from shutil import copy, copytree, move, rmtree
|
||||
from tarfile import open as tar_open
|
||||
from traceback import format_exc
|
||||
from zipfile import ZipFile
|
||||
|
||||
for deps_path in [
|
||||
join(sep, "usr", "share", "bunkerweb", *paths)
|
||||
for paths in (
|
||||
("deps", "python"),
|
||||
("utils",),
|
||||
("api",),
|
||||
("db",),
|
||||
)
|
||||
]:
|
||||
if deps_path not in sys_path:
|
||||
sys_path.append(deps_path)
|
||||
|
||||
from magic import Magic
|
||||
from requests import get
|
||||
|
||||
from logger import setup_logger # type: ignore
|
||||
from jobs import Job # type: ignore
|
||||
|
||||
PLUGIN_NAME_RX = re_compile(r"^# Plugin name: (?P<name>.+)$", MULTILINE)
|
||||
PLUGIN_VERSION_RX = re_compile(r"^# Plugin version: (?P<version>.+)$", MULTILINE)
|
||||
|
||||
CRS_PLUGINS_DIR = Path(sep, "var", "cache", "bunkerweb", "modsecurity", "crs", "plugins")
|
||||
NEW_PLUGINS_DIR = Path(sep, "var", "tmp", "bunkerweb", "crs-new-plugins")
|
||||
TMP_DIR = Path(sep, "var", "tmp", "bunkerweb", "crs-plugins")
|
||||
LOGGER = setup_logger("modsecurity.download-crs-plugins", getenv("LOG_LEVEL", "INFO"))
|
||||
status = 0
|
||||
|
||||
try:
|
||||
# * Check if we're using the 4 or nightly version of the Core Rule Set (CRS)
|
||||
use_right_crs_version = False
|
||||
use_modsecurity_crs_plugins = False
|
||||
|
||||
services = getenv("SERVER_NAME", "").strip()
|
||||
|
||||
if not services:
|
||||
LOGGER.warning("No services found, exiting...")
|
||||
sys_exit(2)
|
||||
|
||||
services = services.split(" ")
|
||||
services_plugin_urls = {}
|
||||
|
||||
if getenv("MULTISITE", "no") == "yes":
|
||||
for first_server in services:
|
||||
if getenv(f"{first_server}_MODSECURITY_CRS_VERSION", getenv("MODSECURITY_CRS_VERSION", "4")) != "3":
|
||||
use_right_crs_version = True
|
||||
|
||||
if getenv(f"{first_server}_USE_MODSECURITY_CRS_PLUGINS", getenv("USE_MODSECURITY_CRS_PLUGINS", "no")) == "yes":
|
||||
use_modsecurity_crs_plugins = True
|
||||
|
||||
service_plugin_urls = getenv(f"{first_server}_MODSECURITY_CRS_PLUGIN_URLS", getenv("MODSECURITY_CRS_PLUGIN_URLS", "")).strip()
|
||||
if service_plugin_urls:
|
||||
services_plugin_urls[first_server] = set(service_plugin_urls.split(" "))
|
||||
else:
|
||||
if getenv("MODSECURITY_CRS_VERSION", "4") != "3":
|
||||
use_right_crs_version = True
|
||||
|
||||
if getenv("USE_MODSECURITY_CRS_PLUGINS", "no") == "yes":
|
||||
use_modsecurity_crs_plugins = True
|
||||
|
||||
plugin_urls = getenv("MODSECURITY_CRS_PLUGIN_URLS", "").strip()
|
||||
if plugin_urls:
|
||||
services_plugin_urls[services[0]] = set(plugin_urls.split(" "))
|
||||
|
||||
if not use_modsecurity_crs_plugins:
|
||||
LOGGER.info("Core Rule Set (CRS) plugins are disabled, skipping download...")
|
||||
sys_exit(0)
|
||||
elif not services_plugin_urls:
|
||||
LOGGER.info("No Core Rule Set (CRS) plugins URLs found, skipping download...")
|
||||
sys_exit(0)
|
||||
elif not use_right_crs_version:
|
||||
LOGGER.warning("No service is using a compatible Core Rule Set (CRS) version with the plugins (4 or nightly), skipping download...")
|
||||
sys_exit(0)
|
||||
|
||||
JOB = Job(LOGGER)
|
||||
|
||||
downloaded_plugins: Dict[str, Set[str]] = {}
|
||||
service_plugins: Dict[str, Set[str]] = {service: set() for service in services}
|
||||
changes = False
|
||||
|
||||
# Loop on plugin URLs
|
||||
LOGGER.info("Checking if any Core Rule Set (CRS) plugin needs to be updated...")
|
||||
for service, plugin_urls in services_plugin_urls.items():
|
||||
installed_plugins = set()
|
||||
|
||||
for crs_plugin_url in plugin_urls:
|
||||
if crs_plugin_url in downloaded_plugins:
|
||||
LOGGER.debug(f"CRS plugin {crs_plugin_url} has already been downloaded, skipping...")
|
||||
installed_plugins.update(downloaded_plugins[crs_plugin_url])
|
||||
continue
|
||||
|
||||
downloaded_plugins[crs_plugin_url] = set()
|
||||
|
||||
with BytesIO() as content:
|
||||
try:
|
||||
resp = get(crs_plugin_url, headers={"User-Agent": "BunkerWeb"}, stream=True, timeout=5)
|
||||
|
||||
if resp.status_code != 200:
|
||||
LOGGER.warning(f"Got status code {resp.status_code}, skipping download of plugin(s) with URL {crs_plugin_url}...")
|
||||
continue
|
||||
|
||||
# Iterate over the response content in chunks
|
||||
for chunk in resp.iter_content(chunk_size=8192):
|
||||
if chunk:
|
||||
content.write(chunk)
|
||||
|
||||
content.seek(0)
|
||||
except BaseException as e:
|
||||
LOGGER.error(f"Exception while downloading plugin(s) with URL {crs_plugin_url} :\n{e}")
|
||||
continue
|
||||
|
||||
# Extract it to tmp folder
|
||||
temp_dir = TMP_DIR.joinpath(str(uuid4()))
|
||||
try:
|
||||
temp_dir.mkdir(parents=True, exist_ok=True)
|
||||
file_type = Magic(mime=True).from_buffer(content.getvalue())
|
||||
content.seek(0)
|
||||
|
||||
if file_type == "application/zip":
|
||||
with ZipFile(content) as zf:
|
||||
zf.extractall(path=temp_dir)
|
||||
elif file_type == "application/gzip":
|
||||
with tar_open(fileobj=content, mode="r:gz") as tar:
|
||||
try:
|
||||
tar.extractall(path=temp_dir, filter="data")
|
||||
except TypeError:
|
||||
tar.extractall(path=temp_dir)
|
||||
elif file_type == "application/x-tar":
|
||||
with tar_open(fileobj=content, mode="r") as tar:
|
||||
try:
|
||||
tar.extractall(path=temp_dir, filter="data")
|
||||
except TypeError:
|
||||
tar.extractall(path=temp_dir)
|
||||
else:
|
||||
LOGGER.error(f"Unknown file type for {crs_plugin_url}, either zip or tar are supported, skipping...")
|
||||
continue
|
||||
except BaseException as e:
|
||||
LOGGER.error(f"Exception while decompressing plugin(s) from {crs_plugin_url} :\n{e}")
|
||||
continue
|
||||
|
||||
# Check if the plugins are valid, if they are already installed and if they need to be updated
|
||||
for plugin_config in temp_dir.rglob("**/*-config.conf"):
|
||||
try:
|
||||
if plugin_config.is_dir():
|
||||
LOGGER.debug(f"CRS plugin {plugin_config} is a directory, skipping...")
|
||||
continue
|
||||
plugin_config_content = plugin_config.read_text()
|
||||
|
||||
# Check if the plugin has a name
|
||||
plugin_name_match = PLUGIN_NAME_RX.search(plugin_config_content)
|
||||
if not plugin_name_match:
|
||||
LOGGER.warning(f"CRS plugin {plugin_config} is missing a name, using filename instead...")
|
||||
plugin_name = plugin_config.stem.replace("-config", "")
|
||||
else:
|
||||
plugin_name = plugin_name_match.group("name")
|
||||
|
||||
# Check if the plugin has a version
|
||||
plugin_version_match = PLUGIN_VERSION_RX.search(plugin_config_content)
|
||||
if not plugin_version_match:
|
||||
LOGGER.warning(f"CRS plugin {plugin_name} is missing a version, skipping...")
|
||||
continue
|
||||
plugin_version = plugin_version_match.group("version")
|
||||
|
||||
LOGGER.debug(f"Checking plugin {plugin_name} (version: {plugin_version})...")
|
||||
|
||||
plugin_id = f"{plugin_name}-{plugin_version}"
|
||||
|
||||
if NEW_PLUGINS_DIR.joinpath(plugin_id).is_dir():
|
||||
LOGGER.debug(f"CRS plugin {plugin_name} (version: {plugin_version}) has already been extracted earlier, skipping...")
|
||||
installed_plugins.add(plugin_id)
|
||||
continue
|
||||
elif CRS_PLUGINS_DIR.joinpath(plugin_id, plugin_config.name).is_file():
|
||||
LOGGER.info(f"CRS plugin {plugin_name} (version: {plugin_version}) is already installed, we don't need to install it")
|
||||
move(CRS_PLUGINS_DIR.joinpath(plugin_id), NEW_PLUGINS_DIR.joinpath(plugin_id))
|
||||
installed_plugins.add(plugin_id)
|
||||
continue
|
||||
|
||||
NEW_PLUGINS_DIR.joinpath(plugin_id).mkdir(parents=True, exist_ok=True)
|
||||
for plugin_file in plugin_config.parent.glob("*"):
|
||||
if plugin_file.is_dir():
|
||||
copytree(plugin_file, NEW_PLUGINS_DIR.joinpath(plugin_id))
|
||||
continue
|
||||
copy(plugin_file, NEW_PLUGINS_DIR.joinpath(plugin_id))
|
||||
|
||||
LOGGER.info(f"CRS plugin {plugin_name} (version: {plugin_version}) has been installed")
|
||||
installed_plugins.add(plugin_id)
|
||||
except BaseException as e:
|
||||
LOGGER.error(f"Exception while checking plugin {plugin_config} :\n{e}")
|
||||
status = 2
|
||||
continue
|
||||
|
||||
downloaded_plugins[crs_plugin_url] = installed_plugins.copy()
|
||||
|
||||
service_plugins[service].update(installed_plugins)
|
||||
|
||||
rmtree(CRS_PLUGINS_DIR, ignore_errors=True)
|
||||
if NEW_PLUGINS_DIR.is_dir():
|
||||
copytree(NEW_PLUGINS_DIR, CRS_PLUGINS_DIR)
|
||||
else:
|
||||
CRS_PLUGINS_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
cached, err = JOB.cache_file("crs-plugins.json", dumps({service: list(plugins) for service, plugins in service_plugins.items()}, indent=2).encode())
|
||||
if not cached:
|
||||
LOGGER.error(f"Failed to cache crs-plugins.json :\n{err}")
|
||||
status = 2
|
||||
|
||||
cached, err = JOB.cache_dir(CRS_PLUGINS_DIR)
|
||||
if not cached:
|
||||
LOGGER.error(f"Error while saving Core Rule Set (CRS) plugins data to db cache: {err}")
|
||||
status = 2
|
||||
else:
|
||||
LOGGER.info("Successfully saved Core Rule Set (CRS) plugins data to db cache.")
|
||||
|
||||
if status == 0:
|
||||
status = 1
|
||||
except SystemExit as e:
|
||||
status = e.code
|
||||
except:
|
||||
status = 2
|
||||
LOGGER.error(f"Exception while running download-crs-plugins.py :\n{format_exc()}")
|
||||
|
||||
rmtree(TMP_DIR, ignore_errors=True)
|
||||
rmtree(NEW_PLUGINS_DIR, ignore_errors=True)
|
||||
|
||||
sys_exit(status)
|
||||
|
|
@ -23,6 +23,15 @@
|
|||
"regex": "^(yes|no)$",
|
||||
"type": "check"
|
||||
},
|
||||
"USE_MODSECURITY_CRS_PLUGINS": {
|
||||
"context": "multisite",
|
||||
"default": "yes",
|
||||
"help": "Enable OWASP Core Rule Set plugins.",
|
||||
"id": "use-modsecurity-crs-plugins",
|
||||
"label": "Use Core Rule Set Plugins",
|
||||
"regex": "^(yes|no)$",
|
||||
"type": "check"
|
||||
},
|
||||
"MODSECURITY_CRS_VERSION": {
|
||||
"context": "multisite",
|
||||
"default": "4",
|
||||
|
|
@ -33,6 +42,15 @@
|
|||
"type": "select",
|
||||
"select": ["3", "4", "nightly"]
|
||||
},
|
||||
"MODSECURITY_CRS_PLUGIN_URLS": {
|
||||
"context": "multisite",
|
||||
"default": "",
|
||||
"help": "List of OWASP CRS plugins URLs (direct download to .zip or .tar file) to download and install (URLs are separated with space). (Not compatible with CRS version 3)",
|
||||
"id": "modsecurity-crs-plugin-urls",
|
||||
"label": "Core Rule Set Plugin URLs",
|
||||
"regex": "^( *((https?:\\/\\/|file:\\/\\/\\/)[\\-\\w@:%.+~#=]+[\\-\\w\\(\\)!@:%+.~#?&\\/=$]*)(?!.*\\2(?!.)) *)*$",
|
||||
"type": "text"
|
||||
},
|
||||
"MODSECURITY_SEC_AUDIT_ENGINE": {
|
||||
"context": "multisite",
|
||||
"default": "RelevantOnly",
|
||||
|
|
@ -69,6 +87,12 @@
|
|||
"file": "coreruleset-nightly.py",
|
||||
"every": "day",
|
||||
"reload": true
|
||||
},
|
||||
{
|
||||
"name": "download-crs-plugins",
|
||||
"file": "download-crs-plugins.py",
|
||||
"every": "day",
|
||||
"reload": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,12 +22,15 @@ METHODS_ENUM = Enum("ui", "scheduler", "autoconf", "manual", name="methods_enum"
|
|||
SCHEDULES_ENUM = Enum("once", "minute", "hour", "day", "week", name="schedules_enum")
|
||||
CUSTOM_CONFIGS_TYPES_ENUM = Enum(
|
||||
"http",
|
||||
"default_server_http",
|
||||
"stream",
|
||||
"server_http",
|
||||
"server_stream",
|
||||
"default_server_http",
|
||||
"default_server_stream",
|
||||
"modsec",
|
||||
"modsec_crs",
|
||||
"stream",
|
||||
"server_stream",
|
||||
"crs_plugins_before",
|
||||
"crs_plugins_after",
|
||||
name="custom_configs_types_enum",
|
||||
)
|
||||
INTEGRATIONS_ENUM = Enum(
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ class Templator:
|
|||
self.__render_template(template)
|
||||
|
||||
def __render_server(self, server: str):
|
||||
templates = self.__find_templates(["modsec", "modsec-crs", "server-http", "server-stream"])
|
||||
templates = self.__find_templates(["modsec", "modsec-crs", "crs-plugins-before", "crs-plugins-after", "server-http", "server-stream"])
|
||||
if self.__config.get("MULTISITE", "no") == "yes":
|
||||
config = self.__config.copy()
|
||||
for variable, value in self.__config.items():
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ from Configurator import Configurator
|
|||
from API import API # type: ignore
|
||||
|
||||
CUSTOM_CONF_RX = re_compile(
|
||||
r"^(?P<service>[0-9a-z\.-]*)_?CUSTOM_CONF_(?P<type>HTTP|SERVER_STREAM|STREAM|DEFAULT_SERVER_HTTP|SERVER_HTTP|MODSEC_CRS|MODSEC)_(?P<name>.+)$"
|
||||
r"^(?P<service>[0-9a-z\.-]*)_?CUSTOM_CONF_(?P<type>HTTP|SERVER_STREAM|STREAM|DEFAULT_SERVER_HTTP|SERVER_HTTP|MODSEC_CRS|MODSEC|CRS_PLUGINS_BEFORE|CRS_PLUGINS_AFTER)_(?P<name>.+)$"
|
||||
)
|
||||
BUNKERWEB_STATIC_INSTANCES_RX = re_compile(r"(http://)?(?P<hostname>(?<![:@])\b[^:@\s]+\b)(:(?P<port>\d+))?")
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ log "$service" "ℹ️" "Setup and check /data folder ..."
|
|||
|
||||
# Create folders if missing and check permissions
|
||||
rwx_folders=("cache" "cache/letsencrypt" "lib")
|
||||
rx_folders=("pro" "pro/plugins" "configs" "configs/http" "configs/stream" "configs/server-http" "configs/server-stream" "configs/default-server-http" "configs/default-server-stream" "configs/modsec" "configs/modsec-crs" "plugins" "www")
|
||||
rx_folders=("pro" "pro/plugins" "configs" "configs/http" "configs/stream" "configs/server-http" "configs/server-stream" "configs/default-server-http" "configs/default-server-stream" "configs/modsec" "configs/modsec-crs" "configs/crs-plugins-before" "configs/crs-plugins-after" "plugins" "www")
|
||||
for folder in "${rwx_folders[@]}" ; do
|
||||
if [ ! -d "/data/${folder}" ] ; then
|
||||
mkdir -p "/data/${folder}"
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ function log() {
|
|||
# get only interesting env (var=value)
|
||||
function get_env() {
|
||||
for var_name in $(python3 -c 'import os ; [print(k) for k in os.environ]') ; do
|
||||
filter=$(echo -n "$var_name" | sed -r 's/^(HOSTNAME|PWD|PKG_RELEASE|NJS_VERSION|SHLVL|PATH|_|NGINX_VERSION|HOME|([0-9a-z\.\-]*)_?CUSTOM_CONF_(HTTP|DEFAULT_SERVER_HTTP|SERVER_HTTP|MODSEC|MODSEC_CRS)_(.*))$//g')
|
||||
filter=$(echo -n "$var_name" | sed -r 's/^(HOSTNAME|PWD|PKG_RELEASE|NJS_VERSION|SHLVL|PATH|_|NGINX_VERSION|HOME|([0-9a-z\.\-]*)_?CUSTOM_CONF_(HTTP|SERVER_STREAM|STREAM|DEFAULT_SERVER_HTTP|SERVER_HTTP|MODSEC_CRS|MODSEC|CRS_PLUGINS_BEFORE|CRS_PLUGINS_AFTER)_(.*))$//g')
|
||||
if [ "$filter" != "" ] ; then
|
||||
var_value=$(python3 -c "import os ; print(os.environ['${var_name}'])")
|
||||
echo "${var_name}=${var_value}"
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ RUN cp helpers/bwcli /usr/bin/ && \
|
|||
chmod 755 /usr/bin/bwcli && \
|
||||
mkdir -p /etc/bunkerweb/configs /etc/bunkerweb/plugins /var/cache/bunkerweb /var/tmp/bunkerweb /var/run/bunkerweb /var/log/bunkerweb /var/lib/bunkerweb /var/www/html && \
|
||||
echo "Linux" > INTEGRATION && \
|
||||
for dir in $(echo "plugins pro/plugins configs/http configs/stream configs/server-http configs/server-stream configs/default-server-http configs/default-server-stream configs/modsec configs/modsec-crs") ; do mkdir -p "/etc/bunkerweb/${dir}" ; done && \
|
||||
for dir in $(echo "plugins pro/plugins configs/http configs/stream configs/server-http configs/server-stream configs/default-server-http configs/default-server-stream configs/modsec configs/modsec-crs configs/crs-plugins-before configs/crs-plugins-after") ; do mkdir -p "/etc/bunkerweb/${dir}" ; done && \
|
||||
find . -path deps -prune -o -type f -exec chmod 0740 {} \; && \
|
||||
find . -path deps -prune -o -type d -exec chmod 0750 {} \; && \
|
||||
chmod 755 /var/log/bunkerweb && \
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ RUN cp helpers/bwcli /usr/bin/ && \
|
|||
chmod 755 /usr/bin/bwcli && \
|
||||
mkdir -p /etc/bunkerweb/configs /etc/bunkerweb/plugins /var/cache/bunkerweb /var/tmp/bunkerweb /var/run/bunkerweb /var/log/bunkerweb /var/lib/bunkerweb /var/www/html && \
|
||||
echo "Linux" > INTEGRATION && \
|
||||
for dir in $(echo "plugins pro/plugins configs/http configs/stream configs/server-http configs/server-stream configs/default-server-http configs/default-server-stream configs/modsec configs/modsec-crs") ; do mkdir -p "/etc/bunkerweb/${dir}" ; done && \
|
||||
for dir in $(echo "plugins pro/plugins configs/http configs/stream configs/server-http configs/server-stream configs/default-server-http configs/default-server-stream configs/modsec configs/modsec-crs configs/crs-plugins-before configs/crs-plugins-after") ; do mkdir -p "/etc/bunkerweb/${dir}" ; done && \
|
||||
find . -path deps -prune -o -type f -exec chmod 0740 {} \; && \
|
||||
find . -path deps -prune -o -type d -exec chmod 0750 {} \; && \
|
||||
chmod 755 /var/log/bunkerweb && \
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ RUN cp helpers/bwcli /usr/bin/ && \
|
|||
chmod 755 /usr/bin/bwcli && \
|
||||
mkdir -p /etc/bunkerweb/configs /etc/bunkerweb/plugins /var/cache/bunkerweb /var/tmp/bunkerweb /var/run/bunkerweb /var/log/bunkerweb /var/lib/bunkerweb /var/www/html && \
|
||||
echo "Linux" > INTEGRATION && \
|
||||
for dir in $(echo "plugins pro/plugins configs/http configs/stream configs/server-http configs/server-stream configs/default-server-http configs/default-server-stream configs/modsec configs/modsec-crs") ; do mkdir -p "/etc/bunkerweb/${dir}" ; done && \
|
||||
for dir in $(echo "plugins pro/plugins configs/http configs/stream configs/server-http configs/server-stream configs/default-server-http configs/default-server-stream configs/modsec configs/modsec-crs configs/crs-plugins-before configs/crs-plugins-after") ; do mkdir -p "/etc/bunkerweb/${dir}" ; done && \
|
||||
find . -path deps -prune -o -type f -exec chmod 0740 {} \; && \
|
||||
find . -path deps -prune -o -type d -exec chmod 0750 {} \; && \
|
||||
chmod 755 /var/log/bunkerweb && \
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ RUN cp helpers/bwcli /usr/bin/ && \
|
|||
chmod 755 /usr/bin/bwcli && \
|
||||
mkdir -p /etc/bunkerweb/configs /etc/bunkerweb/plugins /var/cache/bunkerweb /var/tmp/bunkerweb /var/run/bunkerweb /var/log/bunkerweb /var/lib/bunkerweb /var/www/html && \
|
||||
echo "Linux" > INTEGRATION && \
|
||||
for dir in $(echo "plugins pro/plugins configs/http configs/stream configs/server-http configs/server-stream configs/default-server-http configs/default-server-stream configs/modsec configs/modsec-crs") ; do mkdir -p "/etc/bunkerweb/${dir}" ; done && \
|
||||
for dir in $(echo "plugins pro/plugins configs/http configs/stream configs/server-http configs/server-stream configs/default-server-http configs/default-server-stream configs/modsec configs/modsec-crs configs/crs-plugins-before configs/crs-plugins-after") ; do mkdir -p "/etc/bunkerweb/${dir}" ; done && \
|
||||
find . -path deps -prune -o -type f -exec chmod 0740 {} \; && \
|
||||
find . -path deps -prune -o -type d -exec chmod 0750 {} \; && \
|
||||
chmod 755 /var/log/bunkerweb && \
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ RUN cp helpers/bwcli /usr/bin/ && \
|
|||
chmod 755 /usr/bin/bwcli && \
|
||||
mkdir -p /etc/bunkerweb/configs /etc/bunkerweb/plugins /var/cache/bunkerweb /var/tmp/bunkerweb /var/run/bunkerweb /var/log/bunkerweb /var/lib/bunkerweb /var/www/html && \
|
||||
echo "Linux" > INTEGRATION && \
|
||||
for dir in $(echo "plugins pro/plugins configs/http configs/stream configs/server-http configs/server-stream configs/default-server-http configs/default-server-stream configs/modsec configs/modsec-crs") ; do mkdir -p "/etc/bunkerweb/${dir}" ; done && \
|
||||
for dir in $(echo "plugins pro/plugins configs/http configs/stream configs/server-http configs/server-stream configs/default-server-http configs/default-server-stream configs/modsec configs/modsec-crs configs/crs-plugins-before configs/crs-plugins-after") ; do mkdir -p "/etc/bunkerweb/${dir}" ; done && \
|
||||
find . -path deps -prune -o -type f -exec chmod 0740 {} \; && \
|
||||
find . -path deps -prune -o -type d -exec chmod 0750 {} \; && \
|
||||
chmod 755 /var/log/bunkerweb && \
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ RUN cp helpers/bwcli /usr/bin/ && \
|
|||
chmod 755 /usr/bin/bwcli && \
|
||||
mkdir -p /etc/bunkerweb/configs /etc/bunkerweb/plugins /var/cache/bunkerweb /var/tmp/bunkerweb /var/run/bunkerweb /var/log/bunkerweb /var/lib/bunkerweb /var/www/html && \
|
||||
echo "Linux" > INTEGRATION && \
|
||||
for dir in $(echo "plugins pro/plugins configs/http configs/stream configs/server-http configs/server-stream configs/default-server-http configs/default-server-stream configs/modsec configs/modsec-crs") ; do mkdir -p "/etc/bunkerweb/${dir}" ; done && \
|
||||
for dir in $(echo "plugins pro/plugins configs/http configs/stream configs/server-http configs/server-stream configs/default-server-http configs/default-server-stream configs/modsec configs/modsec-crs configs/crs-plugins-before configs/crs-plugins-after") ; do mkdir -p "/etc/bunkerweb/${dir}" ; done && \
|
||||
find . -path deps -prune -o -type f -exec chmod 0740 {} \; && \
|
||||
find . -path deps -prune -o -type d -exec chmod 0750 {} \; && \
|
||||
chmod 755 /var/log/bunkerweb && \
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ RUN apk add --no-cache bash unzip libgcc libstdc++ libpq openssl libmagic mariad
|
|||
mkdir -p /data/cache && ln -s /data/cache /var/cache/bunkerweb && \
|
||||
mkdir -p /data/lib && ln -s /data/lib /var/lib/bunkerweb && \
|
||||
for dir in $(echo "pro configs plugins") ; do mkdir -p "/data/${dir}" && ln -s "/data/${dir}" "/etc/bunkerweb/${dir}" ; done && \
|
||||
for dir in $(echo "pro/plugins configs/http configs/stream configs/server-http configs/server-stream configs/default-server-http configs/default-server-stream configs/modsec configs/modsec-crs") ; do mkdir "/data/${dir}" ; done && \
|
||||
for dir in $(echo "pro/plugins configs/http configs/stream configs/server-http configs/server-stream configs/default-server-http configs/default-server-stream configs/modsec configs/modsec-crs configs/crs-plugins-before configs/crs-plugins-after") ; do mkdir "/data/${dir}" ; done && \
|
||||
chown -R root:scheduler INTEGRATION /data /etc/nginx /var/cache/bunkerweb /var/lib/bunkerweb /etc/bunkerweb /var/tmp/bunkerweb /var/run/bunkerweb /var/log/bunkerweb /usr/bin/bwcli && \
|
||||
chmod -R 770 /data /etc/nginx /var/cache/bunkerweb /var/lib/bunkerweb /etc/bunkerweb /var/tmp/bunkerweb /var/run/bunkerweb /var/log/bunkerweb && \
|
||||
find core/*/jobs/* -type f -exec chmod 750 {} \; && \
|
||||
|
|
|
|||
|
|
@ -53,6 +53,8 @@ CUSTOM_CONFIGS_DIRS = (
|
|||
"default-server-stream",
|
||||
"modsec",
|
||||
"modsec-crs",
|
||||
"crs-plugins-before",
|
||||
"crs-plugins-after",
|
||||
)
|
||||
|
||||
for custom_config_dir in CUSTOM_CONFIGS_DIRS:
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ RUN apk add --no-cache bash unzip libmagic mariadb-client postgresql-client sqli
|
|||
mkdir -p /data/cache && ln -s /data/cache /var/cache/bunkerweb && \
|
||||
mkdir -p /data/lib && ln -s /data/lib /var/lib/bunkerweb && \
|
||||
for dir in $(echo "pro configs plugins") ; do mkdir -p "/data/${dir}" && ln -s "/data/${dir}" "/etc/bunkerweb/${dir}" ; done && \
|
||||
for dir in $(echo "pro/plugins configs/http configs/stream configs/server-http configs/server-stream configs/default-server-http configs/default-server-stream configs/modsec configs/modsec-crs") ; do mkdir "/data/${dir}" ; done && \
|
||||
for dir in $(echo "pro/plugins configs/http configs/stream configs/server-http configs/server-stream configs/default-server-http configs/default-server-stream configs/modsec configs/modsec-crs configs/crs-plugins-before configs/crs-plugins-after") ; do mkdir "/data/${dir}" ; done && \
|
||||
chown -R root:ui INTEGRATION /data /var/cache/bunkerweb /var/lib/bunkerweb /etc/bunkerweb /var/tmp/bunkerweb /var/run/bunkerweb /var/log/bunkerweb && \
|
||||
chmod -R 770 /data /var/cache/bunkerweb /var/lib/bunkerweb /etc/bunkerweb /var/tmp/bunkerweb /var/run/bunkerweb /var/log/bunkerweb && \
|
||||
chmod 750 gen/*.py ui/*.py ui/src/*.py helpers/*.sh deps/python/bin/* && \
|
||||
|
|
|
|||
|
|
@ -1181,7 +1181,18 @@ def services():
|
|||
operation = request.form["operation"]
|
||||
# Get all variables starting with custom_config and delete them from variables
|
||||
custom_configs = []
|
||||
config_types = ("http", "stream", "server-http", "server-stream", "default-server-http", "modsec", "modsec-crs")
|
||||
config_types = (
|
||||
"http",
|
||||
"stream",
|
||||
"server-http",
|
||||
"server-stream",
|
||||
"default-server-http",
|
||||
"default-server-stream",
|
||||
"modsec",
|
||||
"modsec-crs",
|
||||
"crs-plugins-before",
|
||||
"crs-plugins-after",
|
||||
)
|
||||
|
||||
for variable in variables:
|
||||
if variable.startswith("custom_config_"):
|
||||
|
|
|
|||
|
|
@ -58,15 +58,18 @@ def path_to_dict(
|
|||
services = services or []
|
||||
|
||||
if not is_cache:
|
||||
config_types = [
|
||||
config_types = (
|
||||
"http",
|
||||
"stream",
|
||||
"server-http",
|
||||
"server-stream",
|
||||
"default-server-http",
|
||||
"default-server-stream",
|
||||
"modsec",
|
||||
"modsec-crs",
|
||||
]
|
||||
"crs-plugins-before",
|
||||
"crs-plugins-after",
|
||||
)
|
||||
|
||||
d = {
|
||||
"name": "configs",
|
||||
|
|
|
|||
Loading…
Reference in a new issue