Fail2ban Rules for Foundry VTT
Leave a comment if you like, hate, or find something confusing. This guide covers the steps required to create your own fail2ban jails, using foundryvtt as an example.
*Warning I take some playful liberty at the start of this post.
Welcome fellow nerds, geeks, otaku, or whatever you smartypants call yourselves. I'm assuming you might fit one of the following categories probably because you either know what Fail2ban is you nerd, or you know what FoundryVTT is you DnD tabletop (but on computer) roleplaying geek. Now that i've gotten the tongue in cheek (insults/compliments) aside I have a confession to make. I know what both of those things are so does that make me like a Generked? Okay I just mixed the two words together, that might be good for a riddle or puzzle in some future game. Anyways enough blabbing, you are probably here for the technical content anyways.
Everything that i'm writing is assuming you use an Ubuntu/Debian based Linux distribution. Most Linux distros are pretty similar, if needed adapt as needed. This also won't work if you use a reverse proxy, there are extra steps to get it to work. (There are multiple ways to do it. Easiest is send your log to the reverse proxy. Which may or may not really be the best, most-est, secure-est way to do things....don't look here...nope...).
This was written primarily for FoundryVTT version 10, but the steps are mostly the same for recent versions. In FoundryVTT 12 there have been some changes to how the logs are named that you'll need to adjust. It appears they attach a timestamp, and I haven't used that version enough yet to observe how they rotate the logs. Use file globbing (Not sure why I didn't think of this sooner). I'm guessing the easiest way to deal with this is to write a script & cron job to make a symbolic link to whatever the most recent log is. (I might look into this and make a write-up later) I haven't tested the REGEX on older or newer versions of FoundryVTT, you might need to adjust to your current version.
To start i'm assuming you know that Fail2ban is software that you install on a Linux computer that blocks repeated bad network connections. I'm also assuming you have a basic knowledge of using a Linux shell. If you don't take a look at this post https://blog.iterlyze.com/2020/10/i-recently-made-quick-draft-of-useful.html
I'm not assuming that you know that you might need to configure fail2ban. I'm also assuming you play games in FoundryVTT. I'm not assuming you know there is a nice debug.log file in the data directory e.g. something like /path/foundryuserdata/Logs/debug.log. There is a bunch of stuff that shows up in that log, but I noticed two particular log entries that show up for invalid passwords that might be good to have fail2ban watch. One is for invalid administrator login, the other for users when a world in foundry is active. Lets take a look:
It has an IP address, and what looks to be a time stamp. So lets see if we can setup fail2ban to filter out naughty trolls, and bots for password spraying.
Step 1) Install Fail2Ban
Use your distribution's package manager to install fail2ban. You'll notice I used a semicolon to run both commands one after the other. This way I don't have to wait for one to finish before the next begins. "Sudo" runs the commands as the root account (or administrator). The -y option automatically says yes to any questions asked about if you really want to install stuff.sudo apt update; sudo apt install -y fail2ban
Step 1.b) Install your firewall if it's missing and only if its missing/not working
(If its not working I suggest nftables. There are alternatives.)sudo apt install -y nftables
#!/usr/sbin/nft -f flush ruleset table inet filter { chain input { type filter hook input priority 2; policy accept; ct state established, related counter accept ct state invalid counter drop iif lo counter accept ct state new tcp dport 22 counter accept ct state new tcp dport 80 counter accept ct state new tcp dport 443 counter accept ct state new tcp dport 30000 counter accept counter drop } chain forward { type filter hook forward priority filter; policy drop; } chain output { type filter hook output priority filter; policy accept; } }
Step 2) Create local configs
The default configs you don't want to mess with since they will likely be wiped out if fail2ban is updated. The local configs take precedence over the default ones. Many online guides have you copy these configs. They are wrong. Do Not Copy The Configs. If a default is updated....arguably to be better if you copied an old config you are going to get either an error, or the old and "bad" config. It might be alright to copy if you delete everything that you don't change...which is more work...so don't do it.There are three locations with config files of note. The first two seem to allow you to define many of the same settings. First is /etc/fail2ban/jail.conf which I use to define my settings. Second is /etc/fail2ban/jail.d/defaults-*.conf which I use to enable or disable the various jails (a jail is a filter on a logfile to watch and take actions on like banning bots). The last is /etc/fail2ban/filter.d/filtername.conf which defines the regular expression to watch for (no need to make a local config for that last location).
sudo touch /etc/fail2ban/jail.local; sudo touch /etc/fail2ban/jail.d/local.conf
Step 3) Set your settings
I highly recommend taking a look at the default files.In jail.local add the following (e.g. sudo nano jail.local)
[DEFAULT] findtime = 2h maxretry = 5 bantime.increment = true bantime.rndtime = 512 banaction_allports = nftables-allports banaction = nftables-allports [foundryvtt] findtime = 3m maxretry = 3 bantime = 59m port = 30000 logpath = /home/foundry/foundryuserdata/Logs/debug.log backend = polling
In jail.d/local.conf add the following (e.g. sudo nano jail.local)
[foundryvtt] enabled = true
The name in rectangular brackets [foundryvtt] should be the same name as your filter config file in e.g. /etc/fail2ban/filter.d/foundryvtt.conf
findtime - The time period in which to count detected log entries (e.g. invalid password hits) The number here is counted in seconds, but m changes it to minutes. (Just a guess but h might be hours, d might be day)
maxretry - The number of times a log entry is allowed within a findtime (e.g. 5 invalid password attempts)
bantime - How long the abuser is banned in seconds. As above m changes it to minutes.
port - The port you are taking action on. Since 30000 is the default for foundry we use it.
logpath - The location of your foundry data directory, then Logs/debug.log
backend - It's not a system log, so fail2ban has a algorithm for detecting log changes. Use polling.
enabled - Do you want to turn on this specific jail or not.
banaction_allports or banaction - In the settings under the default we are just assuming if a repeated connection should be banned, we want to completely block them, thus setting this setting to nftables-allports . If you need a scalpel to block one port you can by setting it to nftables. If you want to block several specific ports you will need to write your own custom banactions, which is beyond what this guide is intended for. Note, it's set to the firewall that is used above, if you use a different firewall you'll want to use it's equivalent, you can look and see what is provided in the /etc/fail2ban/action.d/ folder.
As a side note many distributions include many other jails you can enable and use. I suggest taking a look at the Apache or Nginx ones, if you use either webserver.
Step 4) Create a regular expression to detect log entries.
I'm not any particular expert on regex (regular expressions). There is probably a better, more precise, shorter regular expression that you could use. This however worked for me. I'm including a screenshot. Have fun typing that out correctly. muhahahaha (I'll copy and paste it if I ever get around to it)#
#Catch multiple invalid logins and ban
#
[Definition]
failregex = ^\{\"ip\":\"<HOST>\",\"level\":\"warn\",\"message\":\"((Administrator authentication failed for session [a-zA-Z0-9]{24}; invalid password)|(User authentication failed for user [a-zA-Z0-9]{1,50}; invalid password\",\"session\":\"[a-zA-Z0-9]{24}))\",\"status\":40[13],\"timestamp\":\"\"}$
Step 5) Test the Regex
It's especially helpful to test the Regex to make sure it's working. A few notes, don't test from an ip that might lock you out from your system. Generate some bad logins to detect by going to foundry and trying to login with bad passwords. After saving you might want to restart fail2ban. In fact you can just reboot honestly. The fail2ban provides a nifty utility to test your filters with.
sudo /etc/init.d/fail2ban stop
sudo /etc/init.d/fail2ban start
#Excessive command reboot anyways
sudo shutdown -r now ; sudo reboot
Now run the following command to test your filters./etc/fail2ban/filter.d/
(Use your own path to log and path to jail. See above at the very top if you need more hints)
fail2ban-regex /path/to/log /etc/fail2ban/filter.d/foundryvtt.conf
The output can be a little confusing to read honestly. You are looking for something like.....this
Step 6) Troubleshooting
With this step good luck. Here are a few things that you can use. Also read the documentation.
/var/log/fail2ban.log
sudo fail2ban-client status foundryvtt
sudo systemctl status fail2ban
If you run into an error about ssh and fail2ban won't start. " ERROR Failed during configuration: Have not found any log file for sshd jail "
Additional resource links:
Optimising your Fail2Ban filters < System | The Art of Web
How fail2ban works · fail2ban/fail2ban Wiki · GitHub
Installation Guide | Foundry Virtual Tabletop
Recommended Linux Installation Guide | Foundry VTT Community Wiki
TLDR:
sudo apt update
sudo apt install -y fail2ban ufw
sudo nano/etc/fail2ban/jail.local
[foundryvtt] findtime = 3m maxretry = 3 bantime = 59m port = 30000 logpath = /home/foundry/foundryuserdata/Logs/debug.log backend = polling
sudo nano /etc/fail2ban/jail.d/local.conf
[foundryvtt] enabled = true
sudo nano /etc/fail2ban/filter.d/foundryvtt.conf
# #Catch multiple invalid logins and ban # [Definition] failregex = ^\{\"ip\":\"<HOST>\",\"level\":\"warn\",\"message\":\"((Administrator authentication failed for session [a-zA-Z0-9]{24}; invalid password)|(User authentication failed for user [a-zA-Z0-9]{1,50}; invalid password\",\"session\":\"[a-zA-Z0-9]{24}))\",\"status\":40[13],\"timestamp\":\"\"}$
sudo reboot
Hi there! At first thank you very much, after some error-prone tries with perplexity I found your blog. The regex pattern worked in an instant (So thank you for that) - but then stopped working. However this is reproducible:
ReplyDelete1. systemctl restart fail2ban.service
2. open foundry
3. do bad login attempts (the login attempt gets recognized)
4. correct login and logout (errors)
5. bad login attempts (errors)
The error is:
Failed to process line: '{"level":"info","message":"Administrator authentication successful for session 4ad95968fe6f4a171c6730f8","timestamp":"2024-12-07 21:44:30"}', caught exception:
[...]
IndexError: string index out of range
I can reproduce the error at the fail2ban-regex tool fail2ban-regex foundrydata/Logs/debug.2024-12-07.log /etc/fail2ban/filter.d/foundry.conf
However when I do it manually, it works: fail2ban-regex '{"level":"info","message":"Administrator authentication successful for session 4ad95968fe6f4a171c6730f8","timestamp":"2024-12-07 21:44:30"}' /etc/fail2ban/filter.d/foundry.conf -> Lines: 1 lines, 0 ignored, 0 matched, 1 missed
Do you have any ideas on this? Didn't you encounter the same issues? Does your setup still work?
I know we use different Foundry Versions, I am working with Ubuntu 22.04, fail2ban 0.11.2 and Foundry 12. But Still, this is so strange ...
Best regards
T
Actually sleeping a night over this solved it. Apparently this bug was fixed but the apt in Ubuntu is far behind the current version. So updating it manually solved my problem. Still hoping you instance is also running fine!
DeleteThanks again.
No problems on my setup so far. It's pretty frustrating running into issues like that isn't it?
Delete