new changes
This commit is contained in:
78
YakPanel-server/backend/app/api/security.py
Normal file
78
YakPanel-server/backend/app/api/security.py
Normal file
@@ -0,0 +1,78 @@
|
||||
"""YakPanel - read-only security checklist (local server probes)."""
|
||||
import os
|
||||
import re
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
|
||||
from app.api.auth import get_current_user
|
||||
from app.models.user import User
|
||||
from app.core.utils import read_file, exec_shell_sync
|
||||
|
||||
router = APIRouter(prefix="/security", tags=["security"])
|
||||
|
||||
|
||||
@router.get("/checklist")
|
||||
async def security_checklist(current_user: User = Depends(get_current_user)):
|
||||
"""Non-destructive hints: SSH config, firewall helper, fail2ban. Not a full audit."""
|
||||
items: list[dict] = []
|
||||
sshd = "/etc/ssh/sshd_config"
|
||||
body = read_file(sshd) if os.path.isfile(sshd) else None
|
||||
if isinstance(body, str) and body:
|
||||
if re.search(r"^\s*PasswordAuthentication\s+no\s*$", body, re.MULTILINE | re.IGNORECASE):
|
||||
items.append({
|
||||
"id": "ssh_password_auth",
|
||||
"ok": True,
|
||||
"title": "SSH password auth",
|
||||
"detail": "PasswordAuthentication appears set to no (prefer key-based login).",
|
||||
})
|
||||
elif re.search(r"^\s*PasswordAuthentication\s+yes", body, re.MULTILINE | re.IGNORECASE):
|
||||
items.append({
|
||||
"id": "ssh_password_auth",
|
||||
"ok": False,
|
||||
"title": "SSH password auth",
|
||||
"detail": "PasswordAuthentication is yes — consider disabling and using SSH keys.",
|
||||
})
|
||||
else:
|
||||
items.append({
|
||||
"id": "ssh_password_auth",
|
||||
"ok": None,
|
||||
"title": "SSH password auth",
|
||||
"detail": "Could not find an explicit PasswordAuthentication line (defaults depend on distro).",
|
||||
})
|
||||
else:
|
||||
items.append({
|
||||
"id": "ssh_password_auth",
|
||||
"ok": None,
|
||||
"title": "SSH password auth",
|
||||
"detail": "/etc/ssh/sshd_config not readable from the panel process.",
|
||||
})
|
||||
|
||||
ufw_out, _ = exec_shell_sync("ufw status 2>/dev/null", timeout=5)
|
||||
ufw = ufw_out or ""
|
||||
if "Status: active" in ufw:
|
||||
items.append({"id": "ufw", "ok": True, "title": "UFW firewall", "detail": "UFW reports active."})
|
||||
elif "Status: inactive" in ufw:
|
||||
items.append({
|
||||
"id": "ufw",
|
||||
"ok": None,
|
||||
"title": "UFW firewall",
|
||||
"detail": "UFW installed but inactive — enable if this host is public.",
|
||||
})
|
||||
else:
|
||||
items.append({
|
||||
"id": "ufw",
|
||||
"ok": None,
|
||||
"title": "UFW firewall",
|
||||
"detail": "UFW not detected (OK if you use firewalld/iptables only).",
|
||||
})
|
||||
|
||||
f2_out, _ = exec_shell_sync("systemctl is-active fail2ban 2>/dev/null", timeout=5)
|
||||
f2_active = (f2_out or "").strip() == "active"
|
||||
items.append({
|
||||
"id": "fail2ban",
|
||||
"ok": f2_active,
|
||||
"title": "fail2ban",
|
||||
"detail": "fail2ban is active." if f2_active else "fail2ban not active (optional hardening).",
|
||||
})
|
||||
|
||||
return {"items": items, "disclaimer": "YakPanel reads local settings only; this is not a compliance scan."}
|
||||
Reference in New Issue
Block a user