Contigov — Architecture Overview
This document describes the technical architecture of the Contigov platform: how components are structured, how they communicate, what each component is responsible for, and how data flows through the system.
Table of Contents
- High-Level Summary
- Architecture Diagram
- Central Server
- Agent (Endpoint Binary)
- Server ↔ Agent Communication
- Database
- Authentication & Security
- Policy Enforcement Flow
- Vulnerability Scanning Flow
- External Integrations
- Scalability & Performance
- Full Technology Stack
1. High-Level Summary
Contigov is a hub-and-spoke governance platform. A single central server acts as the control plane — storing policy, receiving telemetry, and delivering actions. Lightweight agents run natively on every managed endpoint and carry out enforcement locally, even if the server is temporarily unreachable.
The platform is designed around three core principles:
- Agent autonomy — policy is cached on the agent. Enforcement continues during network interruptions without degrading to an open state.
- Zero persistent open ports on endpoints — agents initiate all outbound connections to the server. No inbound firewall rules are needed on managed machines.
- Single deployable unit — the entire server (web UI, REST API, database, TLS, metrics) ships as one Docker image with no external dependencies (no Redis, no Postgres, no message broker required).
2. Architecture Diagram
│ External Access │
│ Browser / Admin UI AI Assistants (MCP) │
│ Prometheus Scraper Webhooks (Teams/Slack) │
└───────────────┬────────────────────────────┬────────────────────────┘
│ HTTPS (443) │ HTTPS
▼ ▼
┌─────────────────────────────────────────────────────────────────────┐
│ Optional: AWS ALB / nginx / Cloudflare │
│ (TLS termination layer) │
└───────────────────────────────┬─────────────────────────────────────┘
│ HTTP (proxy mode) or HTTPS (direct)
▼
┌─────────────────────────────────────────────────────────────────────┐
│ CONTIGOV SERVER │
│ (Docker container, Node.js 20) │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌──────────────┐ ┌──────────┐ │
│ │ Web UI │ │ REST API │ │ MCP Server │ │ /metrics │ │
│ │ (SPA) │ │ /api/* │ │ /mcp │ │ Prometheus│ │
│ └─────────────┘ └──────┬──────┘ └──────────────┘ └──────────┘ │
│ │ │
│ ┌────────────────────────▼────────────────────────────────────┐ │
│ │ Business Logic Layer │ │
│ │ Policy Engine · Audit Logger · Webhook Engine │ │
│ │ Write Buffer · Notification Rules · AI Detection │ │
│ └────────────────────────┬────────────────────────────────────┘ │
│ │ │
│ ┌────────────────────────▼────────────────────────────────────┐ │
│ │ SQLite Database (WAL mode) │ │
│ │ AES-256-GCM encrypted at rest │ │
│ └─────────────────────────────────────────────────────────────┘ │
└───────────┬───────────────────────────────────────────────────┬─────┘
│ HTTPS (agent reports every 30s) │
│ Agent authenticates with Bearer API Key │
┌─────────▼──────────┐ ┌───────────────────┐ ┌────────────▼──────┐
│ AGENT │ │ AGENT │ │ AGENT │
│ Windows │ │ macOS │ │ Linux │
│ (Go binary) │ │ (Go binary) │ │ (Go binary) │
│ │ │ │ │ │
│ • Container report │ │ • Container report│ │ • Container report│
│ • Hosts enforcement │ │ • Hosts enforcement │ • Hosts enforcement│
│ • Pull interception │ │ • Pull interception │ • Pull interception│
│ • Trivy scanning │ │ • Trivy scanning │ │ • Trivy scanning │
│ • Desktop notify │ │ • Desktop notify │ │ • Desktop notify │
└─────────────────────┘ └───────────────────┘ └───────────────────┘
3. Central Server
The server is a Node.js 20 / Express application packaged as a single Docker image. It is responsible for:
Internal port layout
4. Agent (Endpoint Binary)
The agent is a statically compiled Go binary — no runtime, no dependencies, no installation wizard. It runs natively on Windows, macOS, and Linux. Its entire job is to observe the local Docker daemon, enforce policy, and report telemetry to the server.
Agent responsibilities
Agent startup sequence
- Detect operating system and Docker socket path
- Self-elevate to administrator / root (UAC on Windows, sudo on Linux/macOS) if not already elevated
- Load configuration from
agent-config.json(or environment variables) - Send first report to server — registers the endpoint and receives initial policy
- Apply policy: rewrite hosts file, start Docker event listener
- Start background loops: report timer, override poller, pull interceptor listener
- Download Trivy if not cached; begin scanning local images
Agent binary sizes
5. Server ↔ Agent Communication
Protocol
All agent-to-server communication uses HTTPS over port 443 (or the configured server URL). Communication is always agent-initiated — the server never pushes to agents directly. This means:
- No inbound firewall ports need to be opened on managed machines
- Agents behind NAT or corporate proxies work without special configuration
- The server can be on a private network as long as agents can reach its URL
Authentication
Every request from an agent includes:
The server validates this against the configured API_KEY environment variable. Requests without a valid key are rejected with HTTP 401. This key is shared across all agents in the fleet and is configured in agent-config.json.
Report cycle
Every report cycle the agent:
- Sends
POST /api/reportwith a JSON payload containing running containers, local images, agent version, OS, and hostname - Receives a JSON response containing the current policy (blocked images, blocked registries, overrides), any pending remote actions, the next report interval, and maintenance mode status
- Applies any changes immediately (hosts file sync, container enforcement, action execution)
Report payload (simplified)
“hostname”: “WORKSTATION-01”,
“os”: “windows”,
“agent_version”: “1.0.42”,
“containers”: [
{ “id”: “abc123”, “name”: “nginx”, “image”: “nginx:1.25”, “status”: “running” }
],
“images”: [
{ “id”: “sha256:…”, “tags”: [“nginx:1.25”], “size”: 142000000 }
]
}
Response payload (simplified)
“blocked_images”: [“nginx:1.19”, “python:2.7”],
“blocked_hosts”: [“docker.io”, “gcr.io”],
“overrides”: [],
“actions”: [],
“report_interval_seconds”: 30,
“maintenance_paused”: false,
“maintenance_until”: null
}
Additional agent endpoints
6. Database
Contigov uses SQLite as its embedded database. This is a deliberate design choice — SQLite eliminates the need for a separate database server, making the platform genuinely single-binary deployable with no external dependencies.
Configuration
- WAL mode (Write-Ahead Logging) — readers never block writers. Write throughput is 5–10× higher than SQLite’s default journal mode. Critical for handling concurrent agent reports.
- AES-256-GCM encryption at rest — the entire database file is encrypted using the
DB_ENCRYPTION_KEYenvironment variable. The key never leaves the server process. - 9 indexes — covering all hot-path queries (device lookups, audit log searches, container history). Full table scans are eliminated on all common access patterns.
- In-memory write buffer — agent reports are batched in memory and flushed every 2 seconds in a single transaction, reducing write amplification under high agent load.
- DB-ready guard — the server does not begin accepting API traffic until all schema migrations have completed successfully.
Key tables
Storage estimates
The Monitoring page displays live DB size and audit log row count with threshold warnings at 1 GB, 5 GB, and 10 GB.
7. Authentication & Security
User authentication flow
- User submits username and password to
POST /api/auth/login - Server verifies bcrypt hash. If MFA is enabled, returns a short-lived
mfa_tokeninstead of a session - User submits TOTP code to
POST /api/auth/mfa/verifywith themfa_token - Server issues a signed JWT with a unique
jticlaim, expiry, and user role. The JWT is set as an httpOnly, Secure, SameSite=Strict cookie — never accessible to JavaScript - All subsequent API requests are authenticated by reading and verifying the cookie. The
jtiis checked against the in-memory revocation map on every request
SSO / OIDC flow
- User clicks “Continue with SSO” on the login page
- Server generates a PKCE code verifier + challenge and a random state token, then redirects to the OIDC provider (Entra ID, Okta, Google, Keycloak, etc.)
- User authenticates with the provider
- Provider redirects to
/api/auth/callbackwith an authorization code - Server exchanges the code for tokens, verifies the ID token signature using the provider’s JWKS, and extracts claims
- If
allowed_group_idis configured, the user’s group membership is checked. Ifadmin_group_idis configured, matching group members receive the admin role automatically - User account is auto-provisioned on first SSO login. Subsequent logins update the last-seen timestamp
- Session cookie is issued identically to local login
Security controls summary
8. Policy Enforcement Flow
This diagram shows what happens from the moment an admin blocks an image to the moment a container is stopped on a managed endpoint.
│
▼
POST /api/blocked-images (server)
→ Writes to blocked_images table
→ Invalidates in-memory policy cache
│
▼ (next agent report cycle — up to 30 seconds)
Agent sends POST /api/report
← Server responds with updated blocked_images list
│
▼
Agent updates in-memory policy cache
│
┌─────┴──────────────────────────────────┐
│ │
▼ ▼
Docker event listener Hosts file enforcer
detects “container start” runs on next 60s tick
for a container running nginx:1.19 │
│ ▼
▼ Adds docker.io → 127.0.0.1
Agent calls docker stop -t 0 to /etc/hosts
│ │
▼ ▼
Container is stopped immediately Future “docker pull nginx:1.19”
│ fails immediately at DNS level
▼
Agent sends POST /api/audit
event: ENFORCEMENT_TRIGGERED
│
▼
Server fires webhook (if configured):
Teams / Slack / Discord notification
Agent sends OS desktop notification
to the endpoint user
Hosts file management
The agent writes a clearly marked block to the system hosts file:
127.0.0.1 registry-1.docker.io
127.0.0.1 auth.docker.io
127.0.0.1 index.docker.io
# CONTIGOV END
Only entries between the markers are managed by Contigov. All other hosts file entries are left untouched. When maintenance mode is active or a policy override is granted, the block is removed immediately and restored after the exception expires.
9. Vulnerability Scanning Flow
│
▼
Is Trivy binary present and up to date?
No → Download Trivy from GitHub releases (one-time)
Yes → Proceed
│
▼
Run: trivy image –format json <image>
│
▼
Parse JSON output → extract CVE list
(CVE ID, severity, package, version, fix version)
│
▼
POST /api/scans → Server stores results in vulnerabilities table
│
▼
Web UI displays CVE breakdown per image:
CRITICAL · HIGH · MEDIUM · LOW · UNKNOWN
(with one-click CSV export per image or fleet-wide)
│
▼
If any CRITICAL CVEs found:
→ Notification rule “critical_cve” fires (if enabled)
→ Webhook fires with event type “scan.critical”
→ Admin sees alert badge on the endpoint card
Scan triggers
10. External Integrations
Webhooks
The server’s built-in webhook engine delivers real-time event notifications to external systems. No plugin or third-party service is required.
OX Security
When the OX Security integration is enabled, container vulnerability scan results are pushed to OX Security’s ASPM platform automatically after each Trivy scan completes. Configure the API key and API URL under Settings → Integrations → OX Security.
MCP Server (AI Assistants)
Contigov exposes a Model Context Protocol (MCP) endpoint at /mcp. Any MCP-compatible AI assistant (Cursor IDE, Claude Desktop, GitHub Copilot) can connect and use natural language to query the fleet, check vulnerabilities, and manage policy.
Prometheus
Standard Prometheus metrics are available at /metrics. Authentication is required — either an admin session JWT or a static METRICS_TOKEN configured via environment variable for scrape jobs.
scrape_configs:
– job_name: contigov
scheme: https
bearer_token: <METRICS_TOKEN>
static_configs:
– targets: [“your-contigov-domain.com”]
11. Scalability & Performance
Capacity targets
Tuning the report interval
The report interval is set globally from the Dashboard (Settings → General) and pushed to all agents automatically on their next report cycle — no agent restart or re-deployment required.
Multi-instance / HA limitations
The current architecture is single-server. SQLite, in-memory rate limiters, in-memory token revocation maps, and in-memory write buffers do not coordinate across multiple instances. For high-availability or multi-region deployments, a PostgreSQL-backed version with Redis for shared state is required.