Add fail2ban to management interface

This commit is contained in:
Michael Kroes 2016-03-23 12:29:12 +01:00
parent 65add24e2a
commit 7d4d9915ec
4 changed files with 45 additions and 1 deletions

View File

@ -24,6 +24,15 @@ filter = dovecotimap
findtime = 30 findtime = 30
maxretry = 20 maxretry = 20
[management-daemon]
enabled = true
filter = miab-management-daemon
port = http,https
logpath = /var/log/mailinabox.log
maxretry = 20
findtime = 30
[recidive] [recidive]
enabled = true enabled = true
maxretry = 10 maxretry = 10

View File

@ -0,0 +1,12 @@
# Fail2Ban filter Mail-in-a-Box management daemon
[INCLUDES]
before = common.conf
[Definition]
_daemon = mailinabox
failregex = Failed login from ip <HOST>
ignoreregex =

View File

@ -1,6 +1,6 @@
#!/usr/bin/python3 #!/usr/bin/python3
import os, os.path, re, json import os, os.path, re, json, logging, logging.handlers
from functools import wraps from functools import wraps
@ -32,6 +32,19 @@ with open(os.path.join(os.path.dirname(me), "csr_country_codes.tsv")) as f:
app = Flask(__name__, template_folder=os.path.abspath(os.path.join(os.path.dirname(me), "templates"))) app = Flask(__name__, template_folder=os.path.abspath(os.path.join(os.path.dirname(me), "templates")))
# Initialize the logger
#
# The logger wil automatically rotate the log if it gets to big, it will keep 3 old log files
# The log will contain timestap-level-message
logger = logging.getLogger('mailinabox')
fh = logging.handlers.RotatingFileHandler("/var/log/mailinabox.log", maxBytes=10240, backupCount=3)
fh.setFormatter(logging.Formatter('%(asctime)s %(levelname)-8s %(message)s'))
logger.addHandler(fh)
logger.setLevel(logging.INFO)
# Log a line that the daemon was started
logger.info("Management daemon started")
# Decorator to protect views that require a user with 'admin' privileges. # Decorator to protect views that require a user with 'admin' privileges.
def authorized_personnel_only(viewfunc): def authorized_personnel_only(viewfunc):
@wraps(viewfunc) @wraps(viewfunc)
@ -45,6 +58,9 @@ def authorized_personnel_only(viewfunc):
privs = [] privs = []
error = str(e) error = str(e)
# Write a line in the log recording the failed login
log_failed_login(request)
# Authorized to access an API view? # Authorized to access an API view?
if "admin" in privs: if "admin" in privs:
# Call view func. # Call view func.
@ -117,6 +133,9 @@ def me():
try: try:
email, privs = auth_service.authenticate(request, env) email, privs = auth_service.authenticate(request, env)
except ValueError as e: except ValueError as e:
# Log the failed login
log_failed_login(request)
return json_response({ return json_response({
"status": "invalid", "status": "invalid",
"reason": str(e), "reason": str(e),
@ -504,6 +523,9 @@ def munin(filename=""):
if filename == "": filename = "index.html" if filename == "": filename = "index.html"
return send_from_directory("/var/cache/munin/www", filename) return send_from_directory("/var/cache/munin/www", filename)
def log_failed_login(request):
logger.warning("Failed login from ip %s" % (request.headers.getlist("X-Forwarded-For")[0]))
# APP # APP
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -232,5 +232,6 @@ cat conf/fail2ban/jail.local \
| sed "s/PUBLIC_IP/$PUBLIC_IP/g" \ | sed "s/PUBLIC_IP/$PUBLIC_IP/g" \
> /etc/fail2ban/jail.local > /etc/fail2ban/jail.local
cp conf/fail2ban/dovecotimap.conf /etc/fail2ban/filter.d/dovecotimap.conf cp conf/fail2ban/dovecotimap.conf /etc/fail2ban/filter.d/dovecotimap.conf
cp conf/fail2ban/miab-management-daemon.conf /etc/fail2ban/filter.d/miab-management-daemon.conf
restart_service fail2ban restart_service fail2ban