Security Monitoring & Threat Detection
Understanding SIEM and Wazuh
Monitor everything. Detect threats. Respond fast. All from one dashboard!
Security Information and Event Management
A SIEM collects logs from all your systems, analyzes them for threats, and alerts you when something bad happens. Think of it as a security camera system for your entire infrastructure - but smarter!
Without SIEM:
With Wazuh: All logs in one place, automatic threat detection, instant alerts, and compliance reporting!
| Phase | Time | Difficulty |
|---|---|---|
| Understanding Concepts | 15-20 min | Reading |
| Wazuh Stack Installation | 45-60 min | Medium |
| Agent Deployment | 20-30 min | Easy |
| Custom Rules | 30-45 min | Medium |
| Alerting Setup | 20-30 min | Easy |
| Integration with Other Projects | 30-45 min | Medium |
Total: 3-4 hours
Understanding Wazuh architecture
Three main components work together to protect your infrastructure
| Capability | What It Does | Example |
|---|---|---|
| Log Analysis | Parse and analyze logs from any source | Failed SSH login attempts |
| File Integrity | Detect when critical files change | /etc/passwd modified |
| Rootkit Detection | Find hidden malware and backdoors | Hidden processes, kernel modules |
| Vulnerability Scan | Detect unpatched software | OpenSSL CVE-2024-xxxx |
| Active Response | Automatically block threats | Block IP after 5 failed logins |
| Compliance | Check against standards | PCI-DSS, HIPAA, GDPR checks |
Wazuh maps alerts to the MITRE ATT&CK framework - the industry standard for categorizing attacker tactics and techniques.
This helps you understand:
Running Wazuh gives you hands-on experience with the same tools used in enterprise Security Operations Centers (SOCs). Great for your resume!
What you need before starting
Wazuh needs more resources than our other projects
| Resource | Minimum | Recommended |
|---|---|---|
| CPU | 4 cores | 8 cores |
| RAM | 8 GB | 16 GB |
| Storage | 50 GB SSD | 100+ GB SSD |
Wazuh with the Indexer uses significant RAM. If running alongside Projects A-C, you'll need at least 16 GB total RAM on your server.
| Option | Pros | Cons |
|---|---|---|
| Option A: Docker (This Guide) |
Easy setup, consistent environment, works with our stack | Uses more RAM |
| Option B: Native Install | Better performance, lower overhead | More complex, harder to update |
Deploy the complete Wazuh stack with Docker
SSH into your server first. All commands run on the server, not your local machine.
# Create Wazuh directory
mkdir -p ~/wazuh-docker
cd ~/wazuh-docker
# Clone official Wazuh Docker repository
git clone https://github.com/wazuh/wazuh-docker.git -b v4.9.0
cd wazuh-docker/single-node
# Generate self-signed certificates for Wazuh components
docker compose -f generate-indexer-certs.yml run --rm generator
# Verify certificates were created
ls -la config/wazuh_indexer_ssl_certs/
# Start all Wazuh services
docker compose up -d
# This starts:
# - wazuh.manager (log analysis, rules engine)
# - wazuh.indexer (data storage, search)
# - wazuh.dashboard (web interface)
# Wait for services to be healthy (2-3 minutes)
docker compose ps
# Watch the logs
docker compose logs -f
The indexer needs to initialize. Wait 2-3 minutes before accessing the dashboard.
| Username | admin |
| Password | SecretPassword |
Go to Settings → Security → Internal Users to change the admin password immediately.
# Check all containers are running
docker compose ps
# Check Wazuh Manager status
docker exec -it single-node-wazuh.manager-1 /var/ossec/bin/wazuh-control status
# Check Indexer health
curl -k -u admin:SecretPassword https://localhost:9200/_cluster/health?pretty
# View manager logs
docker logs single-node-wazuh.manager-1 --tail=50
You should see the Wazuh dashboard. Currently no agents are connected - let's fix that next!
Install agents on servers you want to monitor
Agents run on each server, collecting logs and sending them to the Wazuh Manager
Run these commands on the SERVER you want to monitor (not the Wazuh server):
# Add Wazuh repository
curl -s https://packages.wazuh.com/key/GPG-KEY-WAZUH | gpg --no-default-keyring --keyring gnupg-ring:/usr/share/keyrings/wazuh.gpg --import && chmod 644 /usr/share/keyrings/wazuh.gpg
echo "deb [signed-by=/usr/share/keyrings/wazuh.gpg] https://packages.wazuh.com/4.x/apt/ stable main" | tee /etc/apt/sources.list.d/wazuh.list
# Install agent
apt update
WAZUH_MANAGER="YOUR_WAZUH_SERVER_IP" apt install -y wazuh-agent
# Enable and start agent
systemctl daemon-reload
systemctl enable wazuh-agent
systemctl start wazuh-agent
# Check status
systemctl status wazuh-agent
Change YOUR_WAZUH_SERVER_IP to the actual IP address of your Wazuh server.
# Add Wazuh repository
rpm --import https://packages.wazuh.com/key/GPG-KEY-WAZUH
cat > /etc/yum.repos.d/wazuh.repo << EOF
[wazuh]
gpgcheck=1
gpgkey=https://packages.wazuh.com/key/GPG-KEY-WAZUH
enabled=1
name=Wazuh repository
baseurl=https://packages.wazuh.com/4.x/yum/
protect=1
EOF
# Install agent
WAZUH_MANAGER="YOUR_WAZUH_SERVER_IP" yum install -y wazuh-agent
# Enable and start
systemctl daemon-reload
systemctl enable wazuh-agent
systemctl start wazuh-agent
# On the WAZUH SERVER, list connected agents
docker exec -it single-node-wazuh.manager-1 /var/ossec/bin/agent_control -l
# You should see something like:
# ID: 001, Name: ubuntu-server, IP: 192.168.1.50, Active
# Or check in the Dashboard:
# Agents → Summary
You should see your agent in the Wazuh Dashboard under Agents. It will start sending data immediately!
Create your own security detection rules
Wazuh has 3000+ built-in rules. You can add your own for custom detection!
Create a custom rule to detect SSH brute force attacks:
# Create custom rules file
docker exec -it single-node-wazuh.manager-1 bash -c 'cat > /var/ossec/etc/rules/local_rules.xml << "EOF"
5710
SSH brute force attack detected (5+ failures in 2 minutes)
T1110
authentication_failures,
5402
usermod|useradd
sudo|wheel|admin
User added to sudo/admin group - privilege escalation
T1136
550
/etc/passwd|/etc/shadow|/etc/sudoers
CRITICAL: Authentication file modified!
syscheck,
EOF'
# Restart manager to load rules
docker exec single-node-wazuh.manager-1 /var/ossec/bin/wazuh-control restart
Monitor critical files for unauthorized changes:
# Edit the agent configuration (on the monitored server)
nano /var/ossec/etc/ossec.conf
# Add or modify the syscheck section:
<syscheck>
<disabled>no</disabled>
<frequency>300</frequency> <!-- Check every 5 minutes -->
<!-- Critical system files -->
<directories check_all="yes" realtime="yes">/etc/passwd</directories>
<directories check_all="yes" realtime="yes">/etc/shadow</directories>
<directories check_all="yes" realtime="yes">/etc/sudoers</directories>
<directories check_all="yes" realtime="yes">/etc/ssh</directories>
<!-- Web server configs -->
<directories check_all="yes">/etc/nginx</directories>
<directories check_all="yes">/etc/apache2</directories>
<!-- Ignore noisy directories -->
<ignore>/etc/mtab</ignore>
<ignore>/etc/resolv.conf</ignore>
</syscheck>
# Restart agent
systemctl restart wazuh-agent
Each rule has a level (0-15 severity), id (unique number), and description. Rules can chain together using if_sid to detect patterns.
Get notified when threats are detected
Configure email, Slack, or webhook alerts for critical events
# Edit manager config
docker exec -it single-node-wazuh.manager-1 nano /var/ossec/etc/ossec.conf
# Add/modify email settings:
<global>
<email_notification>yes</email_notification>
<smtp_server>smtp.gmail.com</smtp_server>
<email_from>wazuh@yourdomain.com</email_from>
<email_to>security@yourdomain.com</email_to>
<email_maxperhour>12</email_maxperhour>
</global>
<!-- Alert on level 10+ -->
<alerts>
<email_alert_level>10</email_alert_level>
</alerts>
# Restart manager
docker exec single-node-wazuh.manager-1 /var/ossec/bin/wazuh-control restart
Send alerts to a Slack channel:
# Create Slack integration script
docker exec -it single-node-wazuh.manager-1 bash -c 'cat > /var/ossec/integrations/custom-slack << "EOF"
#!/bin/bash
# Slack Webhook Integration for Wazuh
WEBHOOK_URL="YOUR_SLACK_WEBHOOK_URL"
read -r INPUT
ALERT_LEVEL=$(echo $INPUT | jq -r ".alert_level")
RULE_DESC=$(echo $INPUT | jq -r ".rule_description")
AGENT_NAME=$(echo $INPUT | jq -r ".agent_name")
TIMESTAMP=$(echo $INPUT | jq -r ".timestamp")
# Color based on severity
if [ "$ALERT_LEVEL" -ge 12 ]; then
COLOR="danger"
elif [ "$ALERT_LEVEL" -ge 8 ]; then
COLOR="warning"
else
COLOR="good"
fi
curl -X POST -H "Content-type: application/json" \
--data "{
\"attachments\": [{
\"color\": \"$COLOR\",
\"title\": \"Wazuh Alert - Level $ALERT_LEVEL\",
\"text\": \"$RULE_DESC\",
\"fields\": [
{\"title\": \"Agent\", \"value\": \"$AGENT_NAME\", \"short\": true},
{\"title\": \"Time\", \"value\": \"$TIMESTAMP\", \"short\": true}
]
}]
}" $WEBHOOK_URL
EOF
chmod +x /var/ossec/integrations/custom-slack'
Automatically block IPs that trigger brute force alerts:
# Add to manager ossec.conf:
<!-- Active Response - Block attacking IPs -->
<active-response>
<command>firewall-drop</command>
<location>local</location>
<rules_id>100001</rules_id> <!-- Our brute force rule -->
<timeout>600</timeout> <!-- Block for 10 minutes -->
</active-response>
# This will automatically block any IP that triggers
# 5+ failed SSH logins in 2 minutes
Active response can block legitimate users. Test thoroughly and consider whitelisting trusted IPs.
Connect Wazuh to your existing stack
Monitor Authentik, Vault, and all your infrastructure from one place
Collect logs from your Docker containers (Authentik, Vault, etc.):
# On the server running Docker, add to agent ossec.conf:
<localfile>
<log_format>syslog</log_format>
<location>/var/lib/docker/containers/*/*-json.log</location>
</localfile>
# Or for specific containers:
<localfile>
<log_format>json</log_format>
<location>docker logs authentik-server</location>
<command>docker logs authentik-server 2>&1</command>
<frequency>60</frequency>
</localfile>
Create rules to detect suspicious Authentik activity:
# Add to local_rules.xml:
<group name="authentik,">
<!-- Authentik failed login -->
<rule id="100100" level="5">
<decoded_as>json</decoded_as>
<field name="event">login_failed</field>
<description>Authentik: Failed login attempt</description>
<group>authentication_failed,</group>
</rule>
<!-- Authentik brute force -->
<rule id="100101" level="10" frequency="5" timeframe="300">
<if_matched_sid>100100</if_matched_sid>
<description>Authentik: Multiple failed logins (brute force)</description>
<mitre>
<id>T1110</id>
</mitre>
</rule>
<!-- New admin user created -->
<rule id="100102" level="12">
<decoded_as>json</decoded_as>
<field name="event">user_write</field>
<match>is_superuser.*true</match>
<description>Authentik: New admin user created!</description>
</rule>
</group>
You now have a professional Security Operations dashboard showing real-time threats across your entire infrastructure.
Make sure everything works
Generate test events to verify detection is working
# From any machine, try failed SSH logins
# (Use wrong password intentionally)
for i in {1..6}; do
ssh fakeuser@YOUR_MONITORED_SERVER
done
# Press Ctrl+C after each password prompt
# Check Wazuh Dashboard → Security Events
# You should see brute force alerts!
# On a monitored server, modify a watched file
sudo touch /etc/test-fim-alert
# Or add a comment to hosts file
echo "# test" | sudo tee -a /etc/hosts
# Wait for FIM scan (up to 5 minutes)
# Check Dashboard → Integrity Monitoring
# Clean up
sudo rm /etc/test-fim-alert
sudo sed -i '/# test/d' /etc/hosts
Cause: Firewall blocking port 1514/UDP
Solution:
• Check agent logs: tail -f /var/ossec/logs/ossec.log
• Verify manager IP in agent config
• Open port 1514/UDP on firewall
Cause: Indexer still initializing or out of memory
Solution:
• Wait 3-5 minutes after startup
• Check memory: free -h
• Check logs: docker logs wazuh.indexer
Cause: Agent not sending data or rules not matching
Solution:
• Check agent status: systemctl status wazuh-agent
• Verify alerts.log: tail -f /var/ossec/logs/alerts/alerts.log
• Test rule with: /var/ossec/bin/wazuh-logtest
Your SIEM is operational!
You now have enterprise-grade security monitoring in your home lab!