Jul 22 - Update protect admin page with fail2ban
This commit is contained in:
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user