Installation
You run Sentinel on your own servers (on-prem) or in your own cloud account, and the software is the same either way. Each running copy is called an install.
What's in an install
An install is one binary, one PostgreSQL database and, optionally, Redis.
| Component | What it does |
|---|---|
sentinel-api | Serves the API under /v1, /healthz, and the dashboard at /. Applies database migrations when it starts. Scores events with versioned CEL rules. |
sentinel-admin | Command-line tool for operator tasks: creating keys, verifying the audit chain, seeding rules and loading screening lists |
| PostgreSQL | The system of record: events, decisions, alerts, rules, screenings, keys and the audit log. The local setup uses PostgreSQL 17. |
| Redis (optional) | Serves the velocity counters rules read. Without it the counts come from PostgreSQL, which is slower. Redis holds nothing that can't be rebuilt. |
The binary makes no outbound connections except to your database and Redis. Nothing goes to Somu Labs.
org_id, and every API key belongs to exactly one organisation. One install can serve several brands or legal entities with complete separation, including separate audit chains. Screening lists are the exception: they're shared by the whole install.Docker
The Dockerfile in the repository builds one image with the API, the dashboard and sentinel-admin. It runs as a non-root user, listens on port 8080, and has a health check on /healthz.
docker build -t sentinel --build-arg VERSION=v0.1.0 .
docker run -d --name sentinel -p 8080:8080 \
-e SENTINEL_DATABASE_URL="postgres://sentinel:change-me@db.internal:5432/sentinel" \
-e SENTINEL_BOOTSTRAP_API_KEY="snt_live_..." \
sentinel
Migrations run on startup, so a new image upgrades the schema when it starts. Run the admin tool inside the container:
docker exec sentinel /app/sentinel-admin audit verify -org default
From source
You need Go (the version in go.mod) and Node 22 for the dashboard.
make bundle # builds the dashboard and compiles it into bin/sentinel-api
./bin/sentinel-api # serves the dashboard at / and the API under /v1
make build builds the API without the dashboard. / then shows a page explaining the dashboard isn't included. make reads a .env file in the repository root if there is one. .env.example has local defaults.
For a local database, make up starts PostgreSQL on port 5433 and Redis on 6379 with Docker Compose. It also starts Redpanda, which nothing uses yet.
Configuration
All settings are environment variables. Only the database URL is required.
| Variable | Default | Meaning |
|---|---|---|
SENTINEL_DATABASE_URL | none, required | PostgreSQL connection string |
SENTINEL_HTTP_ADDR | :8080 | Address the API listens on |
SENTINEL_REDIS_ADDR | unset | Redis for velocity counters. Unset means counts come from PostgreSQL. |
SENTINEL_REDIS_DB | 0 | Redis database number, for installs that share a Redis |
SENTINEL_AUTO_MIGRATE | true | Apply pending migrations on startup. false skips them. |
SENTINEL_BOOTSTRAP_API_KEY | unset | Becomes the organisation's first API key, only while it has none. See the first key. |
SENTINEL_BOOTSTRAP_ORG | default | The organisation the bootstrap key belongs to |
SENTINEL_SCREENING_SAMPLE | false | Load the synthetic screening list when no list is loaded. Keep it off in production. |
SENTINEL_SLA_HIGH | 4h | How long a high priority alert has to be decided. Any Go duration, like 90m. |
SENTINEL_SLA_MEDIUM | 24h | The same for medium priority alerts. |
SENTINEL_NEAR_THRESHOLD_LOW | 4500 | Lower end of the "just under the reporting threshold" band the structuring counter uses. Set both ends or neither. |
SENTINEL_NEAR_THRESHOLD_HIGH | 5000 | Upper end of the band, not included. Set it to your reporting threshold. |
SENTINEL_RATE_LIMIT | 1000 | Requests a second each API key may make, on average. 0 turns the limit off. Each replica counts its own traffic. |
SENTINEL_RATE_BURST | twice the limit | How many requests a key may make at once before the average applies. |
The server fails to start, with a message naming the variable, if a required value is missing or a value can't be parsed.
First run
Start it
Point SENTINEL_DATABASE_URL at an empty database and start the binary or container. It applies every migration and logs which ones it ran.
Get a key
Set SENTINEL_BOOTSTRAP_API_KEY before the first start, or run sentinel-admin key create -name admin once. See Authentication.
Make your own keys
Sign in to the dashboard with that key, open Developers → API keys, and create a key for each person and service. Four-eyes approvals need at least two. Then revoke the bootstrap key and remove the variable.
Seed the rules
Run sentinel-admin rules seed -org default if you want the built-in rules installed as editable rules. See Rules.
Load a screening list
Run sentinel-admin screening load -file <list.json> with a list you've licensed. See Screening.
Admin commands
sentinel-admin reads SENTINEL_DATABASE_URL. Run it with go run ./cmd/sentinel-admin ... from source, or /app/sentinel-admin ... in the container. -org defaults to default.
| Command | What it does |
|---|---|
key create -org <org> -name <name> | Makes an API key and prints it once |
audit verify -org <org> | Checks the organisation's audit chain and reports the first broken entry |
rules seed -org <org> | Installs the built-in rules as active, editable rules. Refuses if the organisation already has rule versions. |
screening load -file <list.json> | Loads a sanctions or PEP list, or replaces the loaded list with the same code |
Network
| Connection | Direction | Purpose |
|---|---|---|
| Your services → API | Inbound | Events, entities, decisions and the rest of /v1. Internal network only; no public exposure needed. |
| Browsers → dashboard | Inbound | Your compliance team. Same port as the API. |
| API → PostgreSQL | Outbound, internal | Required |
| API → Redis | Outbound, internal | Optional |
The binary speaks plain HTTP. Put TLS in front of it with your load balancer or reverse proxy.
Operations
- Health.
GET /healthzreturns status and version, for your load balancer and monitoring. See Health. - Logs. Structured JSON on standard output.
- Several instances. You can run more than one behind a load balancer. Instances starting together take turns applying migrations. A rule activation takes effect at once on the instance that handled it and within 30 seconds on the others. New screening lists show up within 30 seconds too.
- Backups. Standard PostgreSQL backups cover everything that matters. Redis holds nothing that can't be rebuilt.
Not built yet
The product design includes more than the binary does today. None of these exist yet:
- Async processing on an event stream, and the workers that would deliver webhooks and file reports.
- Connectors that pull events from rails.
- A licence agent, usage metering, and signed updates for releases, lists and rule packs.
- Air-gapped update bundles.
- Sign-in through your SSO. The dashboard signs in with an API key.
- A Helm chart or a documented high-availability layout.