Set up comprehensive intrusion detection by integrating OSSEC HIDS with fail2ban for automated threat response. This advanced configuration provides real-time monitoring, log analysis, and automated IP blocking for enhanced server security.
Prerequisites
- Root or sudo access
- Basic knowledge of Linux security concepts
- Understanding of log file formats
- Familiarity with iptables firewall rules
What this solves
This tutorial shows you how to integrate OSSEC Host-based Intrusion Detection System (HIDS) with fail2ban to create a comprehensive security monitoring solution. OSSEC monitors system logs and file integrity while fail2ban automatically blocks suspicious IP addresses, creating a layered defense against intrusions and automated attacks.
Step-by-step configuration
Update system packages
Start by updating your package manager to ensure you get the latest security updates.
sudo apt update && sudo apt upgrade -y
sudo dnf update -y
Install OSSEC dependencies
Install the required packages for building OSSEC from source and running the system.
sudo apt install -y build-essential gcc make unzip sendmail inotify-tools wget libevent-dev libssl-dev libz-dev
sudo dnf install -y gcc gcc-c++ make unzip sendmail inotify-tools wget libevent-devel openssl-devel zlib-devel
Download and install OSSEC
Download the latest OSSEC release and compile it for your system.
cd /tmp
wget https://github.com/ossec/ossec-hids/archive/v3.7.0.tar.gz
tar -xzf v3.7.0.tar.gz
cd ossec-hids-3.7.0
Configure OSSEC installation
Run the interactive installation script and select server installation for local monitoring.
sudo ./install.sh
When prompted, select these options:
- Installation type: local
- Email notification: y (enter your email)
- SMTP server: localhost
- Firewall response: y
- System integrity check: y
- Rootkit detection: y
- Active response: y
Install fail2ban
Install fail2ban which will handle the automatic IP blocking based on OSSEC alerts.
sudo apt install -y fail2ban
sudo dnf install -y epel-release
sudo dnf install -y fail2ban
Configure OSSEC for fail2ban integration
Modify OSSEC configuration to enable log output that fail2ban can parse.
Create custom OSSEC rules for fail2ban integration
Add custom rules to detect specific attack patterns and generate alerts that fail2ban can process.
Configure fail2ban jail for OSSEC
Create a custom jail configuration that monitors OSSEC alerts and blocks offending IPs.
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
banaction = iptables-multiport
protocol = tcp
chain = INPUT
action_ = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
action_mw = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
%(mta)s-whois[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"]
action_mwl = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
%(mta)s-whois-lines[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", chain="%(chain)s"]
action = %(action_)s
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
[apache-auth]
enabled = true
port = http,https
filter = apache-auth
logpath = /var/log/apache2/*error.log
maxretry = 6
bantime = 3600
[apache-badbots]
enabled = true
port = http,https
filter = apache-badbots
logpath = /var/log/apache2/*error.log
maxretry = 2
bantime = 86400
[apache-noscript]
enabled = true
port = http,https
filter = apache-noscript
logpath = /var/log/apache2/*error.log
maxretry = 6
bantime = 3600
[apache-overflows]
enabled = true
port = http,https
filter = apache-overflows
logpath = /var/log/apache2/*error.log
maxretry = 2
bantime = 3600
[ossec]
enabled = true
filter = ossec
logpath = /var/ossec/logs/alerts/alerts.log
maxretry = 1
bantime = 86400
port = all
protocol = all
banaction = iptables-allports
Create OSSEC filter for fail2ban
Create a custom filter that parses OSSEC alert logs to extract IP addresses for blocking.
[INCLUDES]
[Definition]
failregex = .*\[\d+\]\s+\(\d+\).*Src IP:
Configure OSSEC active response integration
Create a custom active response script that interfaces with fail2ban for coordinated blocking.
#!/bin/bash
# fail2ban-ban.sh - OSSEC active response script for fail2ban integration
# Author: Binadit Infrastructure Team
LOGFILE="/var/ossec/logs/active-responses.log"
FAIL2BAN_CLIENT="/usr/bin/fail2ban-client"
# Function to log messages
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - fail2ban-ban.sh: $1" >> $LOGFILE
}
# Read the action and IP from OSSEC
read ACTION
read USER
read IP
read ALERTID
read RULEID
read AGENT
read FILENAME
# Extract the IP address if it's in CIDR format
IP=$(echo $IP | cut -d'/' -f1)
# Validate IP address
if [[ ! $IP =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
log "Invalid IP address: $IP"
exit 1
fi
# Skip private IP addresses
if [[ $IP =~ ^10\. ]] || [[ $IP =~ ^172\.(1[6-9]|2[0-9]|3[0-1])\. ]] || [[ $IP =~ ^192\.168\. ]]; then
log "Skipping private IP: $IP"
exit 0
fi
case $ACTION in
add)
log "Banning IP $IP (Rule ID: $RULEID)"
# Ban the IP using fail2ban
$FAIL2BAN_CLIENT set ossec banip $IP
if [ $? -eq 0 ]; then
log "Successfully banned IP $IP"
else
log "Failed to ban IP $IP"
fi
;;
delete)
log "Unbanning IP $IP (Rule ID: $RULEID)"
# Unban the IP using fail2ban
$FAIL2BAN_CLIENT set ossec unbanip $IP
if [ $? -eq 0 ]; then
log "Successfully unbanned IP $IP"
else
log "Failed to unban IP $IP"
fi
;;
*)
log "Unknown action: $ACTION"
;;
esac
exit 0
Set permissions for active response script
Set proper permissions for the active response script so OSSEC can execute it.
sudo chmod 750 /var/ossec/active-response/bin/fail2ban-ban.sh
sudo chown root:ossec /var/ossec/active-response/bin/fail2ban-ban.sh
Add active response configuration to OSSEC
Configure OSSEC to use the custom active response script for high-level alerts.
Start and enable services
Enable and start both OSSEC and fail2ban services to begin monitoring.
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
sudo /var/ossec/bin/ossec-control start
sudo systemctl status fail2ban
Configure log monitoring integration
Set up centralized logging to ensure both systems can access and monitor the same log files effectively. This configuration was referenced in our centralized logging tutorial.
# OSSEC log integration
# Send OSSEC alerts to a separate log file
if $programname startswith 'ossec' then /var/log/ossec-alerts.log
& stop
# Ensure fail2ban can read OSSEC logs
$FileCreateMode 0644
$DirCreateMode 0755
Restart rsyslog service
Restart rsyslog to apply the new logging configuration.
sudo systemctl restart rsyslog
Configure automated threat response
Set up email notifications
Configure email alerts for both OSSEC and fail2ban to notify administrators of security events.
[Definition]
actionstart = printf %%b "Subject: [Fail2ban]
Create monitoring dashboard script
Create a script to monitor the status of both systems and generate periodic reports.
#!/bin/bash
# security-monitor.sh - Monitor OSSEC and fail2ban status
# Author: Binadit Infrastructure Team
LOGFILE="/var/log/security-monitor.log"
EMAIL="admin@example.com"
# Function to log messages
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a $LOGFILE
}
# Check OSSEC status
check_ossec() {
if pgrep -f "ossec-syscheckd" > /dev/null; then
log "OSSEC: Running"
# Get recent alerts count
RECENT_ALERTS=$(tail -n 100 /var/ossec/logs/alerts/alerts.log | grep "$(date '+%Y %b %d')" | wc -l)
log "OSSEC: $RECENT_ALERTS alerts today"
else
log "OSSEC: Not running - ALERT!"
echo "OSSEC service is down on $(hostname)" | mail -s "OSSEC Alert" $EMAIL
fi
}
# Check fail2ban status
check_fail2ban() {
if systemctl is-active --quiet fail2ban; then
log "Fail2ban: Running"
# Get banned IPs count
BANNED_IPS=$(/usr/bin/fail2ban-client status | grep "Currently banned" | awk '{print $4}')
log "Fail2ban: $BANNED_IPS IPs currently banned"
# List active jails
ACTIVE_JAILS=$(/usr/bin/fail2ban-client status | grep "Jail list" | cut -d: -f2 | xargs)
log "Fail2ban: Active jails: $ACTIVE_JAILS"
else
log "Fail2ban: Not running - ALERT!"
echo "Fail2ban service is down on $(hostname)" | mail -s "Fail2ban Alert" $EMAIL
fi
}
# Check disk space for logs
check_disk_space() {
DISK_USAGE=$(df /var/log | tail -1 | awk '{print $5}' | sed 's/%//')
if [ $DISK_USAGE -gt 80 ]; then
log "Disk space warning: /var/log is ${DISK_USAGE}% full"
echo "Log partition is ${DISK_USAGE}% full on $(hostname)" | mail -s "Disk SpaAutomated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Configuration
OSSEC_VERSION="3.7.0"
ADMIN_EMAIL="${1:-admin@example.com}"
SMTP_SERVER="${2:-localhost}"
# Usage
show_usage() {
echo "Usage: $0 [admin_email] [smtp_server]"
echo "Example: $0 admin@example.com localhost"
exit 1
}
# Logging functions
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# Cleanup on failure
cleanup() {
log_error "Installation failed. Cleaning up..."
systemctl stop ossec 2>/dev/null || true
systemctl stop fail2ban 2>/dev/null || true
rm -rf /tmp/ossec-hids-* 2>/dev/null || true
}
trap cleanup ERR
# Check prerequisites
check_prerequisites() {
if [[ $EUID -ne 0 ]]; then
log_error "This script must be run as root"
exit 1
fi
if [[ ! "$ADMIN_EMAIL" =~ ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$ ]]; then
log_error "Invalid email format"
show_usage
fi
}
# Detect distribution
detect_distro() {
if [[ ! -f /etc/os-release ]]; then
log_error "/etc/os-release not found. Cannot detect distribution."
exit 1
fi
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="apt update && apt upgrade -y"
PKG_INSTALL="apt install -y"
DEPS="build-essential gcc make unzip sendmail inotify-tools wget libevent-dev libssl-dev zlib1g-dev"
LOG_AUTH="/var/log/auth.log"
APACHE_ACCESS="/var/log/apache2/access.log"
APACHE_ERROR="/var/log/apache2/error.log"
;;
almalinux|rocky|centos|rhel|ol)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
DEPS="gcc gcc-c++ make unzip sendmail inotify-tools wget libevent-devel openssl-devel zlib-devel"
LOG_AUTH="/var/log/secure"
APACHE_ACCESS="/var/log/httpd/access_log"
APACHE_ERROR="/var/log/httpd/error_log"
# Enable EPEL for fail2ban
dnf install -y epel-release 2>/dev/null || true
;;
fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
DEPS="gcc gcc-c++ make unzip sendmail inotify-tools wget libevent-devel openssl-devel zlib-devel"
LOG_AUTH="/var/log/secure"
APACHE_ACCESS="/var/log/httpd/access_log"
APACHE_ERROR="/var/log/httpd/error_log"
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum update -y"
PKG_INSTALL="yum install -y"
DEPS="gcc gcc-c++ make unzip sendmail inotify-tools wget libevent-devel openssl-devel zlib-devel"
LOG_AUTH="/var/log/secure"
APACHE_ACCESS="/var/log/httpd/access_log"
APACHE_ERROR="/var/log/httpd/error_log"
amazon-linux-extras install epel -y 2>/dev/null || true
;;
*)
log_error "Unsupported distribution: $ID"
exit 1
;;
esac
log_info "Detected distribution: $PRETTY_NAME"
}
# Create OSSEC configuration
create_ossec_config() {
cat > /var/ossec/etc/ossec.conf << 'EOF'
<ossec_config>
<global>
<email_notification>yes</email_notification>
<smtp_server>SMTP_SERVER_PLACEHOLDER</smtp_server>
<email_from>ossec@example.com</email_from>
<email_to>ADMIN_EMAIL_PLACEHOLDER</email_to>
<logall>yes</logall>
<logall_json>no</logall_json>
</global>
<rules>
<include>rules_config.xml</include>
<include>pam_rules.xml</include>
<include>sshd_rules.xml</include>
<include>syslog_rules.xml</include>
<include>apache_rules.xml</include>
<include>web_rules.xml</include>
<include>web_appsec_rules.xml</include>
<include>mysql_rules.xml</include>
<include>postfix_rules.xml</include>
<include>firewall_rules.xml</include>
<include>attack_rules.xml</include>
<include>ossec_rules.xml</include>
<include>local_rules.xml</include>
</rules>
<syscheck>
<frequency>79200</frequency>
<directories check_all="yes">/etc,/usr/bin,/usr/sbin</directories>
<directories check_all="yes">/bin,/sbin,/boot</directories>
<ignore>/etc/mtab</ignore>
<ignore>/etc/hosts.deny</ignore>
<ignore>/etc/adjtime</ignore>
<ignore>/etc/random-seed</ignore>
</syscheck>
<rootcheck>
<rootkit_files>/var/ossec/etc/shared/rootkit_files.txt</rootkit_files>
<rootkit_trojans>/var/ossec/etc/shared/rootkit_trojans.txt</rootkit_trojans>
<system_audit>/var/ossec/etc/shared/system_audit_rcl.txt</system_audit>
<system_audit>/var/ossec/etc/shared/cis_debian_linux_rcl.txt</system_audit>
</rootcheck>
<localfile>
<log_format>syslog</log_format>
<location>/var/log/messages</location>
</localfile>
<localfile>
<log_format>syslog</log_format>
<location>LOG_AUTH_PLACEHOLDER</location>
</localfile>
<localfile>
<log_format>apache</log_format>
<location>APACHE_ACCESS_PLACEHOLDER</location>
</localfile>
<localfile>
<log_format>apache</log_format>
<location>APACHE_ERROR_PLACEHOLDER</location>
</localfile>
<active-response>
<disabled>no</disabled>
</active-response>
</ossec_config>
EOF
sed -i "s/SMTP_SERVER_PLACEHOLDER/$SMTP_SERVER/g" /var/ossec/etc/ossec.conf
sed -i "s/ADMIN_EMAIL_PLACEHOLDER/$ADMIN_EMAIL/g" /var/ossec/etc/ossec.conf
sed -i "s|LOG_AUTH_PLACEHOLDER|$LOG_AUTH|g" /var/ossec/etc/ossec.conf
sed -i "s|APACHE_ACCESS_PLACEHOLDER|$APACHE_ACCESS|g" /var/ossec/etc/ossec.conf
sed -i "s|APACHE_ERROR_PLACEHOLDER|$APACHE_ERROR|g" /var/ossec/etc/ossec.conf
chown root:ossec /var/ossec/etc/ossec.conf
chmod 644 /var/ossec/etc/ossec.conf
}
# Create fail2ban jail configuration
create_fail2ban_config() {
cat > /etc/fail2ban/jail.local << EOF
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 5
backend = auto
[sshd]
enabled = true
port = ssh
logpath = $LOG_AUTH
maxretry = 3
[ossec-ssh]
enabled = true
filter = ossec-ssh
logpath = /var/ossec/logs/alerts/alerts.log
maxretry = 1
bantime = 86400
[ossec-web]
enabled = true
filter = ossec-web
logpath = /var/ossec/logs/alerts/alerts.log
maxretry = 1
bantime = 86400
EOF
# Create OSSEC filters for fail2ban
mkdir -p /etc/fail2ban/filter.d
cat > /etc/fail2ban/filter.d/ossec-ssh.conf << 'EOF'
[Definition]
failregex = .*\s+<.*>\s+<.*>\s+<.*>\s+(authentication_failed|Invalid_user|Connection_closed|Multiple_authentication_failures).*Src IP: <HOST>
ignoreregex =
EOF
cat > /etc/fail2ban/filter.d/ossec-web.conf << 'EOF'
[Definition]
failregex = .*\s+<.*>\s+<.*>\s+<.*>\s+(Web_server_400_error|Web_server_403_error|Web_server_404_error|Multiple_web_server_400_errors).*Src IP: <HOST>
ignoreregex =
EOF
chmod 644 /etc/fail2ban/jail.local /etc/fail2ban/filter.d/ossec-*.conf
}
# Main installation
main() {
log_info "Starting OSSEC and fail2ban installation"
echo "[1/10] Checking prerequisites..."
check_prerequisites
echo "[2/10] Detecting distribution..."
detect_distro
echo "[3/10] Updating system packages..."
$PKG_UPDATE
echo "[4/10] Installing OSSEC dependencies..."
$PKG_INSTALL $DEPS
echo "[5/10] Downloading OSSEC..."
cd /tmp
wget -q "https://github.com/ossec/ossec-hids/archive/v${OSSEC_VERSION}.tar.gz"
tar -xzf "v${OSSEC_VERSION}.tar.gz"
cd "ossec-hids-${OSSEC_VERSION}"
echo "[6/10] Installing OSSEC..."
# Automated installation answers
echo -e "\nen\n\nlocal\n\ny\n$ADMIN_EMAIL\n$SMTP_SERVER\ny\ny\ny\ny\n\n" | ./install.sh
echo "[7/10] Configuring OSSEC..."
create_ossec_config
echo "[8/10] Installing fail2ban..."
$PKG_INSTALL fail2ban
echo "[9/10] Configuring fail2ban integration..."
create_fail2ban_config
echo "[10/10] Starting services..."
systemctl enable ossec
systemctl start ossec
systemctl enable fail2ban
systemctl start fail2ban
# Verification
sleep 5
if systemctl is-active --quiet ossec && systemctl is-active --quiet fail2ban; then
log_info "Installation completed successfully!"
log_info "OSSEC Web UI: http://$(hostname -I | awk '{print $1}'):1515"
log_info "Configuration files:"
log_info " - OSSEC: /var/ossec/etc/ossec.conf"
log_info " - fail2ban: /etc/fail2ban/jail.local"
log_info " - Logs: /var/ossec/logs/ and /var/log/fail2ban.log"
else
log_error "Service verification failed"
exit 1
fi
}
main "$@"
Review the script before running. Execute with: bash install.sh