Jump to content

HOW TO: Fail2ban configuration using linux


cpeng

Recommended Posts

I wanted to share my fail2ban configuration for people that want to protect against a brute force attack. Fail2ban is a piece of software that will monitor log files for a authentication failures then ban the source ip address after so many attempts to protect against a brute force attack. I searched around for an tutorial or how to on how to implement this for emby and came up short, so I decided to give it a try and got it to work without much trouble at all. I wouldn't consider myself an expert and this is my first how to I have every written so if I made a mistake or I'm wrong let me know, and use my instructions at your own risk. 

 

USE AT YOUR OWN RISK

 

THIS PROBABLY WILL NOT WORK IF YOU ARE USING EMBY CONNECT

I'm not using emby connect because I think it has some security problems listed here https://emby.media/community/index.php?/topic/80497-log-out-security-hole/

 

 

You need to install fail2ban

 

For my setup with ubuntu 18.10 I used, (should be the same for debian but I haven't tested)

sudo apt install fail2ban

To get fail2ban working with emby there are two parts, filter and jail, they both have their directories (jail.d) (filter.d) in /etc/fail2ban/

 

cpeng@g5500:~$ cd /etc/fail2ban/
cpeng@g5500:/etc/fail2ban$ ls
action.d  fail2ban.conf  fail2ban.d  filter.d  jail.conf  jail.d  paths-arch.conf  paths-common.conf  paths-debian.conf  paths-opensuse.conf

The jail controls what happens with an authentication error and the filter tells how to read the log to find the error.

 

Create a filter:

cpeng@g5500:/etc/fail2ban$ sudo nano filter.d/emby.conf

/etc/fail2ban/filter.d/emby.conf

# Fail2Ban for emby
#
#


[Definition]


failregex = AUTH-ERROR: <HOST> - Invalid user or password entered
ignoreregex =

EDIT: New failregex proposed (below) by @@nayr to catch 401 errors and attempts to find valid user names

[Definition]
failregex = AUTH-ERROR: <HOST> - Invalid user
    HTTP Response 401 to <HOST>.

The failregex tells what the log line will have in it that designates a fail and "<HOST>" designated the actual ip address.

 

That error looked like this:

2019-12-24 11:12:00.326 Warn HttpServer: AUTH-ERROR: 10.9.162.31 - Invalid user or password entered.

So I assumed that AUTH-ERROR will be unique to login errors which is why I started the filter with that.

 

Next you have to create the jail in

cpeng@g5500:/etc/fail2ban$ sudo nano jail.d/emby.local

/etc/fail2ban/jail.d/emby.local

[emby]
enabled = true
filter = emby
logpath = /var/lib/emby/logs/embyserver.txt
port = 80,443

I use a reverse proxy that uses ports 80,443, but if you aren't doing that then you want to block the default ports 8096,8920

The logpath may vary from distribution, you can find yours in your dashboard under paths.

There are other options that you can add, my default ban time was 10 minutes and max number of retries was 5 which is default which seemed fine to me.

 

The last thing you need to do is reload fail2ban so it re reads the files.

sudo systemctl reload fail2ban

Then test by entering the wrong password into emby and confirm that it blocks you. Check out the fail2ban.log at /var/log/fail2ban.log

tail /var/log/fail2ban.log

For testing this command might also come in handy:

sudo fail2ban-client unban --all

Hope this is helpful. 

 

 

P.S.

 

I recently switched from plex to emby for the dvr service and so far I have been very impressed and happy with how it works. I got tired of all the bugs with plex, that would never get fixed, instead we got new "features" and new interfaces. The icing on the cake is how responsiveness the developers are on these forums.

 

 

 

Edited by cpeng
  • Like 2
Link to comment
Share on other sites

Thanks for this, did some testing and it needs tweaking slightly:

failregex = AUTH-ERROR: <HOST> - Invalid user

There is an inconsistency in the logging.. first message is with an invalid username, second message is with an invalid password for a valid username:

2020-01-03 22:28:18.789 Warn HttpServer: AUTH-ERROR: 192.168.4.20 - Invalid username or password entered.
2020-01-03 22:29:17.998 Warn HttpServer: AUTH-ERROR: 192.168.4.20 - Invalid user or password entered.

matching stoping at user will catch both variants.. your original config will not ban hammering of unknown usernames.. which does not provide the desired results.

 

I also put the embyserver logs on a shared resource since my reverse proxy and emby are in different containers, this way my proxy can enact the ban on its side. 

Edited by nayr
Link to comment
Share on other sites

Got another tweak after even further testing, the following filter will also pickup 401 Unauthorized Errors which is what you see in the logs trying to hit the Emby API's w/Invalid Credentials. 

 

Sample Log Entry:

2020-01-04 00:58:15.915 Info HttpServer: HTTP Response 401 to 192.168.4.13. Time: 2ms. http://192.168.4.15:8096/emby/ScheduledTasks/Running/9492d30c70f7f1bec3757c9d0a4feb45

401 Response from Emby API:

Access token is invalid or expired.

New Regex for Multiple Variants. 

[Definition]
failregex = AUTH-ERROR: <HOST> - Invalid user
	HTTP Response 401 to <HOST>.
Edited by nayr
Link to comment
Share on other sites

I'm using a reverse proxy so IDK if that message changes for built in https.. I cant test it, but regardless of http or https transport.. response 401 is a HTTP Response code and AFIK there's no such thing as a HTTPS response code, https specs fall back to http for that stuff.. https just adds a TLS/SSL transport around HTTP so I would not expect that message to change.. but as we can see, making assumptions about security can be a bad idea.

Edited by nayr
Link to comment
Share on other sites

[Definition]
failregex = AUTH-ERROR: <HOST> - Invalid user
	HTTP Response 401 to <HOST>.

 

@@nayr,

 

Thanks for this, I will add it to the OP.

Edited by cpeng
  • Like 1
Link to comment
Share on other sites

  • 4 weeks later...

Thanks for this!  I'm trying to set up fail2ban on my system but running into an issue.  My emby log lists 2 ips (see below) because of my reverse proxy I assume.  Fail2ban is banning the first IP but not the second so I can still access Emby despite the first being banned.  How would I set up my filter to catch this?

 

Log:

2020-02-02 13:44:47.571 Info UserManager: Authentication request for User has been denied.
2020-02-02 13:44:47.571 Warn HttpServer: AUTH-ERROR: XX.XX.XXX.XXX, XXX.XX.XX.XX - Invalid user or password entered.
2020-02-02 13:44:47.571 Error HttpServer: Invalid user or password entered.
2020-02-02 13:44:47.572 Info HttpServer: HTTP Response 401 to XX.XX.XXX.XXX, XXX.XX.XX.XX. Time: 26ms. 

 

Link to comment
Share on other sites

 

Thanks for this!  I'm trying to set up fail2ban on my system but running into an issue.  My emby log lists 2 ips (see below) because of my reverse proxy I assume.  Fail2ban is banning the first IP but not the second so I can still access Emby despite the first being banned.  How would I set up my filter to catch this?

 

Log:

2020-02-02 13:44:47.571 Info UserManager: Authentication request for User has been denied.
2020-02-02 13:44:47.571 Warn HttpServer: AUTH-ERROR: XX.XX.XXX.XXX, XXX.XX.XX.XX - Invalid user or password entered.
2020-02-02 13:44:47.571 Error HttpServer: Invalid user or password entered.
2020-02-02 13:44:47.572 Info HttpServer: HTTP Response 401 to XX.XX.XXX.XXX, XXX.XX.XX.XX. Time: 26ms. 

 

 

Honestly I don't know. I run a reverse proxy as well so maybe the easiest way to fix it is to get the logs to show 1 ip address. This is my nginx reverse proxy

 

server {
        #root /var/www/emby/html;


        # Add index.php to the list if you are using PHP
        #index index.html index.htm index.nginx-debian.html;


        server_name emby.mydomain.com;


        location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                #try_files $uri $uri/ =404;
                proxy_pass http://127.0.0.1:8096/;
                proxy_set_header Range $http_range;
                proxy_set_header If-Range $http_if_range;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header Host $host;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;


                #Next three lines allow websockets
                #proxy_http_version 1.1;


                #proxy_set_header Upgrade $http_upgrade;
                #proxy_set_header Connection "upgrade";
        }




    listen [::]:443 ssl ipv6only=on; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/emby.mydomain.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/emby.mydomain.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot






        add_header X-Xss-Protection "1; mode=block" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header Strict-Transport-Security "max-age=2592000; includeSubdomains" always;
        add_header X-Frame-Options "SAMEORIGIN" always;
        proxy_hide_header X-Powered-By;
        add_header 'Referrer-Policy' 'no-referrer';
        add_header Content-Security-Policy "frame-ancestors emby.mydomain.com;";


}




server {
    if ($host = emby.mydomain.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot




        listen 80 default_server;
        listen [::]:80 default_server;


        server_name emby.mydomain.com;
    return 404; # managed by Certbot




}
Link to comment
Share on other sites

Much appreciated!  I actually figured it out, it was because of Cloudlare which I use as my DNS.  Had to do some more tweaking but i got it to work.

Link to comment
Share on other sites

Keksebacker
Hi at all,

 

I am running emby within a LXC-container behind an apache2 reverse proxy (another LXC-container) and I have some issues to find the right configs for fail2ban.

 

 

Filter:



[INCLUDES]

before = common.conf

[Definition]

_daemon = emby-server

failregex = AUTH-ERROR: <HOST> - Invalid use
HTTP Response 401 to <HOST>.
ignoreregex =



jail.local



[emby]
enabled = true
port = 8096,443,80
protocol = tcp
filter = emby
maxretry = 3
findtime = 600
bantime = 43200
logpath = /var/lib/emby/logs/embyserver.txt
action = %(action_mwl)s


%(action_mwl)s



# ban & send an e-mail with whois report to the destemail.
action_mw = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
%(mta)s-whois[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"]


Banaction will be iptables-multiport

 

 

Fail2ban bans the right ip but emby is still available.

 

I had a similar problem with nextcloud which uses apache as a web server.

I followed the instructions at the following block and now it works but I have no idea how I have to modify the banaction to work properly with emby.


 

Could anybody help me?

Link to comment
Share on other sites

This is kinda how I'm setup, except its nginx reverse proxy.. 

 

What I did was create a shared mount point between my WebServer container and my Emby server that contains the log files then configured fail2ban to process the emby log files inside the WebServer container.. since your behind a proxy, you need to be implementing fail2ban on the proxy itself. 

 

There are other ways to do this also, there's an alternatives and addons to fail2ban for cloud environments where an attack on one host will result in bans across multiple hosts.. its a more complicated setup tho and my method of sharing the log files between hosts is a happy path with least effort... 

 

If you want to maintain security isolation between the containers, you should mount the log file as read only on your proxy container so the web exposed container has minimal rights/attack surfaces. 

Edited by nayr
  • Like 1
Link to comment
Share on other sites

  • 5 months later...
joelang6126
On 2/7/2020 at 4:09 PM, nayr said:

since your behind a proxy, you need to be implementing fail2ban on the proxy itself. 

How do you go about doing this?

Could you share your config files as I too am behind an nginx proxy trying to get fail2ban working with emby.

Link to comment
Share on other sites

joelang6126
On 2/3/2020 at 5:52 PM, gewbert said:

Much appreciated!  I actually figured it out, it was because of Cloudlare which I use as my DNS.  Had to do some more tweaking but i got it to work.

I too am behind cloudflare. I have fail2ban working however it bans the cloudflare IP instead of the real IP.

 

Any idea how I pass the real IP to emby? 

Link to comment
Share on other sites

mastrmind11
58 minutes ago, joelang6126 said:

How do you go about doing this?

Could you share your config files as I too am behind an nginx proxy trying to get fail2ban working with emby.

I believe its this part:

proxy_set_header Range $http_range;
		proxy_set_header If-Range $http_if_range;
		proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
Link to comment
Share on other sites

  • 3 weeks later...
joelang6126
On 8/5/2020 at 2:02 PM, mastrmind11 said:

I believe its this part:


proxy_set_header Range $http_range;
		proxy_set_header If-Range $http_if_range;
		proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

Adding that block reveals the correct IP to Emby now however fail2ban is actually failing to ban the IP even though it is detected and added to the ban list. Emby is still reachable.

If I remove this block and turn Cloudflare to DNS only fail2ban functions correctly. Clearly theres something not quite right with that block.

I'm at a loss to explain this. Any ideas guys?

Edited by joelang6126
Link to comment
Share on other sites

If your using cloudfare infront of your server you cant use fail2ban to blackhole these connections locally, because you'd have to do the blocking at cloudflare level.. locally all you can block is cloudfare as those IP's are not making any connections to you that could be blocked.

You need a fail2ban action that makes an API request to Cloudfare to add the IP to a block list.. that information is out there.

Edited by nayr
Link to comment
Share on other sites

  • 5 months later...
whiteowl3

I'd like to expand on this to cover the emby image traversal "problem", but I wanted to bounce some questions of you guys before I wasted too much time.
We want fail2ban to detect actors which attempt the primary image bruteforce described here:

The first question I have before I get started is: can regex do this?

The second question is: @Luke, would filtering this behavior be likely to ban good actors?  I realize it's a complex question, but, off the top of your head,  does this seem doable?  How likely is it that a good actor will request a massive incremental sequence of primary image resources?
Third question:  Does somebody smarter than me have a better approach to this?  Are there other ways we could determine that the traversal is occurring?  I think this is kinda the more important question because motivated baddies will obscure the iteration.  Would looking for a different pattern be more useful?

I really appreciate input on this before I zone in on code I don't fully comprehend.

Link to comment
Share on other sites

whiteowl3
2 minutes ago, Luke said:

Filter what behavior exactly?

This, and effectively similar behaviors:

http://{public domain}/emby/items/{increment number}/images/primary
Link to comment
Share on other sites

Just now, whiteowl3 said:

This, and effectively similar behaviors:


http://{public domain}/emby/items/{increment number}/images/primary

Yes that would cause a problem.

  • Sad 1
Link to comment
Share on other sites

  • 8 months later...
  • 2 weeks later...
On 10/31/2021 at 10:22 PM, mshaik said:

Finally I am able to ban Ip using fail2ban-docker, npm-docker and emby-docker.

 

1. Create a folder fail2ban and create the docker-compose.yml adding the following code:

```
version: "3.7"
services:
  fail2ban:
    image: crazymax/fail2ban:latest
    container_name: fail2ban_docker
    network_mode: "host"
    environment:
      - TZ=US/Eastern
      - F2B_LOG_TARGET=STDOUT
      - F2B_LOG_LEVEL=INFO
      - F2B_DB_PURGE_AGE=1d
    cap_add:
      - NET_ADMIN
      - NET_RAW
    volumes:
      - "path/to/storage/fail2ban/data:/data"
      - "path/to/storage/fail2ban/log/:/var/log/"
      - "path/to/storage/nginxproxymanager/AppData/data/logs:/log/npm/:ro"
      - "path/to/storage/emby/logs:/log/emby/:ro"
    restart: unless-stopped
```

2. In the fail2ban/data/ folder you created in your storage, create action.d, jail.d, filter.d folders and copy the files in the corresponding folder of git into them.

i.e jail.d will have npm-docker.local,emby.local, filter.d will have npm-docker.conf,emby.conf and filter.d will have docker-action.conf,emby-action.conf respectively .

 

Folder: fail2ban/data/jail.d

npm-docker.local

```

[npm-docker]
enabled = true
ignoreip = 127.0.0.1/8 192.168.1.0/24
logpath = /log/npm/default-host_*.log
          /log/npm/proxy-host-*.log
maxretry = 3
bantime  = 86400
findtime = 60
action = docker-action

```

emby.local

 

```

[emby]
enabled = true
logpath = /log/emby/embyserver.txt
ignoreip = 127.0.0.1/8 192.168.1.0/24 # your local IP subnets
maxretry = 3
bantime = 84600
findtime = 60
action = emby-docker-action

```

 

Folder: fail2ban/data/filter.d

emby.conf

```

[INCLUDES]

[Definition]

failregex = Response.4\d\d.to <HOST>.+ Time
           AUTH-ERROR: <HOST>.+-
 

```

 

npm-docker.conf

```

[INCLUDES]

[Definition]

failregex = ^<HOST>.+" (4\d\d|3\d\d) (\d\d\d|\d) .+$
            ^.+ 4\d\d \d\d\d - .+ \[Client <HOST>\] \[Length .+\] ".+" .+$

```

 

Folder: fail2ban/data/action.d

 

docker-action.conf

```

[Definition]

actionstart = iptables -N f2b-npm-docker
              iptables -A f2b-npm-docker -j RETURN
              iptables -I FORWARD -p tcp -m multiport --dports 0:65535 -j f2b-npm-docker

actionstop = iptables -D FORWARD -p tcp -m multiport --dports 0:65535 -j f2b-npm-docker
             iptables -F f2b-npm-docker
             iptables -X f2b-npm-docker

actioncheck = iptables -n -L FORWARD | grep -q 'f2b-npm-docker[ \t]'

actionban = iptables -I f2b-npm-docker -s <ip> -j DROP

actionunban = iptables -D f2b-npm-docker -s <ip> -j DROP

```

 

emby-action.conf

 

```

[Definition]

actionstart = iptables -N f2b-emby
              iptables -A f2b-emby-docker -j RETURN
              iptables -I FORWARD -p tcp -m multiport --dports 0:65535 -j f2b-emby

actionstop = iptables -D FORWARD -p tcp -m multiport --dports 0:65535 -j f2b-emby
             iptables -F f2b-emby
             iptables -X f2b-emby

actioncheck = iptables -n -L FORWARD | grep -q 'f2b-emby[ \t]'

actionban = iptables -I f2b-emby -s  <ip> -j DROP

actionunban = iptables -D f2b-emby -s <ip> -j DROP

```

 

 

 

 

 

3. Once these are set, run the docker compose and check if the container is up and running or not

 

 

Solution: It's setting custom action to ban and unban and also use Iptables forward from forward to f2b-npm-docker, f2b-emby which is more configuring up docker network, my docker containers are all in forward chain network, you can change FOWARD to DOCKER-USER or INPUT according to your docker-containers network.

 

I used following guides to finally come up with this:

https://github.com/jc21/nginx-proxy-manager/issues/39#issuecomment-907795521 - setup

https://www.the-lazy-dev.com/en/install-fail2ban-with-docker/ - iptable commands etc ..

 

Hope this helps some one like me who is trying to solve the issues they face with fail2ban and docker networks :)

 

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...