IRFlow
IRFlow is the incident response workflow engine for the opensecstack ecosystem. It manages the full incident lifecycle — from detection through containment, eradication, recovery, and closure — while enforcing CITADEL MARSHAL governance and tracking NIS2 Article 23 notification deadlines at every step.
Overview
IRFlow is a Go service (v1.0.0) licensed under AGPL-3.0. It listens on port 8083 and exposes a JWT-protected REST API alongside public HMAC-SHA256 signed webhook endpoints for receiving events from APIGuard, CITADEL, and ThreatFlow. PostgreSQL 16 is the single source of truth; the service is stateless and can run behind a load balancer with multiple replicas.
Key features
- Guarded incident state machine — incidents follow a strict lifecycle:
open → investigating → contained → eradicating → recovering → closed. The API enforces all transitions. - CITADEL MARSHAL governance — every privileged action is evaluated through the 5-gate MARSHAL engine. A
REFUSEorHARD_STOPoutcome prevents local persistence and returns HTTP 403. CITADEL is never bypassed even when unreachable. - CITADEL WORM anchoring — incident creation is anchored in the tamper-evident audit chain; the returned
worm_entry_idis persisted on the incident record. - NIS2 Article 23 notifications — regulatory-significant incidents (P1/P2/P3) trigger an asynchronous notification to the NIS2 Compass Article 21(2)(b) Incident Handling control. The async design ensures a slow Compass API can never block the incident creation path.
- Graph-based playbook executor — playbooks are defined as graphs with
OnSuccess/OnFailurebranching, per-step timeouts, and a cycle guard (max 100 steps per execution). - HMAC-signed webhook ingestion — inbound events from APIGuard, CITADEL, and ThreatFlow are verified with HMAC-SHA256 and a ±5-minute replay protection window.
- IOC enrichment — incidents can have indicators of compromise (IOCs) attached and cross-referenced with ThreatFlow intelligence.
- JWT + RBAC — HS256 bearer tokens with five canonical roles:
admin,operator,verifier,viewer, andservice. - Observability — Prometheus metrics at
/metrics; structured JSON audit log withrequest_idpropagation; the audit middleware fires before authentication so rejected requests are also logged.
Architecture
IRFlow has three concentric responsibility layers:
- Transport — a chi HTTP router with a middleware stack providing request IDs, audit logging, Prometheus metrics, JWT authentication, and HMAC verification for webhook routes.
- Domain services —
incident.Serviceencodes lifecycle rules, Separation of Duties checks, and NIS2 notification thresholds.playbook.Servicedrives the graph-traversal executor. - Persistence + governance —
PGStoreadapters backed by PostgreSQL 16 (pgxpool);CitadelClientfor MARSHAL evaluation and WORM emission;NIS2Clientfor Article 23 notifications. All boundary crossings are HMAC-signed.
| Package | Role |
|---|---|
cmd/irflow | CLI: serve, migrate, version, auth issue |
internal/api | chi router, middleware stack, HTTP handlers |
internal/auth | JWT verification, RBAC guards, audit logging |
internal/incident | Domain types, Service, governance interfaces, Stats |
internal/playbook | Domain types, Service, Executor (graph traversal) |
internal/governance | CitadelClient (MARSHAL + WORM), NIS2Client |
internal/db | pgxpool, PGStore (incidents), PGPlaybookStore |
internal/webhook | HMAC-SHA256 verifier and typed inbound payloads |
The service layer depends on interfaces defined next to its own domain types — not on concrete db or governance packages — so unit tests run against in-memory mocks and integration tests run against live PostgreSQL without changing any service code.
Ports & endpoints
| Service | Default port |
|---|---|
| IRFlow API | 8083 |
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /health | public | Liveness check |
| GET | /health/detail | public | Liveness + DB ping + version info |
| GET | /metrics | public | Prometheus scrape endpoint |
| POST | /api/v1/webhooks/apiguard | HMAC | Inbound APIGuard scan events |
| POST | /api/v1/webhooks/citadel | HMAC | Inbound CITADEL governance events |
| POST | /api/v1/webhooks/threatflow | HMAC | Inbound ThreatFlow IOC events |
| GET / POST | /api/v1/incidents | JWT | List / create incidents |
| GET / PATCH / DELETE | /api/v1/incidents/{id} | JWT | Fetch / update / delete incident |
| POST / GET | /api/v1/incidents/{id}/actions | JWT | Submit / list governed actions |
| GET | /api/v1/incidents/{id}/timeline | JWT | Chronological incident timeline |
| POST / GET | /api/v1/incidents/{id}/iocs | JWT | Attach / list IOCs |
| GET / POST | /api/v1/playbooks | JWT | List / create playbooks |
| POST | /api/v1/playbooks/{id}/execute | JWT | Async execution; returns 202 + Execution |
| GET | /api/v1/stats | JWT | Dashboard aggregation |
"cm"># Build and run make build ./bin/irflow migrate ./bin/irflow serve "cm"># Or with Docker docker build -t irflow . docker run -p 8083:8083 --env-file .env irflow "cm"># Issue a dev JWT (local testing only) export IRFLOW_AUTH_SECRET=local-secret ./bin/irflow auth issue --user alice --role operator --ttl 1h "cm"># Hit a protected endpoint curl -H "Authorization: Bearer $TOKEN" http://localhost:8083/api/v1/incidents
Integration
sinauth (identity)
IRFlow authenticates operators via sinauth SSO — the SIN identity provider (OAuth 2.0 / OIDC, authorization code + PKCE). Access tokens are RS256-signed JWTs issued by https://auth.sin.to and validated against the sinauth JWKS endpoint at https://auth.sin.to/.well-known/jwks.json. See the sinauth integration guide for token validation setup, RBAC mapping, and MFA configuration.
CITADEL (governance)
IRFlow integrates with CITADEL at two points. Every privileged action is evaluated by CITADEL MARSHAL via a dual-control Kerkese call; a REFUSE or HARD_STOP outcome returns HTTP 403 and the action is never persisted locally. Incident creation is anchored in the CITADEL WORM audit chain. Set IRFLOW_CITADEL_API_URL and IRFLOW_CITADEL_KEY_SECRET in production — omitting these leaves IRFlow in dev mode where governance is not enforced.
NIS2 Compass (compliance)
When an incident with severity P1, P2, or P3 is created, IRFlow fires an asynchronous notification to NIS2 Compass (IRFLOW_NIS2_API_URL) to update the Article 21(2)(b) Incident Handling control. The notification has a 30-second per-attempt timeout; failures are logged and nis2_notified_at is only persisted on success.
APIGuard (API security)
IRFlow accepts HMAC-signed webhook events from APIGuard at POST /api/v1/webhooks/apiguard. Critical or high findings from APIGuard can automatically open new incidents or enrich existing ones. Configure the shared secret with IRFLOW_WEBHOOK_APIGUARD_SECRET.
ThreatFlow (threat intelligence)
IRFlow accepts HMAC-signed events from ThreatFlow at POST /api/v1/webhooks/threatflow. ThreatFlow also receives incident artefacts from IRFlow for retroactive IOC matching, and pushes STIX 2.1 IOC bundles back for incident enrichment. Configure the shared secret with IRFLOW_WEBHOOK_THREATFLOW_SECRET.
IRFLOW_DB_PASSWORD, IRFLOW_AUTH_SECRET, IRFLOW_CITADEL_API_URL, IRFLOW_CITADEL_KEY_SECRET, IRFLOW_NIS2_API_URL, IRFLOW_NIS2_API_KEY, IRFLOW_NIS2_ASSESSMENT_ID, and one webhook secret per integrated source. An empty IRFLOW_AUTH_SECRET enables dev mode — never use in production.Full documentation
The complete IRFlow documentation lives in the irflow/docs folder on GitHub. Key references:
- docs/api.md — complete REST API reference with examples and Prometheus metrics catalogue
- docs/architecture.md — component map, package layout, request lifecycle, and design decisions
- CHANGELOG.md — release history
- SECURITY.md — vulnerability reporting and threat model