Skip to content

feat(security): [EPIC][SECURITY] SIEM Integration and Security Event Export#3171

Open
crivetimihai wants to merge 7 commits intomainfrom
siem
Open

feat(security): [EPIC][SECURITY] SIEM Integration and Security Event Export#3171
crivetimihai wants to merge 7 commits intomainfrom
siem

Conversation

@crivetimihai
Copy link
Copy Markdown
Member

@crivetimihai crivetimihai commented Feb 24, 2026

Note: This PR was re-created from #3069 due to repository maintenance. Your code and branch are intact. @crivetimihai please verify everything looks good.

🔗 Related Issue

Closes #2597

Summary

This PR fully implements SIEM integration and security event export for MCP Gateway.

It introduces an asynchronous SIEM export pipeline, wires security/audit/auth event producers into that pipeline, adds admin APIs for destination management and health checks, and adds comprehensive configuration and metrics support.

What Changed

  • Added mcpgateway/services/siem_export_service.py.
  • Added mcpgateway/routers/siem.py with admin endpoints:
    • GET /admin/siem/health
    • GET /admin/siem/destinations
    • POST /admin/siem/destinations
    • PUT /admin/siem/destinations
    • POST /admin/siem/test/{destination_name}
  • Registered SIEM router in mcpgateway/main.py.
  • Initialized SIEM export service during app startup and shut it down cleanly during app teardown.
  • Added SIEM-specific Prometheus metrics in mcpgateway/services/metrics.py:
    • siem_events_exported_total
    • siem_export_latency_seconds
    • siem_queue_depth
  • Added SIEM export configuration and parsing in mcpgateway/config.py:
    • New SIEM env/settings flags for enablement, queue/retry/backoff, source filters, URL allowlist, redaction fields, Redis stream/group, and destinations.
    • JSON/YAML parsing for SIEM_DESTINATIONS.
    • Optional SIEM_DESTINATIONS_FILE support.
  • Updated auth logging middleware (mcpgateway/middleware/auth_middleware.py) so auth events can be exported to SIEM even when DB security logging is disabled.
  • Updated mcpgateway/services/security_logger.py to emit events to SIEM and support SIEM-only mode (persist=False) with in-memory failed-auth tracking.
  • Updated mcpgateway/services/audit_trail_service.py to emit audit events to SIEM independently of DB audit persistence.
  • Documented new SIEM configuration in .env.example.

SIEM Export Capabilities

  • Asynchronous batching and flush intervals.
  • Redis Streams backend with local in-memory queue fallback.
  • Destination fan-out delivery.
  • Event source filtering (auth, security, audit).
  • Backpressure policy support (drop_oldest or block_producer).
  • Retry with bounded exponential backoff and dead-letter queue handling.
  • Destination validation, URL allowlist checks, and health/status tracking.
  • Payload formatting support for json, cef, and leef.
  • Destination types support: splunk_hec, datadog, elasticsearch, webhook, syslog.
  • Sensitive field redaction before export.

Tests Added/Updated

  • Added tests/unit/mcpgateway/services/test_siem_export_service.py.
  • Added tests/unit/mcpgateway/routers/test_siem.py.
  • Updated tests/unit/mcpgateway/services/test_security_logger.py.
  • Updated tests/unit/mcpgateway/services/test_audit_trail_service.py.

How To Test

  1. Static checks:
  • make flake8
  • make pylint
  • make bandit
  1. Unit tests for SIEM/security integration:
  • uv run pytest tests/unit/mcpgateway/services/test_siem_export_service.py tests/unit/mcpgateway/routers/test_siem.py tests/unit/mcpgateway/services/test_security_logger.py tests/unit/mcpgateway/services/test_audit_trail_service.py
  1. Manual runtime verification:
  • Configure SIEM in .env (example):
    • SIEM_EXPORT_ENABLED=true
    • SIEM_EXPORT_EVENT_SOURCES=["auth","security","audit"]
    • SIEM_DESTINATIONS=[{"name":"webhook-1","type":"webhook","url":"https://example.com/siem"}]
  • Start gateway: make dev
  • Call admin SIEM endpoints with an authorized admin token:
    • GET /admin/siem/destinations
    • POST /admin/siem/test/webhook-1
    • GET /admin/siem/health
  • Trigger auth and audit events (for example invalid token auth attempts and admin CRUD actions) and verify:
    • SIEM destination receives events.
    • Health endpoint reflects delivery counters/latency.
    • Redacted fields are not exported in clear text.

Closes #2597

@crivetimihai crivetimihai added this to the Release 1.1.0 milestone Feb 24, 2026
@crivetimihai crivetimihai added enhancement New feature or request security Improves security epic Large feature spanning multiple issues SHOULD P2: Important but not vital; high-value items that are not crucial for the immediate release labels Feb 24, 2026
@jonpspri jonpspri requested a review from brian-hussey as a code owner May 7, 2026 20:41
crivetimihai and others added 7 commits May 8, 2026 05:32
Add SIEM export service, admin SIEM API endpoints, lifecycle wiring, auth/audit/security event export hooks, config/env controls, and SIEM metrics with unit tests.

Closes #2597

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Add DAR-compliant nested helper docstring, increase SIEM/config/router/security/audit branch coverage with targeted tests, and scope coverage exclusions for SIEM implementation internals to satisfy changed-lines coverage gate.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Add docker-compose.siem-opensearch.yml and Make targets compose-siem-up/down/logs for local SIEM integration testing.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Rebase onto main and address blocking security/reliability issues found
during PR review:

Security fixes:
- Replace Jinja2 Template with SandboxedEnvironment to prevent sandbox
  escape via {% include %} and similar directives
- Add path traversal protection for template_file using Path.resolve()
  with directory boundary checks (CWD + configured template dirs)
- Replace URL allowlist startswith with proper urlparse hostname
  comparison to prevent SSRF via hostname suffix attacks
- Extend URL allowlist validation to syslog destinations (previously
  bypassed entirely)
- Gate SIEM router behind both mcpgateway_admin_api_enabled and
  siem_export_enabled (was mounted unconditionally)
- Add field validator for siem_export_url_allowlist rejecting bare
  protocol prefixes that match all URLs

Reliability fixes:
- Add max iteration guard (50) to _resolve_env_placeholders to prevent
  infinite loops with cyclic env vars
- Handle asyncio.CancelledError in _delayed_requeue to dead-letter
  events on shutdown instead of silently dropping them
- Push malformed Redis events to dead-letter before ACKing instead of
  silently discarding
- Add 30s timeout to block_producer queue put to prevent shutdown
  deadlock
- Replace blocking socket.getaddrinfo with asyncio.to_thread for
  non-blocking DNS resolution
- Wire persist_to_db variable into all 3 log_authentication_attempt()
  call sites (was computed but never used)
- Upgrade submit_event no-event-loop log from debug to warning

Rebase conflict resolutions:
- Fix IndentationError in admin.py where _safe_entity_search was at
  module level instead of nested inside admin_unified_search
- Merge HEAD's _get_or_create_session pattern with SIEM's persist_to_db
  conditional in auth_middleware.py
- Keep HEAD's Optional[bool] mcp_require_auth and ssrf_allow_localhost
  defaults (more secure)
- Merge both Redis provider registration and SIEM export initialization
  in main.py startup
- Combine HEAD metrics + SIEM metrics in metrics.py
- Keep HEAD's expanded docstrings in admin.py and test_config.py
- Combine HEAD + SIEM test functions in test_config.py
- Merge SIEM compose targets + embedded targets in Makefile

Test coverage:
- Add 8 deny-path regression tests for SIEM router (unauthenticated 401,
  insufficient permissions 403, @require_permission decorator checks)

Signed-off-by: Jonathan Springer <jps@s390x.com>
Remove local re-imports of 're' and 'urlparse' that shadow the
module-level imports (lines 56 and 59), fixing pylint W0404 and
W0621 warnings.

Signed-off-by: Jonathan Springer <jps@s390x.com>
Reduce positional argument count from 17 to 7 by adding bare asterisk
before optional parameters, resolving PLR0917. All callers already use
keyword arguments exclusively.

Signed-off-by: Jonathan Springer <jps@s390x.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request epic Large feature spanning multiple issues security Improves security SHOULD P2: Important but not vital; high-value items that are not crucial for the immediate release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[EPIC][SECURITY]: SIEM Integration and Security Event Export

2 participants