mipo
Architecture

How mipo is built

Users reach the manager through Traefik on :443; scanners and resolvers reach ingest through a dedicated mutual-TLS ingress on :8443; the dispatcher orchestrates scans; one TimescaleDB cluster with three purpose-built schemas lives on an isolated network. The public website runs on separate infrastructure.

Topology

Edge, services, data — and a detached public site

Request path
Edge
Users + scanner bootstrap → :443 TraefikScanners / resolvers → :8443 Traefik (mTLS)
Two Traefik processes. :443 terminates TLS for users and for scanner provisioning/enrollment; a dedicated :8443 process requires a client certificate on every handshake and routes /scanner/* to ingest and /scanner/cert* to the manager.
↓
Services
Manager (GUI + admin API)Ingest ×2 (scanner API)Dispatcher (orchestration)Maintenance (evidence retention)Watchdog (platform health)
Session cookies for users; client certificates (mTLS) plus a per-scanner API key for scanners. The Node services run from one image selected by a ROLE variable.
↓
Data
db (TimescaleDB cluster)config / results / jobs schemasPer-service database roles
One TimescaleDB cluster with three schemas on an isolated internal network with no outbound internet; hypertables live only in the results schema. Each app service connects as its own role, and the evidence tables are append-only for every app role.
Separate infrastructure
Public siteNot behind Traefik
mipo.network (Astro static)
The marketing/docs site deploys to separate infrastructure, NOT behind Traefik.

The public website (this site) is static HTML/CSS/JS deployed to its own host. It shares no runtime, no database, and no request path with the mipo application.

Services

What each container does

ServiceRole
traefikThe :443 edge: TLS termination, path routing and load balancing for users, and for scanner provisioning and enrollment (the bootstrap channel).
traefik-scanner-mtlsA second Traefik process on :8443 for scanner and resolver runtime traffic. Every handshake must present a client certificate; /scanner/* routes to ingest, /scanner/cert* to the manager.
managerGUI + admin API (session cookies). Single instance.
ingest ×2Scanner API (client certificate + API key): heartbeats, job claims, result and receipt collection. Two fixed nodes behind the mTLS ingress.
dispatcherScan orchestration: resolves templates, batches jobs, reconciles stalls, schedules reverse-DNS work. Singleton.
maintenanceOwner-run evidence retention: the one service that prunes the append-only tables. No HTTP, no outbound. Singleton.
watchdogPython sidecar for platform health: container auto-heal, metrics, restart recovery, and activation of the scanner-CA trust bundle the :8443 ingress verifies against.
migratorOne-shot: applies schema migrations and reconciles the per-service role grants before any app container starts; also runs the pre-upgrade preflight.
backupEncrypted database backup (scheduled bundles); internal HTTP API. Restore is the operator CLI scripts/ops/restore.sh, which connects as the database owner.
dbOne TimescaleDB cluster (database mipo) with config / results / jobs schemas, on an isolated internal network. Hypertables live only in the results schema.

The five Node services — manager, ingest, dispatcher, maintenance, migrator — run from one unified image; a ROLE variable selects the entry point per container. Backup (shell + pg_dump) and the watchdog (Python) are separate images. A Docker socket proxy and a one-shot scanner-CA reconcile job complete the stack.

Deployment boundaries

Three Docker networks, one isolated database cluster

external (mipo_external)

Bridge with outbound NAT for services that need internet or external-facing ports: the :443 Traefik, manager, backup, watchdog, and the Docker socket proxy Traefik reads routes from.

internal (mipo_internal)

Isolated, no outbound internet. The database cluster plus everything that talks to it: manager, both ingest nodes, dispatcher, maintenance, backup, migrator, watchdog. The database cannot be reached from outside or reach out.

scanner-proxy

A fixed-subnet network for the mTLS path: both Traefik processes, the manager, and both ingest nodes. The pinned proxy address lets the backends verify that scanner traffic really arrived through the :8443 ingress.

Only the manager sits on all three networks. The ingest nodes are on scanner-proxy and internal — never on external — so scanner traffic can only arrive through the mTLS ingress. The dispatcher and maintenance are internal-only; backup and the watchdog bridge external and internal.

Database containment

Per-service roles, append-only evidence

The migrator creates five Postgres login roles — mipo_manager, mipo_ingest, mipo_dispatcher, mipo_ops, mipo_watchdog — each with its own password, and a container holds only its own role's credentials. The cluster owner is reserved for schema migrations, evidence retention, and break-glass access.

Six chain-of-custody tables are append-only: audit events, scan results, scan job receipts, DNS job receipts, DNS observation batches, and DNS observations. No application role is granted UPDATE or DELETE on them, and a BEFORE UPDATE/DELETE trigger blocks mutation even on a privileged path. Only the owner-run maintenance service prunes them, on the documented retention windows.

Scanner lifecycle

Provision → heartbeat → dispatch → report → receipt → reconcile

  1. Provision — the manager generates a one-time install command whose token is valid for one hour. The installer verifies the binary signature, generates the host's own key pair and API key, and sends a certificate request; the manager signs it and the host persists its client certificate.
  2. Heartbeat — every 60s the scanner reports liveness + system metrics to ingest over :8443; 2 minutes of silence marks it offline.
  3. Dispatch — the dispatcher fans fully-resolved jobs out to the right scanners (one job per scanner for groups).
  4. Report — scanners stream results back through ingest; scanners never write the database directly.
  5. Receipt — each job ends with a receipt signed by the scanner; the server recomputes every hash before accepting it.
  6. Reconcile — a background reconciler flags stalled jobs and emits recovery events.

Read the architecture guide

A long-form reference covers the topology, request path, and trust boundaries in depth.

Architecture guide Security model