329 lines
9.5 KiB
Bash
329 lines
9.5 KiB
Bash
#!/bin/bash
|
|
# Package Verification Check Script for SAW
|
|
# Version: 1.0
|
|
# Date: 2026-04-02
|
|
#
|
|
# This script checks the package verification configuration and verifies
|
|
# that all installed packages are properly signed.
|
|
#
|
|
# Usage: sudo ./check-verification.sh
|
|
#
|
|
# SECURITY RATIONALE:
|
|
# Regular verification of all installed packages ensures:
|
|
# 1. No packages were tampered with after installation
|
|
# 2. No malicious packages were added
|
|
# 3. All packages are still properly signed
|
|
# 4. Any compromised packages are detected early
|
|
#
|
|
# This should be run regularly (weekly/monthly) as part of security
|
|
# monitoring and compliance verification.
|
|
#
|
|
# Reference: https://docs.fedoraproject.org/en-US/fedora-coreos/security-verification/
|
|
|
|
set -e
|
|
|
|
# Configuration
|
|
CA_KEY_PATH="/etc/pki/rpm-gpg/RPM-GPG-KEY-custom-ca"
|
|
CRL_FILE="/etc/pki/ca-trust/source/anchors/crl.pem"
|
|
LOG_FILE="/var/log/package-verification-check.log"
|
|
|
|
# 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 CA certificate
|
|
check_ca_certificate() {
|
|
echo -e "${CYAN}1. CA Certificate Check${NC}"
|
|
echo "=========================================="
|
|
|
|
if [ -f "$CA_KEY_PATH" ]; then
|
|
log_info "PASS: CA certificate installed"
|
|
echo " Path: $CA_KEY_PATH"
|
|
echo " Status: PRESENT"
|
|
|
|
# Show certificate details
|
|
openssl x509 -in "$CA_KEY_PATH" -noout -subject -issuer -dates 2>/dev/null | sed 's/^/ /'
|
|
else
|
|
log_error "FAIL: CA certificate not found"
|
|
echo " Path: $CA_KEY_PATH"
|
|
echo " Status: MISSING"
|
|
echo " Action: Copy CA certificate to $CA_KEY_PATH"
|
|
fi
|
|
|
|
echo ""
|
|
}
|
|
|
|
# Check DNF configuration
|
|
check_dnf_config() {
|
|
echo -e "${CYAN}2. DNF Configuration Check${NC}"
|
|
echo "=========================================="
|
|
|
|
if [ ! -f /etc/dnf/dnf.conf ]; then
|
|
log_error "FAIL: DNF configuration not found"
|
|
echo " Status: FILE NOT FOUND"
|
|
echo " Action: Create /etc/dnf/dnf.conf"
|
|
echo ""
|
|
return
|
|
fi
|
|
|
|
# Check gpgcheck
|
|
if grep -q "^gpgcheck=1" /etc/dnf/dnf.conf; then
|
|
log_info "PASS: Package GPG check enabled"
|
|
echo " Status: ENABLED"
|
|
else
|
|
log_error "FAIL: Package GPG check not enabled"
|
|
echo " Status: DISABLED"
|
|
echo " Action: Add 'gpgcheck=1' to /etc/dnf/dnf.conf"
|
|
fi
|
|
|
|
# Check repo_gpgcheck
|
|
if grep -q "^repo_gpgcheck=1" /etc/dnf/dnf.conf; then
|
|
log_info "PASS: Repository GPG check enabled"
|
|
echo " Status: ENABLED"
|
|
else
|
|
log_error "FAIL: Repository GPG check not enabled"
|
|
echo " Status: DISABLED"
|
|
echo " Action: Add 'repo_gpgcheck=1' to /etc/dnf/dnf.conf"
|
|
fi
|
|
|
|
echo ""
|
|
}
|
|
|
|
# Check RPM database
|
|
check_rpm_database() {
|
|
echo -e "${CYAN}3. RPM Database Check${NC}"
|
|
echo "=========================================="
|
|
|
|
# Check if CA key is imported
|
|
if rpm -q gpg-pubkey 2>/dev/null | grep -q "$(basename $CA_KEY_PATH)"; then
|
|
log_info "PASS: CA key imported into RPM database"
|
|
echo " Status: IMPORTED"
|
|
else
|
|
log_warning "WARNING: CA key not imported into RPM database"
|
|
echo " Status: NOT IMPORTED"
|
|
echo " Action: Run 'rpm --import $CA_KEY_PATH'"
|
|
fi
|
|
|
|
echo ""
|
|
}
|
|
|
|
# Check audit script
|
|
check_audit_script() {
|
|
echo -e "${CYAN}4. Audit Script Check${NC}"
|
|
echo "=========================================="
|
|
|
|
if [ -f /usr/local/bin/verify-package.sh ]; then
|
|
log_info "PASS: Package verification script exists"
|
|
echo " Path: /usr/local/bin/verify-package.sh"
|
|
echo " Status: PRESENT"
|
|
|
|
if [ -x /usr/local/bin/verify-package.sh ]; then
|
|
log_info "PASS: Script is executable"
|
|
echo " Status: EXECUTABLE"
|
|
else
|
|
log_warning "WARNING: Script is not executable"
|
|
echo " Status: NOT EXECUTABLE"
|
|
echo " Action: Run 'chmod +x /usr/local/bin/verify-package.sh'"
|
|
fi
|
|
else
|
|
log_warning "WARNING: Package verification script not found"
|
|
echo " Status: NOT FOUND"
|
|
echo " Action: Run the lockdown script to create the script"
|
|
fi
|
|
|
|
echo ""
|
|
}
|
|
|
|
# Check CRL file
|
|
check_crl() {
|
|
echo -e "${CYAN}5. CRL Check${NC}"
|
|
echo "=========================================="
|
|
|
|
if [ -f "$CRL_FILE" ]; then
|
|
log_info "PASS: CRL file exists"
|
|
echo " Path: $CRL_FILE"
|
|
echo " Size: $(du -h "$CRL_FILE" | cut -f1)"
|
|
|
|
# Check if CRL is valid
|
|
if openssl crl -in "$CRL_FILE" -noout 2>/dev/null; then
|
|
log_info "PASS: CRL is valid"
|
|
echo " Status: VALID"
|
|
|
|
# Show CRL dates
|
|
openssl crl -in "$CRL_FILE" -noout -text 2>/dev/null | grep -E "(Last Update|Next Update):" | sed 's/^/ /'
|
|
else
|
|
log_error "FAIL: CRL is invalid"
|
|
echo " Status: INVALID"
|
|
fi
|
|
else
|
|
log_warning "WARNING: CRL file not found"
|
|
echo " Path: $CRL_FILE"
|
|
echo " Status: NOT FOUND"
|
|
echo " Action: Run daily-crl-update.sh to download CRL"
|
|
fi
|
|
|
|
echo ""
|
|
}
|
|
|
|
# Check firewall rules
|
|
check_firewall() {
|
|
echo -e "${CYAN}6. 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 rules
|
|
echo " Active Zones:"
|
|
firewall-cmd --list-zones 2>/dev/null | sed 's/^/ /'
|
|
|
|
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 ""
|
|
}
|
|
|
|
# Check SELinux
|
|
check_selinux() {
|
|
echo -e "${CYAN}7. 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 enforcing"
|
|
echo " Status: ENFORCING"
|
|
else
|
|
log_warning "WARNING: SELinux is not enforcing"
|
|
echo " Status: $(echo "$selinux_status" | grep "Current mode" | awk '{print $3}')"
|
|
fi
|
|
|
|
echo ""
|
|
}
|
|
|
|
# Check auditd
|
|
check_auditd() {
|
|
echo -e "${CYAN}8. Auditd Check${NC}"
|
|
echo "=========================================="
|
|
|
|
if systemctl is-active auditd >/dev/null 2>&1; then
|
|
log_info "PASS: Auditd is running"
|
|
echo " Status: RUNNING"
|
|
else
|
|
log_warning "WARNING: Auditd is not running"
|
|
echo " Status: NOT RUNNING"
|
|
fi
|
|
|
|
echo ""
|
|
}
|
|
|
|
# Check for unsigned packages
|
|
check_unsigned_packages() {
|
|
echo -e "${CYAN}9. Unsigned Packages Check${NC}"
|
|
echo "=========================================="
|
|
|
|
local unsigned_count=0
|
|
local total_count=0
|
|
|
|
# Get list of installed packages
|
|
while IFS= read -r pkg; do
|
|
# Check if package has signature
|
|
if ! rpm -q "$pkg" --queryformat='%{SIGPGP:pgpsig}\n' 2>/dev/null | grep -q "0x"; then
|
|
log_warning "WARNING: Package has no signature: $pkg"
|
|
((unsigned_count++))
|
|
fi
|
|
((total_count++))
|
|
done < <(rpm -qa --queryformat='%{NAME}\n' 2>/dev/null | head -100)
|
|
|
|
echo " Total packages checked: $total_count"
|
|
echo " Unsigned packages found: $unsigned_count"
|
|
echo ""
|
|
}
|
|
|
|
# Generate summary
|
|
generate_summary() {
|
|
echo ""
|
|
echo "=========================================="
|
|
echo " Package Verification Summary"
|
|
echo " Date: $(date '+%Y-%m-%d %H:%M:%S')"
|
|
echo " Hostname: $(hostname)"
|
|
echo "=========================================="
|
|
echo ""
|
|
}
|
|
|
|
# Main execution
|
|
main() {
|
|
echo ""
|
|
echo "=========================================="
|
|
echo " Package Verification Check"
|
|
echo " Fedora Kinoite SAW"
|
|
echo " Version: 1.0"
|
|
echo "=========================================="
|
|
echo ""
|
|
|
|
check_root
|
|
check_ca_certificate
|
|
check_dnf_config
|
|
check_rpm_database
|
|
check_audit_script
|
|
check_crl
|
|
check_firewall
|
|
check_selinux
|
|
check_auditd
|
|
check_unsigned_packages
|
|
generate_summary
|
|
|
|
echo ""
|
|
echo "=========================================="
|
|
echo " Check 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 CA certificates secure"
|
|
echo "- Regularly update CRL"
|
|
echo ""
|
|
}
|
|
|
|
# Run main function
|
|
main "$@" |