diff --git a/openresty/.gitignore b/openresty/.gitignore new file mode 100644 index 0000000..7773c34 --- /dev/null +++ b/openresty/.gitignore @@ -0,0 +1,5 @@ +logs/ +.env +*.key +*.cer +.op diff --git a/openresty/README.md b/openresty/README.md new file mode 100644 index 0000000..33904e4 --- /dev/null +++ b/openresty/README.md @@ -0,0 +1,37 @@ +# WARNING + +See [here](../basic/README.md) for the log file pitfall + +# Description + +This example explains how to integrate Crowdsec in environment deployed with docker-compose. It set up multiple containers : + +This example contains multiple containers : +* app : apache server serving index.html containing an `hello world` +* openresty : openresty built on nginx that serving this app from the host +* crowdsec : it will read reverse-proxy logs from the shared volume +* dashboard : we use [metabase](https://hub.docker.com/r/metabase/metabase) to display crowdsec database data. + +## Openresty + +The example builds om the https://registry.hub.docker.com/r/crowdsecurity/openresty docker image, as it comes with the bouncer plugin bundled. +The configuration is passed by by the enviroment variable `BOUNCER_CONFIG`. The referenced secrect e.g. `${CROWDSEC_BOUNCER_OPENRESTY_APIKEY}` are passed via a `.env` file. + +The `APPSEC_URL` feature needs is activated in the `crowdsec` container itself. + +For website serving the file [default.conf](openresty/conf.d/default.conf) shows a plain port 80 http example and a SSL https example. Note the [certificate](https://nginx.org/en/docs/http/configuring_https_servers.html) and key need to be provided, to run this. + +## Crowdsec + +Note the `BOUNCER_KEY_openresty` enviroment variable. It regesiters the Bouncer with an own key. Yes, that means the `${CROWDSEC_BOUNCER_OPENRESTY_APIKEY}` value can be choosen in the `.env` file. Recommendation is to use a random UUID. + +`APPSEC` in configured by adding the collections `crowdsecurity/appsec-virtual-patching` and `crowdsecurity/appsec-generic-rules`, as well as in [acquis.yaml](crowdsec/acquis.yaml). Note [link](https://docs.crowdsec.net/u/getting_started/post_installation/acquisition_new/) shows how to cleanly do this. + +# Prerequisites: +[Docker](https://docs.docker.com/engine/install/) / [Docker Compose](https://docs.docker.com/compose/install/) + +# Discussions + +[GitHub --> Networking - userland-proxy could better clarify impact #17312](https://github.com/docker/docs/issues/17312) + +# ps: default's credentials for metabase are `crowdsec@crowdsec.net` and `!!Cr0wdS3c_M3t4b4s3??` diff --git a/openresty/app/index.html b/openresty/app/index.html new file mode 100644 index 0000000..93b493a --- /dev/null +++ b/openresty/app/index.html @@ -0,0 +1 @@ +Hello world ! \ No newline at end of file diff --git a/openresty/crowdsec/acquis.yaml b/openresty/crowdsec/acquis.yaml new file mode 100644 index 0000000..f220d4c --- /dev/null +++ b/openresty/crowdsec/acquis.yaml @@ -0,0 +1,11 @@ +filenames: + - /var/log/nginx/example.*.log +labels: + type: nginx +--- +listen_addr: :7422 +appsec_config: crowdsecurity/appsec-default +name: openrestyAppSec +source: appsec +labels: + type: appsec \ No newline at end of file diff --git a/openresty/crowdsec/dashboard/Dockerfile b/openresty/crowdsec/dashboard/Dockerfile new file mode 100644 index 0000000..002484a --- /dev/null +++ b/openresty/crowdsec/dashboard/Dockerfile @@ -0,0 +1,3 @@ +FROM metabase/metabase + +RUN mkdir /data/ && wget https://crowdsec-statics-assets.s3-eu-west-1.amazonaws.com/metabase_sqlite.zip && unzip metabase_sqlite.zip -d /data/ \ No newline at end of file diff --git a/openresty/docker-compose.yml b/openresty/docker-compose.yml new file mode 100644 index 0000000..d25d297 --- /dev/null +++ b/openresty/docker-compose.yml @@ -0,0 +1,84 @@ +name: crowdsec + +services: + #the application itself : static html served by apache2. + #the html can be found in ./app/ + app: + image: httpd:alpine + restart: unless-stopped + volumes: + - ./app/:/usr/local/apache2/htdocs/ + + openresty: + image: ghcr.io/stevusprimus/cs-openresty-bouncer:buildx-latest + restart: unless-stopped + ports: + - 3080:80 + - 3443:443 + depends_on: + - 'app' + volumes: + - ./openresty/conf.d:/etc/nginx/conf.d + - ./logs:/var/log/nginx + environment: + BOUNCER_CONFIG: | + APPSEC_URL=http://crowdsec:7422 + + APPSEC_FAILURE_ACTION=deny + ALWAYS_SEND_TO_APPSEC=true + SSL_VERIFY=false + MODE=stream + + FALLBACK_REMEDIATION=ban + BOUNCING_ON_TYPE=all + + BAN_TEMPLATE_PATH=/var/lib/crowdsec/lua/templates/ban.html + + API_KEY=${CROWDSEC_BOUNCER_OPENRESTY_APIKEY} + API_URL=http://crowdsec:8080 + + CAPTCHA_PROVIDER=${CROWDSEC_BOUNCER_OPENRESTY_CAPTCHA_PROVIDER} + SECRET_KEY=${CROWDSEC_BOUNCER_OPENRESTY_SECRET_KEY} + SITE_KEY=${CROWDSEC_BOUNCER_OPENRESTY_SITE_KEY} + CAPTCHA_TEMPLATE_PATH=/var/lib/crowdsec/lua/templates/captcha.html + + crowdsec: + image: crowdsecurity/crowdsec + restart: unless-stopped + environment: + #this is the list of collections we want to install + #https://hub.crowdsec.net/author/crowdsecurity/collections/nginx + COLLECTIONS: "crowdsecurity/nginx crowdsecurity/appsec-virtual-patching crowdsecurity/appsec-generic-rules" + GID: "${GID-1000}" + TZ: "Europe/Berlin" + BOUNCER_KEY_openresty: ${CROWDSEC_BOUNCER_OPENRESTY_APIKEY} + depends_on: + - openresty + #ports: + # - 3001:8080 ## We expose the LAPI 8080 via loopback for bouncers to connect + ## Change to '8080:8080' if you want to expose the LAPI to external hosts, HOWEVER, do so at your own risk. + volumes: + - ./crowdsec/acquis.yaml:/etc/crowdsec/acquis.yaml + - ./logs:/var/log/nginx + - crowdsec-db:/var/lib/crowdsec/data/ + - crowdsec-config:/etc/crowdsec/ + + #metabase, because security is cool, but dashboards are cooler + # dashboard: + # #we're using a custom Dockerfile so that metabase pops with pre-configured dashboards + # build: ./crowdsec/dashboard + # restart: unless-stopped + # ports: + # - 3000:3000 + # environment: + # MB_DB_FILE: /data/metabase.db + # MGID: "${GID-1000}" + # depends_on: + # - 'crowdsec' + # volumes: + # - crowdsec-db:/metabase-data/ + +volumes: + logs: + crowdsec-db: + crowdsec-config: diff --git a/openresty/openresty/conf.d/default.conf b/openresty/openresty/conf.d/default.conf new file mode 100644 index 0000000..81e6447 --- /dev/null +++ b/openresty/openresty/conf.d/default.conf @@ -0,0 +1,102 @@ +# nginx.vh.default.conf -- docker-openresty +# +# This file is installed to: +# `/etc/nginx/conf.d/default.conf` +# +# It tracks the `server` section of the upstream OpenResty's `nginx.conf`. +# +# This config (and any other configs in `etc/nginx/conf.d/`) is loaded by +# default by the `include` directive in `/usr/local/openresty/nginx/conf/nginx.conf`. +# +# See https://github.com/openresty/docker-openresty/blob/master/README.md#nginx-config-files +# + +upstream docker-app { + server app:80; +} + +server { + listen 443 ssl; + server_name localhost; + ssl_certificate /etc/nginx/conf.d/dummy.cer; + ssl_certificate_key /etc/nginx/conf.d/dummy.key; + + location / { + proxy_pass http://docker-app; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host $host; + + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $server_name; + proxy_redirect off; + proxy_read_timeout 86400; + add_header Access-Control-Allow-Origin *; + } + + access_log /var/log/nginx/example.access.log; + error_log /var/log/nginx/example.error.log; +} + +server { + listen 80; + server_name localhost; + + #charset koi8-r; + #access_log /var/log/nginx/host.access.log main; + + #location / { + # root /usr/local/openresty/nginx/html; + # index index.html index.htm; + #} + + location / { + proxy_pass http://docker-app; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host $host; + + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $server_name; + proxy_redirect off; + proxy_read_timeout 86400; + add_header Access-Control-Allow-Origin *; + } + + access_log /var/log/nginx/example.access.log; + error_log /var/log/nginx/example.error.log; + + #error_page 404 /404.html; + + # redirect server error pages to the static page /50x.html + # + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/local/openresty/nginx/html; + } + + # proxy the PHP scripts to Apache listening on 127.0.0.1:80 + # + #location ~ \.php$ { + # proxy_pass http://127.0.0.1; + #} + + # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 + # + #location ~ \.php$ { + # root /usr/local/openresty/nginx/html; + # fastcgi_pass 127.0.0.1:9000; + # fastcgi_index index.php; + # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; + # include fastcgi_params; + #} + + # deny access to .htaccess files, if Apache's document root + # concurs with nginx's one + # + #location ~ /\.ht { + # deny all; + #} +} \ No newline at end of file