nginx-proxy-manager icon indicating copy to clipboard operation
nginx-proxy-manager copied to clipboard

Integration with crowdsecurity/cs-nginx-bouncer

Open Sparkxxx opened this issue 3 years ago • 59 comments

Is your feature request related to a problem? Please describe. I would like to add protection for sites to NPM and be able to block IP's based on reputation/scenario using Crowdsecurity https://github.com/crowdsecurity which is a log analyzer and reactive firewall, something like fail2ban but in a much modern architecture and suitable for the containers world and having a distributed banlist generated from users around the world.

The question/feature request is how/where to add the https://github.com/crowdsecurity/cs-nginx-bouncer module to nginx config. This bouncer leverages nginx lua's API, namely access_by_lua_file. New/unknown IPs are checked against crowdsec API, and if request should be blocked, a 403 is returned to the user, and put in cache. The exact desired action can be configured in Crowdsec, like displaying captcas etc.

Describe the solution you'd like I would like to have an easy way (example maybe) to deploy the bouncer without breaking things in npm.

Describe alternatives you've considered None so far since it might take you minutes to offer a solution and it would take me hours to tweak things and break them :)

Additional context Please have a look at https://crowdsec.net/ to understand what is crowdsec and how it works. I use jc21/nginx-proxy-manager:latest for NPM and https://github.com/crowdsecurity/crowdsec/tree/master/docker for Crowdsec containers analyzing the nginx logs allready written by NPM on disk (docker map volumes ./npm_data/logs/:/var/log/nginx/ and have a quick look at acquis.yaml which tells crowdsec which logs to parse, mine looks like this): `filenames:

  • /var/log/nginx/*.log labels: type: nginx`

Thank you and hope you'd consider this as a valuable addition to NPM

Sparkxxx avatar May 28 '21 06:05 Sparkxxx

Referencing https://github.com/jc21/nginx-proxy-manager/issues/39.

chaptergy avatar May 28 '21 09:05 chaptergy

I have read that feature request but, let me justify better my request. As far as I know fail2ban works only on one machine so it would have to manipulate some iptables/ipsets or scripts to work over a network and this implies many moving parts. It is basically a stand alone application from before the container world and I'm not even speaking here about swarms. I know it's usefull, I'm using it but not in the container world where in my opinion it looks like a dinosaur. Crowdsec (runs on docker and has 3.3K stars on github) on the other hand is a more modern and advanced way of achieving the same goals as with fail2ban but in a distributed infrastructure with networking, VM's, containers, barebones, detecting atacks, redirecting, banning, serving captchas, etc., with a graphical interface and we love the GUIs. Bouncers and detectors don't even have to be on the same machine/container. Have a look at their agents/bouncers HUB https://hub.crowdsec.net/ and BLOG https://crowdsec.net/blog/ for what is already available.

My requested integration ( https://hub.crowdsec.net/author/crowdsecurity/bouncers/cs-nginx-bouncer ) is already a lua script that works in OpenResty, so it would only be, in my opinion, a matter of copy-paste in the config file of NPM and not writing a new module or script to integrate it.

Please allow me to cite from Crowdsec's website:

  • CrowdSec is an open-source and collaborative EDR. Analyze behaviors, respond to attacks & share signals across the community.

  • Crowdsec-agent is an open-source and lightweight software that allows you to detect peers with malevolent behaviors and block them from accessing your systems at various level (infrastructural, system, applicative).

  • To achieve this, Crowdsec-agent reads logs from different sources (files, streams ...) to parse, normalize and enrich them before matching them to threats patterns called scenarios.

  • Crowdsec-agent is a modular and plug-able framework, it ships a large variety of well known popular scenarios; users can choose what scenarios they want to be protected from as well as easily adding new custom ones to better fit their environment.

  • Detected malevolent peers can then be prevented from accessing your resources by deploying bouncers at various levels (applicative, system, infrastructural) of your stack.

  • One of the advantages of Crowdsec when compared to other solutions is its crowd-sourced aspect : Meta information about detected attacks (source IP, time and triggered scenario) are sent to a central API and then shared amongst all users.

  • Thanks to this, besides detecting and stopping attacks in real time based on your logs, it allows you to preemptively block known bad actors from accessing your information system.

I understand that Crowdsec is a new tool for many but it is able to do even more than fail2ban and the learning curve is low and in the long run it would overtake f2b and all you have to do is configure it where to read the logs and it is already packed with detectors and ready to take action trough bouncers on new detected atacker or the ones downloaded from the community list. It is a set and forget application that can be further integrated with others, being prometheus or your own application over the network trough it's api.

Sparkxxx avatar May 28 '21 14:05 Sparkxxx

Yeah, it was not my intention to say this issue was the same thing as the fail2ban one, I just wanted to cross-link these issues, since this they seem mutually exclusive.

chaptergy avatar May 28 '21 14:05 chaptergy

I didn't thought you were saying that, just wanted to clarify a little bit since with appearance of crowdsec (v0.0.1 - May 15, 2020), supporting an old tool and reinventing the wheel and wasting time building around f2b seeamd like a bad idea. Hope you like my proposal and looking forward to see it integrated in NPM.

Sparkxxx avatar May 28 '21 15:05 Sparkxxx

Hello, I'll add my vote for this feature. I thinks this is very different from fail2ban in which follows the crowdsourcing approach.

Thanks!

luismanson avatar Oct 08 '21 00:10 luismanson

@Sparkxxx do you have the manual steps to do this for the time being? I'm not very familiar with crowdsec so forgive my naivete, I think I have setup crowdsec and metabse in the same dockerfile using the guide here and here, but when i test with nikto from another machine on the local network I do not see a new decision and logs don't appear to show traffic. There isn't an official docker image for the nginx bouncer either, but based on your comment it seems like there may not be a need for an extra bouncer container. Here's the setup I have so far:

version: '3'
services:
  app:
    image: 'jc21/nginx-proxy-manager:latest'
    restart: unless-stopped
    ports:
      - '80:80'
      - '81:81'
      - '443:443'
    environment:
      DB_MYSQL_HOST: "db"
      DB_MYSQL_PORT: 3306
      DB_MYSQL_USER: "npm"
      DB_MYSQL_PASSWORD: "npm"
      DB_MYSQL_NAME: "npm"
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
      - logs:/var/log/nginx
  db:
    image: 'jc21/mariadb-aria:latest'
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: 'npm'
      MYSQL_DATABASE: 'npm'
      MYSQL_USER: 'npm'
      MYSQL_PASSWORD: 'npm'
    volumes:
      - ./data/mysql:/var/lib/mysql


  #crowdsec : it will be fed nginx's logs
  #and later we're going to plug a firewall bouncer to it
  crowdsec:
    image: crowdsecurity/crowdsec:latest
    restart: always
    environment:
      #this is the list of collections we want to install
      #https://hub.crowdsec.net/author/crowdsecurity/collections/nginx
      COLLECTIONS: "crowdsecurity/nginx"
      GID: "${GID-1000}"
    depends_on:
      - 'app'
    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: always
    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:

nisargjoshi95 avatar Oct 14 '21 23:10 nisargjoshi95

I am head of community at CrowdSec (and an avid user myself). I think it's a great idea to add support for CrowdSec as well. Also I would like to offer my assistance and a way into the CrowdSec dev team if you need any help implementing it.

I would also like to point any technical questions regarding CrowdSec to our discourse where all devs are available to help out.

@nisargjoshi95 Did you ever get this working? If not, feel free to ask on the discourse :-)

klausagnoletti avatar Nov 18 '21 10:11 klausagnoletti

@nisargjoshi95 Did you ever get this working? If not, feel free to ask on the discourse :-)

klausagnoletti avatar Nov 18 '21 10:11 klausagnoletti

@Sparkxxx please give me a buzz on the discourse, on twitter @klausagnoletti or send me a mail [email protected]. I'd like to ask about your experience with CrowdSec etc.

klausagnoletti avatar Nov 18 '21 10:11 klausagnoletti

I am here to cast my vote, I haven't started looking in depth yet but does anyone have crowdsec setup with the bouncer and NPM?

@klausagnoletti - Should I just go to the discourse and ask there or are there any crowdsec docs on how to set it all up while utilizing NPM? Thanks.

baudneo avatar Nov 22 '21 01:11 baudneo

@nisargjoshi95

I'll think your docker-compose wont work because nginx proxymanager is storing it's logs in other than the default nginx folders.

change your acquis.yml to - /var/log/nginx/*.log and then try this docker-compose: it reads the logs folder which is mounted by nginx-proxymananger container. it will read the logs but the parsing isn't that good


services:
 #crowdsec : it will be fed nginx's logs
 #and later we're going to plug a firewall bouncer to it
 crowdsec:
   image: crowdsecurity/crowdsec:v1.2.1
   restart: always
   environment:
     #this is the list of collections we want to install
     #https://hub.crowdsec.net/author/crowdsecurity/collections/nginx
     COLLECTIONS: "crowdsecurity/nginx"
     GID: "${GID-1000}"
  
   volumes:
     - ./crowdsec/acquis.yaml:/etc/crowdsec/acquis.yaml
     - /fullpath-to-nginx-proxymanager/data/logs:/var/log/nginx
     - crowdsec-db:/var/lib/crowdsec/data/
     - crowdsec-config:/etc/crowdsec/
   networks:
     crowdsec_test:
       ipv4_address: 172.20.0.4
  #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: always
   ports:
     - 3000:3000
   environment:
     MB_DB_FILE: /data/metabase.db
     MGID: "${GID-1000}"
   depends_on:
     - 'crowdsec'
   volumes:
     - crowdsec-db:/metabase-data/
   networks:
     crowdsec_test:
       ipv4_address: 172.20.0.5

volumes:
 logs:
 crowdsec-db:
 crowdsec-config:

networks:
 crowdsec_test:
   ipam:
     driver: default
     config:
       - subnet: 172.20.0.0/24




INFO[26-11-2021 04:58:54 PM] Buckets Metrics:
+--------------------------------------+---------------+-----------+--------------+--------+---------+
|                BUCKET                | CURRENT COUNT | OVERFLOWS | INSTANCIATED | POURED | EXPIRED |
+--------------------------------------+---------------+-----------+--------------+--------+---------+
| crowdsecurity/http-bad-user-agent    | -             | -         |            2 |      2 |       2 |
| crowdsecurity/http-crawl-non_statics | -             | -         |           77 |     77 |      77 |
+--------------------------------------+---------------+-----------+--------------+--------+---------+
INFO[26-11-2021 04:58:54 PM] Acquisition Metrics:
+---------------------------------------------+------------+--------------+----------------+------------------------+
|                   SOURCE                    | LINES READ | LINES PARSED | LINES UNPARSED | LINES POURED TO BUCKET |
+---------------------------------------------+------------+--------------+----------------+------------------------+
| file:/var/log/nginx/default-host_access.log |         37 |           30 |              7 |                     32 |
| file:/var/log/nginx/fallback-access.log     |         34 | -            |             34 | -                      |
| file:/var/log/nginx/fallback_error.log      |         23 |           23 | -              |                     20 |
| file:/var/log/nginx/proxy-host-1_access.log |        216 | -            |            216 | -                      |
| file:/var/log/nginx/proxy-host-1_error.log  |         28 |           28 | -              |                     27 |
+---------------------------------------------+------------+--------------+----------------+------------------------+
INFO[26-11-2021 04:58:54 PM] Parser Metrics:
+--------------------------------+------+--------+----------+
|            PARSERS             | HITS | PARSED | UNPARSED |
+--------------------------------+------+--------+----------+
| child-crowdsecurity/http-logs  |  243 |    100 |      143 |
| child-crowdsecurity/nginx-logs |  646 |     81 |      565 |
| crowdsecurity/dateparse-enrich |   81 |     81 | -        |
| crowdsecurity/geoip-enrich     |   30 |     30 | -        |
| crowdsecurity/http-logs        |   81 |     14 |       67 |
| crowdsecurity/nginx-logs       |  338 |     81 |      257 |
| crowdsecurity/non-syslog       |  338 |    338 | -        |
| crowdsecurity/whitelists       |   81 |     81 | -        |
+--------------------------------+------+--------+----------+
INFO[26-11-2021 04:58:54 PM] Local Api Metrics:
+----------------------+--------+------+
|        ROUTE         | METHOD | HITS |
+----------------------+--------+------+
| /v1/alerts           | GET    |    1 |
| /v1/decisions/stream | GET    | 7021 |
| /v1/watchers/login   | POST   |    3 |
+----------------------+--------+------+
INFO[26-11-2021 04:58:54 PM] Local Api Machines Metrics:
+-----------+------------+--------+------+
|  MACHINE  |   ROUTE    | METHOD | HITS |
+-----------+------------+--------+------+
| localhost | /v1/alerts | GET    |    1 |
+-----------+------------+--------+------+
INFO[26-11-2021 04:58:54 PM] Local Api Bouncers Metrics:
+---------------------+----------------------+--------+------+
|       BOUNCER       |        ROUTE         | METHOD | HITS |
+---------------------+----------------------+--------+------+
| HostFirewallBouncer | /v1/decisions/stream | GET    | 7021 |
+---------------------+----------------------+--------+------+





2Wanderer avatar Nov 26 '21 16:11 2Wanderer

@baudneo did this work for you? I would have thought there would be issues with NPM's custom log format.

jakern avatar Nov 26 '21 20:11 jakern

@klausagnoletti - Should I just go to the discourse and ask there or are there any crowdsec docs on how to set it all up while utilizing NPM? Thanks.

Sorry for my late reply. I don't get notifications from Github even though I enabled it :-/

Just go to the Discorse and ask. To my knowledge noone has tried integrating with npm yet.

klausagnoletti avatar Nov 26 '21 21:11 klausagnoletti

@jakern, it is a strange situation. If NPM is already running, proxying requests and I start up crowdsec with the newest config that @2Wanderer posted, everything is ok. When I reboot, NPM no longer will come up, citing an error binding to port :80 and :443 due to the crowdsec nginx bouncer using port :80 or :443. I am playing around trying to get things to mesh properly. Once I get that part stable I will start trying to integrated the logs structure.

baudneo avatar Nov 30 '21 19:11 baudneo

I tried creating a docker container extending the npm container and installing crowdsec-nginx-bouncer. It didn't work. Turns out npm doesn't use nginx but openresty, wghich we don't (yet) support. But it's on the roadmap. So I guess it'a a bit of a PITA to get working before then.

klausagnoletti avatar Dec 01 '21 09:12 klausagnoletti

Can you give a rough estimation when this will probably happen?

leon1995 avatar Dec 14 '21 12:12 leon1995

No, it is not scheduled. Maybe the community will contribute it. It's open source after all :-)

klausagnoletti avatar Dec 14 '21 15:12 klausagnoletti

I already tried it with a custom dockerfile:

FROM jc21/nginx-proxy-manager:latest

RUN curl -s https://packagecloud.io/install/repositories/crowdsec/crowdsec/script.deb.sh | bash
RUN apt install -y crowdsec crowdsec-nginx-bouncer
RUN sed -i '1s/^/filenames:\n - \/data\/logs\/*.log\nlabels:\n  type:nginx/' /etc/crowdsec/acquis.yaml

but I get some weird errors. here are some of these:

Unpacking crowdsec-nginx-bouncer (0.0.7) ...
Setting up lua-logging (1.3.0-1) ...
Setting up libxpm4:amd64 (1:3.5.12-1) ...
Setting up nginx-common (1.14.2-2+deb10u4) ...

Configuration file '/etc/nginx/mime.types'
 ==> File on system created by you or by a script.
 ==> File also in package provided by package maintainer.
   What would you like to do about it ?  Your options are:
    Y or I  : install the package maintainer's version
    N or O  : keep your currently-installed version
      D     : show the differences between the versions
      Z     : start a shell to examine the situation
 The default action is to keep your current version.
*** mime.types (Y/I/N/O/D/Z) [default=N] ? dpkg: error processing package nginx-common (--configure):
 end of file on stdin at conffile prompt
Setting up lua-socket:amd64 (3.0~rc1+git+ac3201d-4) ...
dpkg: dependency problems prevent configuration of nginx-full:
 nginx-full depends on nginx-common (= 1.14.2-2+deb10u4); however:
  Package nginx-common is not configured yet.

dpkg: error processing package nginx-full (--configure):
 dependency problems - leaving unconfigured
Setting up libjbig0:amd64 (2.1-3.1+b2) ...
Setting up libicu63:amd64 (63.1-6+deb10u2) ...
Setting up lua-sql-sqlite3:amd64 (2.3.4-1+b1) ...
dpkg: dependency problems prevent configuration of libnginx-mod-http-xslt-filter:
 libnginx-mod-http-xslt-filter depends on nginx-common (= 1.14.2-2+deb10u4); however:
  Package nginx-common is not configured yet.

dpkg: error processing package libnginx-mod-http-xslt-filter (--configure):
 dependency problems - leaving unconfigured
Setting up libjpeg62-turbo:amd64 (1:1.5.2-2+deb10u1) ...
dpkg: dependency problems prevent configuration of libnginx-mod-http-auth-pam:
 libnginx-mod-http-auth-pam depends on nginx-common (= 1.14.2-2+deb10u4); however:
  Package nginx-common is not configured yet.

dpkg: error processing package libnginx-mod-http-auth-pam (--configure):
 dependency problems - leaving unconfigured
dpkg: dependency problems prevent configuration of libnginx-mod-http-geoip:
 libnginx-mod-http-geoip depends on nginx-common (= 1.14.2-2+deb10u4); however:
  Package nginx-common is not configured yet.

dpkg: error processing package libnginx-mod-http-geoip (--configure):
 dependency problems - leaving unconfigured
dpkg: dependency problems prevent configuration of libnginx-mod-http-ndk:
 libnginx-mod-http-ndk depends on nginx-common (= 1.14.2-2+deb10u4); however:
  Package nginx-common is not configured yet.

maybe you can help? or is this the error you mentioned, that not the real nginx but openresty is used?

leon1995 avatar Dec 14 '21 15:12 leon1995

This is the error I mentioned. Openresty != nginx (and they're not compatible). So the .deb complains that dependencies are not installed. So it won't work, unfortunately.

klausagnoletti avatar Dec 14 '21 15:12 klausagnoletti

Anyways I have good news @leon1995. I asked the developers just to be sure. And it turns out they're working on it as we speak. Only a new bouncer is needed as logfiles are the same, apparently. I'll ping you here once it's out in some usable shape or form. Are you willing to do a beta test?

klausagnoletti avatar Dec 14 '21 16:12 klausagnoletti

@klausagnoletti I'm running on unRaid with NPM and willing to beta test if you need more people. I have to be honest: I have a pretty private server, so there won't be many visitors. I can imagine you'd rather have a beta tester with some spicey logs.

sanderdatema avatar Dec 14 '21 16:12 sanderdatema

I can imagine you'd rather have a beta tester with some spicey logs.

Not gonna lie: That would be more interesting. But it won't prevent you to join the fun :-)

klausagnoletti avatar Dec 14 '21 16:12 klausagnoletti

@klausagnoletti I would also join the beta. However, mine is also a private server with multiple services and just a few people using it (maybe up to ten I think)

leon1995 avatar Dec 14 '21 16:12 leon1995

So... @leon1995 and I will visit each other's servers like crazy til steam's coming out of our logs. Will that work for you, @klausagnoletti? 🤪

sanderdatema avatar Dec 14 '21 16:12 sanderdatema

Sure, hit me up at klaus (at) crowdsec (dot) net. You'd have to do a Docker container on your own (but would be happy to help :-)

klausagnoletti avatar Dec 15 '21 07:12 klausagnoletti

I sent you an email

leon1995 avatar Dec 15 '21 09:12 leon1995

I can help testing if you wish. I have a host with Dietpi for x86, several dockers containers, one with Nginx proxy manager, other with crowdsec with the logs from Nginx proxy manager logs mapped, and also the firewall bouncer installed on the host and connected to Crowdsec's docker container. I have installed Crowdsec last week, so my knowledge about it is very limited.

dhernan3 avatar Dec 28 '21 08:12 dhernan3

I can help testing if you wish. I have a host with Dietpi for x86, several dockers containers, one with Nginx proxy manager, other with crowdsec with the logs from Nginx proxy manager logs mapped, and also the firewall bouncer installed on the host and connected to Crowdsec's docker container. I have installed Crowdsec last week, so my knowledge about it is very limited.

Cool, please send me an email so I have your information in my inbox :-)

klausagnoletti avatar Dec 30 '21 21:12 klausagnoletti

Now there's interesting news! @dhernan3 @leon1995 @sanderdatema @baudneo @2Wanderer @nisargjoshi95 @Sparkxxx

https://docs.crowdsec.net/docs/bouncers/openresty/

The bouncer is out. It should be easy to extend the existing npm Dockerfile with that since it's available as a .deb and npm is based on Debian. For log parsing and scenarios the normal nginx collection can be used. Contrary to my former believe, the log format is indeed the same. Find it here: https://hub.crowdsec.net/author/crowdsecurity/collections/nginx

Let me know what comes out of experimenting with it :-)

klausagnoletti avatar Jan 03 '22 14:01 klausagnoletti

Would be great if anyone can get this working and write some quick instructions :)

  • I might give it at go myself when I have the time.

Revorge avatar Jan 05 '22 08:01 Revorge