33from ..monitor import HealthCheck , CheckResult
44
55class SecurityCheck (HealthCheck ):
6+ """Check security configuration including firewall and SSH settings."""
7+
68 def run (self ) -> CheckResult :
9+ """
10+ Run security checks for firewall status and SSH configuration.
11+
12+ Returns:
13+ CheckResult with security score based on detected issues.
14+ """
715 score = 100
816 issues = []
917 recommendations = []
1018
1119 # 1. Firewall (UFW) Check
12- ufw_active = False
13- try :
14- # Add timeout to prevent hanging (Fixes Reliability Issue)
15- res = subprocess .run (
16- ["systemctl" , "is-active" , "ufw" ],
17- capture_output = True ,
18- text = True ,
19- timeout = 5
20- )
21- # Fix: Use exact match to avoid matching "inactive" which contains "active"
22- if res .returncode == 0 and res .stdout .strip () == "active" :
23- ufw_active = True
24- except subprocess .TimeoutExpired :
25- pass # Command timed out, treat as inactive or unavailable
26- except FileNotFoundError :
27- pass # Environment without systemctl (e.g., Docker or non-systemd)
28- except Exception :
29- pass # Generic error protection
30-
20+ ufw_active , ufw_issue , ufw_rec = self ._check_firewall ()
3121 if not ufw_active :
32- score = 0 # Spec: 0 points if Firewall is inactive
33- issues .append ("Firewall Inactive" )
34- recommendations .append ("Enable UFW Firewall" )
22+ score = 0
23+ issues .append (ufw_issue )
24+ recommendations .append (ufw_rec )
3525
3626 # 2. SSH Root Login Check
37- try :
38- ssh_config = "/etc/ssh/sshd_config"
39- if os .path .exists (ssh_config ):
40- with open (ssh_config , 'r' ) as f :
41- for line in f :
42- line = line .strip ()
43- # Check for uncommented PermitRootLogin yes
44- if line .startswith ("PermitRootLogin" ) and "yes" in line .split ():
45- score -= 50
46- issues .append ("Root SSH Allowed" )
47- recommendations .append ("Disable SSH Root Login in sshd_config" )
48- break
49- except PermissionError :
50- pass # Cannot read config, skip check
51- except Exception :
52- pass # Generic error protection
27+ ssh_penalty , ssh_issue , ssh_rec = self ._check_ssh_root_login ()
28+ if ssh_penalty > 0 :
29+ score -= ssh_penalty
30+ issues .append (ssh_issue )
31+ recommendations .append (ssh_rec )
5332
5433 status = "OK"
5534 if score < 50 : status = "CRITICAL"
@@ -63,4 +42,35 @@ def run(self) -> CheckResult:
6342 details = ", " .join (issues ) if issues else "Secure" ,
6443 recommendation = ", " .join (recommendations ) if recommendations else None ,
6544 weight = 0.35
66- )
45+ )
46+
47+ def _check_firewall (self ):
48+ """Check if UFW is active."""
49+ try :
50+ res = subprocess .run (
51+ ["systemctl" , "is-active" , "ufw" ],
52+ capture_output = True ,
53+ text = True ,
54+ timeout = 10
55+ )
56+ if res .returncode == 0 and res .stdout .strip () == "active" :
57+ return True , None , None
58+ except (subprocess .TimeoutExpired , FileNotFoundError , Exception ):
59+ pass
60+
61+ return False , "Firewall Inactive" , "Enable UFW Firewall"
62+
63+ def _check_ssh_root_login (self ):
64+ """Check for PermitRootLogin yes in sshd_config."""
65+ try :
66+ ssh_config = "/etc/ssh/sshd_config"
67+ if os .path .exists (ssh_config ):
68+ with open (ssh_config , 'r' ) as f :
69+ for line in f :
70+ line = line .strip ()
71+ if line .startswith ("PermitRootLogin" ) and "yes" in line .split ():
72+ return 50 , "Root SSH Allowed" , "Disable SSH Root Login in sshd_config"
73+ except (PermissionError , Exception ):
74+ pass
75+
76+ return 0 , None , None
0 commit comments