SAW-Kinoite/scripts/security-audit.sh
2026-04-02 17:23:23 -05:00

609 lines
18 KiB
Bash

#!/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 "$@"