Jul 22 - Update protect admin page with fail2ban

This commit is contained in:
2026-07-22 16:41:08 -04:00
parent ade7c5b33c
commit 8533cbe27c
9 changed files with 254 additions and 23 deletions
+35
View File
@@ -1,9 +1,13 @@
import logging
import os
from datetime import datetime
from logging.handlers import RotatingFileHandler
from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import CSRFProtect
from markupsafe import Markup
from werkzeug.middleware.proxy_fix import ProxyFix
from config import Config
@@ -75,11 +79,42 @@ def log_action(actor, action, entity, entity_id=None, detail=None):
db.session.commit()
def _configure_auth_logger(app):
"""A dedicated 'jqc.auth' logger writing one line per login attempt to a
file fail2ban watches. Kept separate from the app log so the filter regex
stays tight and rotation is self-contained (no logrotate needed)."""
log_path = app.config.get("AUTH_LOG_PATH") or os.path.join(
os.path.dirname(os.path.abspath(__file__)), "logs", "auth.log"
)
os.makedirs(os.path.dirname(log_path), exist_ok=True)
auth_log = logging.getLogger("jqc.auth")
auth_log.setLevel(logging.INFO)
auth_log.propagate = False
# Guard against duplicate handlers if create_app runs more than once.
if not any(isinstance(h, RotatingFileHandler) for h in auth_log.handlers):
handler = RotatingFileHandler(
log_path, maxBytes=1_000_000, backupCount=5, encoding="utf-8"
)
handler.setFormatter(
logging.Formatter("%(asctime)s %(name)s %(levelname)s %(message)s")
)
auth_log.addHandler(handler)
return auth_log
def create_app():
app = Flask(__name__)
app.config.from_object(Config)
# Behind nginx: trust ONE proxy hop so request.remote_addr / scheme reflect
# the real client (nginx sets X-Forwarded-For / -Proto). gunicorn binds
# 127.0.0.1 only, so these headers can't be spoofed from outside.
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1)
db.init_app(app)
csrf.init_app(app)
_configure_auth_logger(app)
# Deferred import avoids a circular import: admin.py imports the models and
# log_action defined above, which are ready by the time create_app() runs.