-
-
Notifications
You must be signed in to change notification settings - Fork 0
MISP Integration
IRIS-NG ships two complementary MISP integration features:
-
Goal #1 — Native MISP sync module (
IrisMISPSyncModule): bidirectional sync of cases and IOCs to MISP events and attributes -
Goal #2 — MISP nomenclature alignment: every IOC type maps to a canonical MISP
attribute type via
IocType.type_taxonomy
A third, separate module publishes correlation results rather than individual cases:
IrisMISPCluster pushes a cross-case IOC cluster to MISP as a single campaign event,
on demand and one-directionally. See
MISP Cluster Publishing. It shares this module's REST client,
so the tag-search fix below applies to both.
| iris-ng event | MISP result |
|---|---|
| Case created | New MISP event created; link stored in misp_event_link
|
| Case updated | MISP event info updated |
| IOC created on case | New MISP attribute created on the event; link stored in misp_attribute_link
|
| IOC updated | MISP attribute updated |
The IOC's TLP drives the MISP attribute distribution and applies the matching tlp:<level>
tag on the attribute.
| Table | Purpose |
|---|---|
misp_event_link |
Maps case_id ↔ misp_event_uuid
|
misp_attribute_link |
Maps ioc_id ↔ misp_attribute_uuid
|
Navigate to /manage/modules → IrisMISPSync → Configure:
| Setting | Description |
|---|---|
| MISP URL | Base URL of your MISP instance |
| MISP API key | Authkey from MISP /auth_keys
|
| Verify TLS | Uncheck for self-signed certificates (lab/internal MISP) |
| AI API key | For the AI type resolver fallback (Goal #2) |
No restart required when changing module settings — parameters are read per-call.
If your MISP uses a self-signed certificate, disable Verify TLS in the module config.
This skips MITM protection — acceptable for internal/lab use. For stricter environments,
add the MISP CA to the app and worker container trust stores.
| Symptom | Cause | Fix |
|---|---|---|
(psycopg2.DatabaseError) PGRES_TUPLES_OK on hook tasks |
Celery fork-safety | Already fixed via NullPool in __init__.py — do not add db.session.remove() shims |
NotImplementedError in _indexes_for_keys before module runs |
app/worker code skew after upgrade | Run up --build --force-recreate
|
SSLCertVerificationError: self-signed certificate |
TLS | Uncheck Verify TLS in module config |
(406) PRECONDITION_FAILED - inequivalent arg 'x-max-priority' on case import |
Wrong celery queue-priority config | Fixed in configuration.py — ai_queue only; celery default queue is bare |
# Configure module via API (reads from .env)
docker exec iriswebapp_app python /iriswebapp/scripts/iris_misp_sync_dev.py configure
# Smoke test: create a case + IOC, verify MISP sync
docker exec iriswebapp_app python /iriswebapp/scripts/iris_misp_sync_dev.py smoke-test
# Re-sync a single IOC (bypasses celery, recovers dropped syncs)
docker exec iriswebapp_app python /iriswebapp/scripts/iris_misp_sync_dev.py resync-ioc --ioc-id <id>
# Validate MISP sync state
docker exec iriswebapp_app python /iriswebapp/scripts/validate_misp_sync.pyGET /tags/search/<term> silently returns [] for any tag name containing : — which
is every MISP taxonomy tag (tlp:green, circl:incident-classification="…", etc.).
Always use POST /tags/index with body {"searchall": term} when looking up a tag by name.
Every row in the ioc_type table carries a type_taxonomy column mapping it to the
canonical MISP attribute type. This is populated at app startup from the bundled MISP
catalog (source/app/resources/misp.attribute_types.json, 193 types).
Three IRIS-local types have no clean MISP match (account, file-path, ip-any).
For these, source/iris_misp_sync_module/ai_type_resolver.py calls LM Studio
(gpt-oss-20b) at confidence ≥ 0.70 to resolve them.
# Test the AI fallback resolver
docker exec iriswebapp_app python /iriswebapp/scripts/iris_misp_sync_dev.py test-ai-fallbackThe bundled MISP taxonomy + galaxy catalog powers tag autocomplete across every object modal in the UI (cases, IOCs, assets, tasks, events, evidence).
The catalog lazy-loads once on first /manage/tags/suggest call (~52 MB in-memory).
Each search is a linear scan with early-exit at limit 25 (~30-50 ms per call).
# Download the latest taxonomies + galaxies from GitHub
docker exec iriswebapp_app python /iriswebapp/scripts/download_misp_tag_bundles.pyCelery prefork workers inherit the parent's SQLAlchemy QueuePool and the live psycopg2
connection file descriptors. Concurrent children corrupt each other's protocol state on
a shared fd.
The fix is NullPool for worker processes only, configured in source/app/__init__.py
keyed on "worker" in sys.argv. Every query opens a fresh connection and closes it on
return.
Do not add per-module db.session.remove() at the top of hooks_handler — this
detaches ORM objects handed in by task_hook_wrapper and causes DetachedInstanceError.
The task_prerun / worker_process_init session-drop handlers in tasker/tasks.py
remain as defense-in-depth but are not the primary fix.