Security Engineering · Technical Deep-Dive
Security compliance frameworks exist to answer one uncomfortable question: Can you prove your systems are secure? Not claim it — prove it with logs, alerts, and audit trails that hold up under third-party scrutiny.
| Tool | Role | License |
|---|---|---|
| Identity Layer (0) — SSO, SAML, OIDC, MFA, and a full audit log of every auth event | ✓ Open Source · Apache 2.0 | |
| SIEM & Compliance Engine — log ingestion, threat correlation, SOC 2 / HIPAA / PCI dashboards | ✓ Open Source · GPL | |
| Query & Inventory Layer — osquery across all endpoints, queryable compliance record | ✓ Open Source · MIT | |
🔬 OpenEDR | Behavioral Detection Layer — process trees, credential access, lateral movement via MITRE ATT&CK | ✓ Open Source · Apache 2.0 |
🚫 Fail2ban | Active Response Layer — bans offending IPs via firewall rules, immutable response audit trail | ✓ Open Source · GPL |
📧 MXToolbox | Email & Domain Security — continuous SPF, DKIM, DMARC, and blacklist monitoring | ✓ Free monitoring tier |
| Runtime Detection Layer — eBPF syscall interception on Linux servers and containers | ✓ Open Source · Apache 2.0 | |
| SOAR & Automation Layer — connects Wazuh, Fleet, Keycloak, Fail2ban, and Rocket.Chat into response workflows | ✓ Open Source · Apache 2.0 |
The App Stack
Keycloak — Identity Layer (Layer 0)
- Centralizes authentication across all devices and servers via SSO, SAML, and OIDC
- Produces a complete audit log of every login, token issuance, and admin action
For a fully managed Keycloak deployment on PikaPods, see Hosting Without the Headaches: Run WordPress, Ghost & Keycloak on PikaPods.
▶ show code▼ hide code
# Setup Steps
1. Deploy via Docker or dedicated 2 vCPU / 4 GB host
2. Create a dedicated realm — never use master for app logins
3. Create OIDC clients for Wazuh, Shuffle, Fleet, and Rocket.Chat
4. Enforce TOTP MFA via Required Actions
5. Set password policy: 12+ chars, special char, digit, history 5
6. Enable full event logging with 90+ day expiration
7. Wire Wazuh Dashboard SAML/OIDC via roles_mapping.yml
▶ show code▼ hide code
// Enable full event logging (realm settings)
// Keycloak realm settings — enable full event logging
{
"eventsEnabled": true,
"eventsExpiration": 7776000,
"adminEventsEnabled": true,
"adminEventsDetailsEnabled": true,
"enabledEventTypes": [
"LOGIN", "LOGIN_ERROR", "LOGOUT",
"REGISTER", "REGISTER_ERROR",
"UPDATE_PASSWORD", "UPDATE_PASSWORD_ERROR",
"CLIENT_LOGIN", "CLIENT_LOGIN_ERROR"
]
}
<!-- Wazuh agent — read Keycloak log output -->
<!-- ossec.conf — on Keycloak host -->
<ossec_config>
<localfile>
<log_format>json</log_format>
<location>/opt/keycloak/data/log/keycloak.log</location>
<label key="source">keycloak</label>
</localfile>
</ossec_config>
<!-- Wazuh rules — login failures and admin privilege changes -->
<!-- keycloak_rules.xml -->
<group name="keycloak,authentication,">
<rule id="92001" level="8">
<decoded_as>json</decoded_as>
<field name="source">keycloak</field>
<field name="type">LOGIN_ERROR</field>
<description>Keycloak: Authentication failure</description>
<group>pci_dss_10.2.4,hipaa_164.312.b,soc2_cc6.1,</group>
</rule>
<rule id="92002" level="12" frequency="5" timeframe="60">
<if_matched_sid>92001</if_matched_sid>
<description>Keycloak: Brute force attack — 5+ failures in 60 seconds</description>
<group>pci_dss_10.6.1,hipaa_164.312.b,</group>
</rule>
<rule id="92003" level="10">
<decoded_as>json</decoded_as>
<field name="source">keycloak</field>
<field name="operationType">CREATE|UPDATE|DELETE</field>
<field name="resourceType">USER|ROLE_MAPPING|CLIENT_ROLE_MAPPING</field>
<description>Keycloak: Admin privilege change detected</description>
<group>pci_dss_8.5,soc2_cc6.1,</group>
</rule>
</group>
Wazuh — SIEM & Compliance Engine
- Ingests logs from virtually any source and applies correlation rules to detect threats and policy violations
- Compliance dashboards map every event to specific control requirements — audit-ready without weeks of manual work
▶ show code▼ hide code
# Setup Steps
# Deploy Wazuh Manager + Indexer + Dashboard
1. Provision 4 vCPU, 8 GB RAM, 50+ GB SSD
2. Set hostname and configure /etc/hosts for local FQDN
3. Run the Wazuh all-in-one installer script
4. Confirm all three services are running
5. Log in and immediately change the default admin password
6. Lock firewall to ports 1514, 1515, and 443 only
# Install Wazuh Agents on all endpoints + Keycloak host
1. Linux: dpkg install with WAZUH_MANAGER env set
2. macOS: .pkg install + launchctl load
3. Windows: msiexec silent install
4. Verify each agent appears in dashboard within 60 seconds
5. Enable FIM on Keycloak config and log directories
6. Tag agents by group for policy segmentation
# Enable Wazuh Compliance Modules
1. Enable compliance dashboards in Wazuh → Modules
2. Verify ruleset includes compliance tags
3. Download and deploy NIST/CIS SCA policy files to agent groups
4. Run initial SCA scan and review compliance %
5. Document failing controls as tracked exceptions
# Configure Alert Routing
1. Email: configure SMTP in ossec.conf, set alert level >= 10
2. Phone/SMS: bridge via PagerDuty, OpsGenie, or Shuffle → Twilio
3. Rocket.Chat: configure incoming webhook in Wazuh or Shuffle
4. Test all channels with ossec-logtest
# Set ILM Retention Policies
1. Identify longest requirement (HIPAA = 6 years)
2. Create ILM policy: hot 7d → warm 30d → cold → delete at limit
3. Apply to wazuh-alerts-* and wazuh-archives-* templates
4. Size storage at ~1 GB/day per 100 agents
5. Configure S3 or NFS snapshot repo for cold storage
6. Document policy for audit evidence
Fleet — Query & Inventory Layer
- Manages osquery across all endpoints — servers, workstations, and cloud instances
- Gives auditors a queryable record of system state over time, not a point-in-time snapshot
- WireGuard add-on — pair Fleet with WireGuard to enforce VPN tunnel presence as a Fleet policy; osquery can verify the WireGuard interface is active on every enrolled device before granting access to internal resources
▶ show code▼ hide code
# Setup Steps
# Stand up Fleet + osquery
1. Deploy Fleet with MySQL + Redis backend (or Docker preview)
2. Configure TLS with Let's Encrypt or internal CA
3. Generate and distribute enroll secret via MDM
4. Confirm all hosts appear in Fleet UI within 5 minutes
5. Set agent update channel to stable with auto-update enabled
# Configure Fleet → Filebeat → Wazuh pipeline
1. Install Filebeat on the Fleet host (not the Wazuh server)
2. Point Filebeat input at Fleet's log output directory
3. Enable and configure the Wazuh Filebeat module
4. Test output: filebeat test output
5. Verify Fleet events appear in Wazuh Discover
# Schedule Fleet Compliance Queries
1. SELECT * FROM disk_encryption; — every 24h
2. SELECT username, uid, shell FROM users WHERE uid >= 1000; — every 12h
3. SELECT name, version, source FROM software; — every 24h
4. SELECT * FROM authorized_keys; — every 6h on servers
5. Create pass/fail Fleet Policies for FileVault/BitLocker status
6. Route query results through Fleet log pipeline → Filebeat → Wazuh
▶ show code▼ hide code
# Fleet result log configuration
# fleet.yml — result log configuration
logging:
result:
plugin: filesystem
config:
result_log_file: /var/log/fleet/osquery_results.log
status:
plugin: filesystem
config:
status_log_file: /var/log/fleet/osquery_status.log
# Filebeat — forward Fleet logs to Wazuh
# filebeat.yml
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/fleet/osquery_results.log
fields:
source: fleet-osquery
compliance: true
output.logstash:
hosts: ["wazuh-manager:5044"]
ssl.certificate_authorities: ["/etc/filebeat/wazuh-ca.pem"]
OpenEDR — Behavioral Detection Layer
- Continuous behavioral monitoring for process trees, credential access patterns, lateral movement, and file system anomalies
- Telemetry modeled on the MITRE ATT&CK framework
Deploy the Wazuh agent alongside OpenEDR on each endpoint. Configure the agent to read OpenEDR's JSON telemetry directly, then map MITRE ATT&CK categories to compliance control groups.
▶ show code▼ hide code
<!-- Wazuh agent — read OpenEDR telemetry and Windows Security Event Log -->
<!-- ossec.conf — on each endpoint -->
<ossec_config>
<localfile>
<log_format>json</log_format>
<location>C:\ProgramData\OpenEDR\Logs\*.json</location>
<label key="source">openedr</label>
</localfile>
<!-- Windows Security Event Log for HIPAA audit trail -->
<localfile>
<log_format>eventchannel</log_format>
<location>Security</location>
</localfile>
</ossec_config>
<!-- Wazuh rules — MITRE ATT&CK credential access detection -->
<!-- openedr_rules.xml -->
<group name="openedr,mitre,">
<rule id="91001" level="12">
<decoded_as>json</decoded_as>
<field name="source">openedr</field>
<field name="threat.type">credential_access</field>
<description>OpenEDR: Credential access attempt detected</description>
<mitre><id>T1003</id></mitre>
<group>pci_dss_10.6.1,hipaa_164.312.b,</group>
</rule>
</group>
Fail2ban — Active Response Layer
- Monitors log files for repeated authentication failures and automatically bans offending IPs via firewall rules
- Produces the immutable automated-response audit trail required by PCI DSS Req. 10 and SOC 2 CC7
▶ show code▼ hide code
# Setup Steps
1. Install on all internet-facing servers
2. Copy jail.conf → jail.local; enable sshd and nginx-http-auth jails
3. Set bantime = 1h, findtime = 10m, maxretry = 5
4. Configure JSON log output for Wazuh ingestion
5. Add Wazuh FIM watch on /etc/fail2ban/
6. Add active-response block in ossec.conf on rule 30105
7. Test: 5 bad SSH attempts → confirm ban + Wazuh alert fires
Wazuh triggers Fail2ban (active response): Wazuh detects brute force patterns across SSH, RDP, web applications, and Keycloak login failures, then calls Fail2ban to ban the source IP:
▶ show code▼ hide code
<!-- Wazuh active response configuration -->
<!-- ossec.conf — on Wazuh Manager -->
<ossec_config>
<active-response>
<command>fail2ban</command>
<location>local</location>
<rules_id>5763,5764,92002</rules_id> <!-- SSH brute force + Keycloak brute force -->
<timeout>3600</timeout>
</active-response>
</ossec_config>
#!/bin/bash
# /var/ossec/active-response/bin/fail2ban.sh
ACTION=$1
USER=$2
IP=$3
if [ "$ACTION" = "add" ]; then
fail2ban-client set wazuh-response banip "$IP"
elif [ "$ACTION" = "delete" ]; then
fail2ban-client set wazuh-response unbanip "$IP"
fi
# /etc/fail2ban/jail.d/wazuh-response.conf
[wazuh-response]
enabled = true
banaction = iptables-multiport
port = all
filter =
logpath = /var/log/wazuh-response.log
maxretry = 1
bantime = 3600
Fail2ban logs feed into Wazuh (audit trail): Every ban and unban becomes a Wazuh event — creating an immutable record of automated responses for PCI DSS Req. 10.2 and SOC 2 CC7:
▶ show code▼ hide code
<!-- Fail2ban log ingestion and audit rules -->
<!-- ossec.conf — Fail2ban log ingestion -->
<ossec_config>
<localfile>
<log_format>syslog</log_format>
<location>/var/log/fail2ban.log</location>
<label key="source">fail2ban</label>
</localfile>
</ossec_config>
<!-- fail2ban_rules.xml -->
<group name="fail2ban,">
<rule id="93001" level="8">
<decoded_as>fail2ban</decoded_as>
<match>Ban</match>
<description>Fail2ban: IP banned after repeated failures</description>
<group>pci_dss_10.2.4,pci_dss_10.6.1,soc2_cc7.2,</group>
</rule>
<rule id="93002" level="6">
<decoded_as>fail2ban</decoded_as>
<match>Unban</match>
<description>Fail2ban: IP ban expired and lifted</description>
<group>pci_dss_10.2.4,</group>
</rule>
</group>
The result is a closed loop: Wazuh detects → Fail2ban blocks → Fail2ban logs the action → Wazuh records it as a compliance event with full timestamp and IP.
MXToolbox — Email & Domain Security
- Passive monitoring of email domain health — verifies SPF, DKIM, and DMARC records continuously
- A misconfigured DMARC or blacklisted IP can enable domain spoofing or cause breach notification failures
▶ show code▼ hide code
# Setup Steps
1. Add blacklist monitors for all outbound mail server IPs
2. Add DNS monitors for SPF, DKIM, DMARC health on all sending domains
3. Add MX record monitors to detect tampering
4. Route MXToolbox webhooks into Shuffle → Wazuh for centralized logging
Falco — Runtime Behavioral Detection Layer
- eBPF-based syscall interception — detects threats at the kernel level without agents modifying endpoint code
- Fills the gap OpenEDR leaves on Linux servers and containers where Windows EDR agents don't apply
Deploy Falco on each Linux endpoint for eBPF-based runtime behavioral detection. Falco intercepts system calls and maps anomalies — shells spawned from web processes, mass file writes, privilege escalations — to MITRE ATT&CK techniques, feeding structured JSON events directly into Wazuh.
▶ show code▼ hide code
# Setup Steps
1. Add the Falco apt repo and install: apt install -y falco
2. Select eBPF driver at install — do not use kernel module on production hosts
3. Install driver: falcoctl driver install --type ebpf
4. Enable service: systemctl enable --now falco
5. Set json_output: true in /etc/falco/falco.yaml
6. Configure file output to /var/log/falco/falco.json
7. Add custom rules to falco_rules.local.yaml (mass file writes, shells from web processes)
8. Add Wazuh <localfile> block to tail /var/log/falco/falco.json
9. Restart Wazuh agent and confirm Falco events appear in Wazuh Discover
10. Add custom Falco decoder and rules in local_rules.xml on the Wazuh manager
Shuffle — SOAR & Automation Layer
- Connects Wazuh, Fleet, Keycloak, Fail2ban, and Rocket.Chat into automated response workflows
- Every automated action is logged as a timestamped workflow execution — providing the response audit trail auditors require
Deploy Shuffle SOAR to automate triage, enrichment, and response across the full stack. Wazuh alerts trigger Shuffle workflows that query Fleet for host context, call Wazuh active response to block IPs, and notify Rocket.Chat with enriched incident details.
▶ show code▼ hide code
# Setup Steps
1. Provision dedicated host: 2 vCPU / 4 GB RAM / 20 GB disk
2. Install Docker + Compose: curl -fsSL https://get.docker.com | sh
3. Clone Shuffle repo, set OUTER_HOSTNAME in docker-compose.yml, run docker compose up -d
4. Restrict login to Keycloak OIDC immediately after first launch
5. Install the Wazuh and HTTP apps from the Shuffle app library
6. Configure Wazuh app with manager URL and a least-privilege API user
7. Create a Webhook trigger in Shuffle and copy the hook URL
8. Add the Shuffle <integration> block to Wazuh ossec.conf with the webhook URL
9. Restart Wazuh manager and confirm test alerts arrive in Shuffle → Executions
10. Build triage playbook: parse alert level → if >= 12, call Wazuh active response → notify Rocket.Chat
11. Build Falco playbook: filter on falco rule group → enrich via Fleet/osquery → alert with host + process context
12. Build FIM rollback playbook: filter on rule 550/554 → SSH to agent → trigger restic/VSS restore → notify
13. Test each playbook end-to-end with ossec-logtest synthetic alerts
14. Set execution history retention to 30 days in Shuffle Settings
Alerting Configuration
Route Wazuh alerts by severity to ensure the right team is notified at the right time:
| Severity | Destination | Trigger Conditions |
|---|---|---|
| Level 12+ (critical) | Email + Phone | Active threats, credential access, policy breach |
| Level 8–11 (high) | Rocket.Chat #security | New admin accounts, failed login bursts, config drift |
| Weekly digest | Compliance pass/fail rates and alert trends | |
| Pre-audit export | Wazuh compliance dashboards export directly for SOC 2 / PCI evidence packages |
Security Frameworks Covered by This Stack
- NIST Five Functions — Priority: Critical. The strategic framework used to organize the entire network and server defense lifecycle. Each tool in this stack maps directly to one or more of the five functions: Identify (Fleet, Keycloak), Protect (Fail2ban, WireGuard), Detect (Wazuh, OpenEDR, Falco), Respond (Shuffle, Fail2ban), and Recover (Wazuh playbooks, Shuffle workflows).
- CWE — Common Weakness Enumeration coverage is addressed through OpenEDR's behavioral detection and Wazuh's rule library, which flags known weakness patterns (injection, privilege escalation, improper authentication) at the process and log level.
- CIS Docker Benchmarks — Priority: High. The gold standard for hardening the containerized server environments where modern apps live. Wazuh ships CIS Docker Benchmark audit rules out of the box; Fleet osquery policies can verify benchmark compliance continuously across every host running containers.
Answering Auditor Questions
"Show me your access control monitoring." Export the Wazuh SOC 2 CC6 dashboard. Fleet query history shows every host's user account state across the entire audit period. Keycloak admin event logs show every privilege grant and revocation.
"Show me your incident detection capability." OpenEDR's MITRE ATT&CK coverage map combined with Wazuh rule statistics demonstrates active detection across the full attack surface. Fail2ban ban logs show automated response to active brute force attempts.
"Were there any security incidents during the audit period?" Wazuh's alert history provides a complete, timestamped, immutable record. Incidents present means your detection-and-response process worked as designed.
"How do you detect unauthorized software changes?" Fleet's software inventory queries and Wazuh File Integrity Monitoring (FIM) provide a continuous record of what was installed, when, and on which host.
"How do you enforce MFA and manage user access?" Keycloak enforces MFA at the identity layer for all internal services. Its audit logs, ingested by Wazuh, provide a timestamped record of every authentication event and admin change.
This architecture scales from a 50-endpoint startup pursuing SOC 2 Type I to a 10,000-endpoint enterprise maintaining PCI DSS certification. The open-source foundation keeps licensing costs near zero, and the modular design allows adding commercial EDR feeds, cloud security logs, or network monitoring without replacing the core pipeline.