#!/bin/bash # Security Audit Script for SAW # Version: 1.0 # Date: 2026-04-02 # # This script performs a comprehensive security audit of the Fedora Kinoite SAW system. # It checks all security controls and provides a detailed report of the system's # security posture. # # Usage: sudo ./security-audit.sh # # SECURITY RATIONALE: # Regular security audits are essential for: # 1. Verifying security controls are still in place # 2. Detecting unauthorized changes # 3. Identifying potential security issues # 4. Providing compliance documentation # 5. Tracking security posture over time # # This script should be run: # - Weekly for critical systems # - Monthly for standard systems # - After any system changes # - Before and after security updates # # Reference: NSA Linux Security Hardening Guide, CIS Fedora Benchmarks set -e # Configuration LOG_FILE="/var/log/security-audit.log" AUDIT_DATE=$(date '+%Y-%m-%d %H:%M:%S') AUDIT_REPORT="/var/log/security-audit-report-$(date +%Y%m%d).txt" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' # Print functions log_info() { local timestamp=$(date '+%Y-%m-%d %H:%M:%S') echo -e "${GREEN}[$timestamp]${NC} ${BLUE}[INFO]${NC} $1" | tee -a "$LOG_FILE" } log_warning() { local timestamp=$(date '+%Y-%m-%d %H:%M:%S') echo -e "${YELLOW}[$timestamp]${NC} ${YELLOW}[WARNING]${NC} $1" | tee -a "$LOG_FILE" } log_error() { local timestamp=$(date '+%Y-%m-%d %H:%M:%S') echo -e "${RED}[$timestamp]${NC} ${RED}[ERROR]${NC} $1" | tee -a "$LOG_FILE" } # Check if running as root check_root() { if [ "$EUID" -ne 0 ]; then log_error "This script must be run as root" exit 1 fi } # Check sudo access # # SECURITY RATIONALE: # Sudo access should be disabled in SAW because: # 1. Prevents privilege escalation attacks # 2. Reduces attack surface # 3. Enforces least privilege principle # 4. Makes lateral movement harder # 5. All admin operations should go through controlled workflows # # This check verifies: # - User is not in wheel group # - Root SSH login is disabled # - No sudo commands available check_sudo_access() { echo -e "${CYAN}1. Sudo Access Check${NC}" echo "==========================================" local user=$(whoami) # Check if user is in wheel group if id -nG "$user" | grep -q wheel; then log_error "FAIL: User '$user' is in wheel group" echo " Status: SUDO ENABLED (Security Risk)" return 1 else log_info "PASS: User '$user' is not in wheel group" echo " Status: SUDO DISABLED" fi # Check root SSH login if [ -f /etc/ssh/sshd_config ]; then if grep -q "^PermitRootLogin yes" /etc/ssh/sshd_config || \ grep -q "^#PermitRootLogin yes" /etc/ssh/sshd_config; then log_warning "WARNING: Root SSH login may be enabled" echo " Check: /etc/ssh/sshd_config" else log_info "PASS: Root SSH login is disabled" echo " Status: ROOT SSH DISABLED" fi fi echo "" return 0 } # Check SELinux # # SECURITY RATIONALE: # SELinux (Security-Enhanced Linux) provides: # 1. Mandatory Access Control (MAC) # 2. Protection against privilege escalation # 3. Application containment # 4. Fine-grained access control # 5. Defense in depth # # SELinux should be in enforcing mode to provide protection. check_selinux() { echo -e "${CYAN}2. SELinux Check${NC}" echo "==========================================" local selinux_status=$(sestatus 2>/dev/null || echo "SELinux not available") if echo "$selinux_status" | grep -q "Current mode: enforcing"; then log_info "PASS: SELinux is in enforcing mode" echo " Status: ENFORCING" echo " Mode: Mandatory Access Control active" else log_warning "WARNING: SELinux is not in enforcing mode" echo " Status: $(echo "$selinux_status" | grep "Current mode" | awk '{print $3}')" fi echo "" return 0 } # Check audit daemon # # SECURITY RATIONALE: # auditd (audit daemon) provides: # 1. Comprehensive system auditing # 2. Logging of security-relevant events # 3. Detection of unauthorized access # 4. Forensic capabilities # 5. Compliance with security standards # # auditd should be running to ensure security events are logged. check_auditd() { echo -e "${CYAN}3. Audit Daemon Check${NC}" echo "==========================================" if systemctl is-active auditd >/dev/null 2>&1; then log_info "PASS: Auditd is running" echo " Status: RUNNING" echo " Logging: All security events" else log_warning "WARNING: Auditd is not running" echo " Status: NOT RUNNING" fi echo "" return 0 } # Check firewall # # SECURITY RATIONALE: # The firewall provides: # 1. Network traffic filtering # 2. Egress filtering (outbound) # 3. Ingress filtering (inbound) # 4. Network segmentation # 5. Protection against network attacks # # The firewall should be: # - Active # - Configured with default deny # - Only allowing necessary traffic check_firewall() { echo -e "${CYAN}4. Firewall Check${NC}" echo "==========================================" if command -v firewall-cmd &> /dev/null; then if firewall-cmd --state 2>/dev/null | grep -q "running"; then log_info "PASS: Firewall is running" echo " Status: RUNNING" # Show active zones echo " Active Zones:" firewall-cmd --list-zones 2>/dev/null | sed 's/^/ /' # Show services echo " Active Services:" firewall-cmd --list-services 2>/dev/null | sed 's/^/ /' else log_warning "WARNING: Firewall is not running" echo " Status: NOT RUNNING" fi else log_warning "WARNING: Firewall command not found" echo " Status: COMMAND NOT FOUND" fi echo "" return 0 } # Check VPN # # SECURITY RATIONALE: # WireGuard VPN provides: # 1. Encrypted network traffic # 2. Protection against network eavesdropping # 3. Traffic routing through secure tunnel # 4. Kill-switch protection # 5. Centralized network control # # VPN should be: # - Active and connected # - Routing all traffic # - Using strong encryption check_vpn() { echo -e "${CYAN}5. VPN Check${NC}" echo "==========================================" if command -v wg &> /dev/null; then if wg show >/dev/null 2>&1; then log_info "PASS: WireGuard is active" echo " Status: ACTIVE" echo " Interface: $(wg show | grep 'interface:' | awk '{print $2}')" # Show peers echo " Peers:" wg show 2>/dev/null | grep 'peer:' | sed 's/^/ /' # Show allowed IPs echo " Allowed IPs:" wg show 2>/dev/null | grep 'allowed-ips:' | sed 's/^/ /' else log_warning "WARNING: WireGuard is not active" echo " Status: NOT ACTIVE" fi else log_warning "WARNING: WireGuard not installed" echo " Status: NOT INSTALLED" fi echo "" return 0 } # Check DNS configuration # # SECURITY RATIONALE: # DNS lockdown provides: # 1. Prevention of DNS leaks # 2. All DNS through VPN tunnel # 3. Protection against DNS tracking # 4. Centralized DNS logging # 5. Block malicious domains # # DNS should be: # - Configured to use VPN gateway only # - Not allowing external DNS # - Using secure DNS resolution check_dns() { echo -e "${CYAN}6. DNS Configuration Check${NC}" echo "==========================================" if [ -f /etc/resolv.conf ]; then local dns_servers=$(grep "^nameserver" /etc/resolv.conf | awk '{print $2}') if echo "$dns_servers" | grep -q "127.0.0.1"; then log_info "PASS: DNS configured to use local resolver" echo " Status: LOCAL DNS" echo " Servers: $dns_servers" elif echo "$dns_servers" | grep -q "10.0.0.1"; then log_info "PASS: DNS configured to use VPN gateway" echo " Status: VPN DNS" echo " Servers: $dns_servers" else log_warning "WARNING: DNS may not be properly configured" echo " Status: EXTERNAL DNS" echo " Servers: $dns_servers" fi else log_warning "WARNING: /etc/resolv.conf not found" echo " Status: FILE NOT FOUND" fi echo "" return 0 } # Check package verification # # SECURITY RATIONALE: # Package verification ensures: # 1. Only signed packages installed # 2. Package integrity maintained # 3. Authentic package source # 4. Protection against tampering # 5. Supply chain attack prevention # # Package verification should be: # - Enabled in DNF configuration # - CA key imported # - CRL checking enabled check_package_verification() { echo -e "${CYAN}7. Package Verification Check${NC}" echo "==========================================" # Check CA key if [ -f /etc/pki/rpm-gpg/RPM-GPG-KEY-custom-ca ]; then log_info "PASS: CA key installed" echo " Status: CA KEY PRESENT" else log_warning "WARNING: CA key not found" echo " Status: CA KEY MISSING" fi # Check DNF configuration if [ -f /etc/dnf/dnf.conf ]; then if grep -q "^gpgcheck=1" /etc/dnf/dnf.conf; then log_info "PASS: Package signature verification enabled" echo " Status: GPG CHECK ENABLED" else log_warning "WARNING: Package signature verification not enabled" echo " Status: GPG CHECK DISABLED" fi if grep -q "^repo_gpgcheck=1" /etc/dnf/dnf.conf; then log_info "PASS: Repository signature verification enabled" echo " Status: REPO GPG CHECK ENABLED" else log_warning "WARNING: Repository signature verification not enabled" echo " Status: REPO GPG CHECK DISABLED" fi else log_warning "WARNING: DNF configuration not found" echo " Status: FILE NOT FOUND" fi # Check audit script if [ -f /usr/local/bin/verify-package.sh ]; then log_info "PASS: Package verification script exists" echo " Status: SCRIPT PRESENT" else log_warning "WARNING: Package verification script not found" echo " Status: SCRIPT MISSING" fi echo "" return 0 } # Check kernel hardening # # SECURITY RATIONALE: # Kernel hardening provides: # 1. Protection against kernel exploits # 2. Memory layout randomization # 3. Protection against buffer overflows # 4. Control Flow Integrity # 5. Defense in depth # # Kernel hardening should include: # - ASLR enabled # - NX bit enabled # - Stack protection # - SELinux enabled check_kernel_hardening() { echo -e "${CYAN}8. Kernel Hardening Check${NC}" echo "==========================================" # Check ASLR if [ -f /proc/sys/kernel/randomize_va_space ]; then local aslr=$(cat /proc/sys/kernel/randomize_va_space) if [ "$aslr" = "2" ]; then log_info "PASS: ASLR enabled" echo " Status: FULL ASLR (Randomize everything)" elif [ "$aslr" = "1" ]; then log_info "PASS: ASLR enabled" echo " Status: BASIC ASLR (Standard)" else log_warning "WARNING: ASLR not enabled" echo " Status: ASLR DISABLED" fi fi # Check SELinux if command -v getenforce &> /dev/null; then if [ "$(getenforce)" = "Enforcing" ]; then log_info "PASS: SELinux enforcing" echo " Status: ENFORCING" else log_warning "WARNING: SELinux not enforcing" echo " Status: $(getenforce)" fi fi # Check for ExecShield if [ -f /proc/sys/kernel/exec-shield ]; then local execshield=$(cat /proc/sys/kernel/exec-shield) if [ "$execshield" = "1" ]; then log_info "PASS: ExecShield enabled" echo " Status: EXEC SHIELD ENABLED" fi fi echo "" return 0 } # Check for suspicious processes # # SECURITY RATIONALE: # Suspicious processes check provides: # 1. Detection of unauthorized processes # 2. Identification of potential malware # 3. Monitoring of system activity # 4. Early detection of compromise # # This check looks for: # - Unknown processes # - Processes running as root # - Suspicious network processes check_suspicious_processes() { echo -e "${CYAN}9. Suspicious Processes Check${NC}" echo "==========================================" # Check for processes running as root local root_processes=$(ps aux | grep "root" | wc -l) if [ "$root_processes" -gt 50 ]; then log_warning "WARNING: High number of root processes: $root_processes" echo " Status: $root_processes root processes running" else log_info "PASS: Reasonable number of root processes" echo " Status: $root_processes root processes running" fi # Check for suspicious processes local suspicious=$(ps aux | grep -E "(nc|netcat|nmap|hydra|metasploit)" | grep -v grep) if [ -n "$suspicious" ]; then log_error "FAIL: Suspicious processes detected!" echo " Status: SUSPICIOUS PROCESSES FOUND" echo "$suspicious" | sed 's/^/ /' else log_info "PASS: No suspicious processes detected" echo " Status: NO SUSPICIOUS PROCESSES" fi echo "" return 0 } # Check audit logs # # SECURITY RATIONALE: # Audit log review provides: # 1. Detection of security events # 2. Identification of unauthorized access # 3. Forensic information # 4. Compliance documentation # 5. Security incident response # # This check looks for: # - Failed sudo attempts # - Privilege escalation attempts # - File access to sensitive files # - System configuration changes check_audit_logs() { echo -e "${CYAN}10. Audit Log Check${NC}" echo "==========================================" # Check for failed sudo attempts if [ -f /var/log/secure ]; then local sudo_failures=$(grep "authentication failure" /var/log/secure 2>/dev/null | wc -l) if [ "$sudo_failures" -gt 0 ]; then log_warning "WARNING: Failed sudo attempts detected: $sudo_failures" echo " Status: $sudo_failures failed sudo attempts" echo " Last 5 failures:" grep "authentication failure" /var/log/secure 2>/dev/null | tail -5 | sed 's/^/ /' else log_info "PASS: No failed sudo attempts" echo " Status: No failed sudo attempts" fi fi # Check auditd logs if command -v ausearch &> /dev/null; then local avc_denials=$(ausearch -m avc -ts recent 2>/dev/null | wc -l) if [ "$avc_denials" -gt 0 ]; then log_warning "WARNING: SELinux denials detected: $avc_denials" echo " Status: $avc_denials SELinux denials" else log_info "PASS: No SELinux denials" echo " Status: No SELinux denials" fi fi echo "" return 0 } # Check file permissions # # SECURITY RATIONALE: # File permissions check provides: # 1. Detection of overly permissive files # 2. Verification of sensitive file protection # 3. Identification of potential security issues # 4. Compliance with security standards # # This check looks for: # - World-writable files in critical directories # - Files with incorrect ownership # - SUID/SGID files check_file_permissions() { echo -e "${CYAN}11. File Permissions Check${NC}" echo "==========================================" # Check /etc permissions local etc_world_writable=$(find /etc -type f -perm -0002 2>/dev/null | wc -l) if [ "$etc_world_writable" -gt 0 ]; then log_warning "WARNING: World-writable files in /etc: $etc_world_writable" echo " Status: $etc_world_writable world-writable files" else log_info "PASS: No world-writable files in /etc" echo " Status: No world-writable files" fi # Check for SUID/SGID files local suid_files=$(find /usr -type f \( -perm -4000 -o -perm -2000 \) 2>/dev/null | wc -l) if [ "$suid_files" -gt 100 ]; then log_warning "WARNING: High number of SUID/SGID files: $suid_files" echo " Status: $suid_files SUID/SGID files" else log_info "PASS: Reasonable number of SUID/SGID files" echo " Status: $suid_files SUID/SGID files" fi echo "" return 0 } # Generate summary generate_summary() { echo "" echo "==========================================" echo " Security Audit Summary" echo "==========================================" echo "" echo "Date: $AUDIT_DATE" echo "Hostname: $(hostname)" echo "OS: $(cat /etc/os-release | grep PRETTY_NAME | cut -d'"' -f2)" echo "" } # Main execution main() { echo "" echo "==========================================" echo " Fedora Kinoite SAW Security Audit" echo " Version: 1.0" echo " Date: 2026-04-02" echo "==========================================" echo "" check_root # Run all checks check_sudo_access check_selinux check_auditd check_firewall check_vpn check_dns check_package_verification check_kernel_hardening check_suspicious_processes check_audit_logs check_file_permissions # Generate summary generate_summary echo "" echo "==========================================" echo " Audit Complete!" echo "==========================================" echo "" echo "Recommendations:" echo "- Review any WARNING or ERROR items" echo "- Run this script weekly for critical systems" echo "- Run this script monthly for standard systems" echo "- Keep audit logs secure" echo "- Test rollback capability regularly" echo "" } # Run main function main "$@"