# FoodProject SOC Lab This repository runs a combined SOC lab with: - `wazuh-docker` (single-node) — SIEM, log ingestion, rule engine - `iris-web` — case and alert management (DFIR-IRIS) - `Shuffle` — SOAR workflow automation - `pagerduty-stub` — mock PagerDuty escalation endpoint - `soc-integrator` (FastAPI) — KPI enrichment, IOC analysis, orchestration - `flask-openapi-shuffle` — OpenAPI demo for Shuffle integration All services are connected through a shared Docker network (`soc_shared`). ## Prerequisites - Docker + Docker Compose plugin - Bash - Python 3 (for test/seed scripts) ## Quick Start Start all services (detached): ```bash ./run-combined-stack.sh up --all -d ``` Start all and stream logs: ```bash ./run-combined-stack.sh up --all ``` Stop all: ```bash ./run-combined-stack.sh down --all ``` Status overview: ```bash ./run-combined-stack.sh status ``` ## Stack Management ```bash ./run-combined-stack.sh [target] [options] ``` | Command | Description | |---|---| | `up [target] [-d]` | Start services (default: all, detached) | | `down ` | Stop services (target required) | | `recreate [target]` | Force-recreate containers (picks up bind-mount changes) | | `logs [target] [-f]` | View logs | | `status` | Show container and endpoint status | | `dedup` | Remove duplicate OpenSearch index patterns in Wazuh dashboard | | `cleanup [--with-volumes]` | Prune stopped containers, unused images, builder cache | | `help` | Show full usage | Targets: `all` / `--all`, `wazuh`, `iris`, `shuffle`, `pagerduty`, `integrator`, `flask-openapi-shuffle` Examples: ```bash ./run-combined-stack.sh up iris -d ./run-combined-stack.sh recreate wazuh ./run-combined-stack.sh recreate --all ./run-combined-stack.sh down shuffle ./run-combined-stack.sh logs integrator -f ./run-combined-stack.sh dedup ./run-combined-stack.sh cleanup --with-volumes ``` > **macOS bind mount note**: After editing config files on the host, run `recreate` to ensure the > container picks up the new inode. The `Edit`/`Write` tools create new inodes on macOS which Docker > does not automatically detect. ## Service URLs | Service | URL | |---|---| | Wazuh Dashboard | `https://localhost` | | Wazuh API | `https://localhost:55000` | | IRIS-web | `https://localhost:8443` | | IRIS KPI Dashboard | `https://localhost:8443/kpi-dashboard` | | Shuffle UI | `http://localhost:3001` | | PagerDuty Stub | `http://localhost:18080` | | SOC Integrator API | `http://localhost:8088` | | SOC Integrator Swagger | `http://localhost:8088/docs` | ## SOC Integrator Key env file: `soc-integrator/.env` ### IRIS KPI endpoints These endpoints fetch IRIS data and enrich each record with live SLA/KPI metrics: ``` GET /iris/alerts List alerts with KPI GET /iris/alerts/{id} Single alert with KPI POST /iris/alerts/{id}/assign Assign alert GET /iris/alerts/export-csv Export alerts as CSV GET /iris/cases List cases with KPI GET /iris/cases/{id} Single case with KPI GET /iris/cases/export-csv Export cases as CSV ``` KPI is computed per alert/case: ``` elapsed_pct = (now − created_at) / sla_seconds × 100 kpi_pct = 100 − elapsed_pct (clamped 0–100) SLA by severity: High → 4 h Medium → 8 h Low → 24 h Status thresholds: On Track ≥ 80 | Watch ≥ 60 | Warning ≥ 40 | Urgent ≥ 20 | Critical > 0 | Breached Resolved alerts: elapsed frozen at resolution time, status = "Resolved" ``` ### MVP orchestration endpoints ``` POST /mvp/incidents/ingest POST /mvp/ioc/evaluate POST /mvp/vpn/evaluate GET /mvp/config/policies PUT /mvp/config/policies GET /mvp/health/dependencies ``` Protected endpoints require header: `X-Internal-API-Key` Key from: `SOC_INTEGRATOR_INTERNAL_KEY` in `soc-integrator/.env` ### Other endpoints ``` GET /health GET /wazuh/alerts GET /wazuh/agents POST /wazuh/sync-to-mvp GET /wazuh/auto-sync/status POST /ingest/wazuh-alert GET /ioc/enrich POST /ioc/evaluate GET /geoip/{ip} POST /action/create-incident POST /action/create-iris-case POST /action/trigger-shuffle GET/POST /shuffle/workflows GET /sim/logs/runs POST /sim/logs/start ``` ### Example: MVP ingest ```bash curl -X POST http://localhost:8088/mvp/incidents/ingest \ -H 'Content-Type: application/json' \ -H 'X-Internal-API-Key: dev-internal-key' \ -d '{ "source":"manual", "event_type":"ioc_ips", "event_id":"evt-1", "timestamp":"2026-02-12T16:00:00Z", "severity":"high", "title":"Test IOC", "description":"MVP test", "asset":{"hostname":"labhost","user":"analyst"}, "network":{"src_ip":"203.0.113.10","country":"US"}, "tags":["mvp","test"], "risk_context":{"admin_account":true}, "raw":{}, "payload":{} }' ``` ## Sending Test Events to Wazuh ### Appendix A/B/C simulation logs Replay production-style sample logs via syslog UDP 514: ```bash scripts/send-wazuh-sim-logs.sh all 1 0.2 scripts/send-wazuh-sim-logs.sh a2 1 0 scripts/send-wazuh-sim-logs.sh B3-06 1 0 scripts/send-wazuh-sim-logs.sh all 1 0 --dry-run ``` See `scripts/README.md` for full selector/flag reference. ### FortiGate firewall syslog test Send FortiGate-style syslog messages directly to Wazuh port 514/UDP: ```bash python3 scripts/test-firewall-syslog.py --via-docker python3 scripts/test-firewall-syslog.py --scenario rdp --via-docker ``` The `--via-docker` flag sends from inside the container to preserve the firewall source IP through Docker NAT. Source IP must be in the `allowed-ips` list in `wazuh_manager.conf`. ### Sync Wazuh alerts into MVP pipeline ```bash curl -X POST "http://localhost:8088/wazuh/sync-to-mvp?limit=50&minutes=120&q=*" \ -H 'X-Internal-API-Key: dev-internal-key' ``` Notes: - Reads from `wazuh-alerts-*` in Wazuh indexer. - Re-running is safe — dedupe applied by `source + event_id`. - Wazuh must fire rules before alerts appear (check `archives.log` first). ### Enable automatic sync worker ```bash sed -i 's/^WAZUH_AUTO_SYNC_ENABLED=.*/WAZUH_AUTO_SYNC_ENABLED=true/' soc-integrator/.env ./run-combined-stack.sh up integrator --build -d ``` Auto-sync settings in `soc-integrator/.env`: - `WAZUH_AUTO_SYNC_ENABLED` (`true|false`) - `WAZUH_AUTO_SYNC_INTERVAL_SECONDS` (default `60`) - `WAZUH_AUTO_SYNC_QUERY` (default `*`) - `WAZUH_AUTO_SYNC_LIMIT` (default `50`) - `WAZUH_AUTO_SYNC_MINUTES` (default `120`) ## KPI Dashboard The KPI dashboard is embedded inside IRIS at `/kpi-dashboard`. It shows alerts and cases with live SLA progress (colour-coded gauge), status, owner, and severity. The page auto-refreshes every 60 seconds. To seed test data covering every KPI state: ```bash IRIS_API_KEY= python3 scripts/seed-kpi-test-data.py ``` Find your API key in IRIS → My Profile. ## Logs All logs (non-follow): ```bash ./run-combined-stack.sh logs --all --tail 200 ``` Follow one stack: ```bash ./run-combined-stack.sh logs integrator -f ./run-combined-stack.sh logs wazuh -f ``` ## Notes - MVP escalation is wired to `pagerduty-stub` (not real PagerDuty). - IRIS-web is used as case management backend. - After `recreate wazuh`, run `./run-combined-stack.sh dedup` to remove duplicate index patterns created by the Wazuh dashboard post-init script. - Wazuh archive logging requires `yes` in `wazuh_manager.conf` (already enabled); archives appear in `/var/ossec/logs/archives/archives.log`.