Jump to content
cpeng

HOW TO: Fail2ban configuration using linux

Recommended Posts

cpeng

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

Share this post


Link to post
Share on other sites
Luke

Hi, that's great, thanks for the info !

Share this post


Link to post
Share on other sites
Renodep

Thank you for this awesome tutorial!

Share this post


Link to post
Share on other sites
nayr
Posted (edited)

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

Share this post


Link to post
Share on other sites
nayr
Posted (edited)

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

Share this post


Link to post
Share on other sites
Prototyp

Hey.

 

If there is an api http response, what about https ?

Share this post


Link to post
Share on other sites
nayr
Posted (edited)

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

Share this post


Link to post
Share on other sites
sfatula

Thanks for reminding me I need to do this, love fail2ban

Share this post


Link to post
Share on other sites
cpeng
Posted (edited)
[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

Share this post


Link to post
Share on other sites
gewbert

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. 

 

Share this post


Link to post
Share on other sites
cpeng

 

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




}

Share this post


Link to post
Share on other sites
gewbert

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.

Share this post


Link to post
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?

Share this post


Link to post
Share on other sites
nayr

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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
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? 

Share this post


Link to post
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;

Share this post


Link to post
Share on other sites
joelang6126
Posted (edited)
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

Share this post


Link to post
Share on other sites
nayr
Posted (edited)

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

Share this post


Link to post
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...