Architecture, no magic.
Four containers, two databases, one license check. That is the whole stack.
What's in the box
Every service mlab IR runs, and what it does. Tap a row to expand.
app
Rust and Actix-web. Serves the UI, exposes the REST API, handles authentication, two-factor verification and the twelve-bit permission system, and talks to both databases. Stateless, so restart it whenever you like. SQL migrations apply at boot.
executor
Background worker. Runs the license challenge, playbook executions, enrichment
lookups, SLA recomputation, webhook delivery with retries, and report generation.
Writes analytics to ClickHouse. It authenticates to app with a shared
secret: INTERNAL_SECRET is required and has no default.
MySQL 8
Transactional store: alerts, cases, incidents, observables, users, evidence metadata, playbooks, webhooks and enrichment configuration. Health-checked by Compose, so the app waits for it rather than crash-looping.
ClickHouse
Analytics and audit store: the append-only activity timeline, metric rollups and the enrichment cache. Two-year default retention, configurable from 30 to 3 650 days. The client recovers on its own after the server restarts.
License check - mlab.sh
The one call that is always on. Once per hour the executor sends a signed HMAC
challenge to mlab.sh/api/v1/ir/license/validate, carrying the tier, a
timestamp and a nonce. The result is cached locally with a 48-hour grace window.
No telemetry, no usage analytics, no error reporting to a SaaS.
Everything else that can leave your network →
Request to resolution
- Your SIEM posts to
app:/api/v1/ingest/alertwith an app token. appmaps the fields, deduplicates, writes to MySQL and emits a timeline event to ClickHouse.- Observables routed to an automatic source are enriched by
executor, and the merged verdict is cached for six hours. - The analyst loads the queue.
appreads MySQL for state and ClickHouse for history and metrics. - Escalation creates a case, then an incident. Subscribed webhooks are delivered by
executor, with retries and a delivery log. - On resolution, the report is rendered from the case and stored on the uploads volume.
Topology
Single host: all four containers via Docker Compose. Two gigabytes of RAM and ten of disk to start.
Scaled out: point DB_HOST and CH_HOST at managed instances and drop the database containers. app and executor stay stateless and scale horizontally behind a reverse proxy.
No Kubernetes operator and no Helm chart maintained as a separate product. If you run K8s you convert the compose file: the service contract is plain.
Serving over plain HTTP for a lab? Set COOKIE_SECURE=false, or sign-in will not work.
Everything that leaves your network, on one page.
Authentication, key scoping, egress and the gaps we know about.