Administration¶
Audience: IT administrators managing a Sentari deployment at a government agency or regulated enterprise
Applies to: Docker Compose and OpenShift (Helm) deployments
Table of Contents¶
- Service Overview
- Health Checks
- Starting and Stopping
- Database Backup and Restore
- Secret Rotation
- User Management
- Agent Management
- Dashboard Navigation
- CVE Feed Configuration
- Alert Configuration
- Proxy Configuration
- Log Management
- Updating Sentari
- Task Monitoring with Flower
1. Service Overview¶
Sentari runs as five services. Each service has a specific role; understanding them helps you diagnose problems and apply the right corrective action.
| Service | Container / Workload name | Role |
|---|---|---|
| sentari-api | sentari-api |
FastAPI application server. Serves the web dashboard and all REST API endpoints. Initialises the internal CA and bootstrap admin on first startup. |
| sentari-worker | sentari-worker |
Celery worker. Executes asynchronous tasks: CVE correlation after a scan upload, SIEM webhook delivery, email alert dispatch. Scales horizontally. |
| sentari-beat | sentari-beat |
Celery Beat scheduler. Fires periodic tasks, including the daily CVE feed synchronisation. Exactly one instance must run at all times. Running multiple Beat processes causes duplicate task execution. |
| db | sentari-db |
TimescaleDB 2.14 on PostgreSQL 16. Stores all application data: devices, packages, CVE correlations, audit logs, compliance snapshots. |
| redis | sentari-redis |
Redis 7. Acts as the Celery message broker and result backend. All task queuing passes through Redis. |
Internal CA¶
On first startup, sentari-api generates a self-signed RSA-4096 CA keypair stored in /etc/sentari/ca/ (Docker volume ca-data, or a PVC in Kubernetes). This CA issues ECDSA P-256 client certificates to enrolling agents for mTLS authentication. The CA data volume is shared between sentari-api and sentari-worker.
License¶
If a SENTARI_LICENSE_KEY is configured, it is validated at startup and periodically thereafter. Without a valid license the application enters read-only mode: GET requests and agent scans continue to work, but management writes (user creation, policy changes, agent registration) return HTTP 402. The dashboard displays a banner indicating the license state.
2. Health Checks¶
Docker Compose¶
Check the status and health of all services:
cd deploy
docker compose ps
Expected output when everything is healthy:
NAME IMAGE STATUS
sentari-api ghcr.io/sentari-dev/sentari/server Up (healthy)
sentari-worker ghcr.io/sentari-dev/sentari/server Up (healthy)
sentari-beat ghcr.io/sentari-dev/sentari/server Up (healthy)
sentari-docs ghcr.io/sentari-dev/sentari/docs Up (healthy)
sentari-db timescale/timescaledb Up (healthy)
sentari-redis redis:7.2-alpine Up (healthy)
A service in Up (unhealthy) or Up (health: starting) state needs investigation. Check its logs:
docker compose logs --tail=50 <service-name>
OpenShift¶
oc get pods -l app.kubernetes.io/instance=sentari
Check a specific pod's readiness and recent events:
oc describe pod <pod-name>
API health endpoint¶
The /api/health endpoint verifies database and Redis connectivity. It returns HTTP 200 when both backends are reachable, or HTTP 503 with a list of unreachable components if one or both are down.
curl -s https://<server-hostname>/api/health
Healthy response:
{"status": "ok", "version": "..."}
Degraded response (database unreachable):
{"status": "degraded", "version": "...", "unreachable": ["database"]}
Use this endpoint in your monitoring system. A 503 response should trigger an alert to your operations team.
3. Starting and Stopping¶
Docker Compose¶
Start all services:
cd deploy
docker compose --env-file .env up -d
The first startup includes Alembic database migrations. Allow up to 60 seconds before the API becomes available.
Stop all services (data preserved):
docker compose down
Restart a single service (for example after a configuration change):
docker compose restart sentari-api
Restart all application services (not the database or Redis):
docker compose restart sentari-api sentari-worker sentari-beat
Correct shutdown order when performing maintenance that requires taking services offline:
# 1. Stop the scheduler first to prevent new tasks from being enqueued
docker compose stop sentari-beat
# 2. Stop the API to stop accepting new requests
docker compose stop sentari-api
# 3. Allow the worker to drain in-flight tasks (wait ~30 seconds), then stop it
docker compose stop sentari-worker
# 4. Stop Redis and the database last
docker compose stop redis db
OpenShift¶
Scale a deployment to zero (takes it offline without deleting it):
oc scale deployment sentari-api --replicas=0
oc scale deployment sentari-worker --replicas=0
oc scale deployment sentari-beat --replicas=0
Bring it back:
oc scale deployment sentari-api --replicas=1
oc scale deployment sentari-worker --replicas=1
oc scale deployment sentari-beat --replicas=1
Trigger a rolling restart (pulls new configuration without downtime):
oc rollout restart deployment/sentari-api
oc rollout restart deployment/sentari-worker
oc rollout restart deployment/sentari-beat
Watch the rollout status:
oc rollout status deployment/sentari-api
Note on Beat replicas: The
sentari-beatdeployment is always set to exactly one replica. Do not scale it above 1. The Helm chart'svalues.yamldoes not expose a replica count for Beat precisely for this reason. If Beat is running as multiple pods, duplicate scheduled tasks will fire, causing repeated CVE sync runs and spurious alert emails.
4. Database Backup and Restore¶
Sentari uses TimescaleDB (PostgreSQL 16). Standard PostgreSQL tools work without modification.
Backup — Docker Compose¶
Run pg_dump inside the database container and write the dump to the host:
docker exec sentari-db pg_dump \
-U sentari \
-d sentari \
-F custom \
-f /tmp/sentari-backup.dump
docker cp sentari-db:/tmp/sentari-backup.dump ./sentari-backup-$(date +%Y%m%d).dump
The -F custom flag produces a compressed binary dump. It is smaller than plain SQL and supports parallel restore with pg_restore.
Backup — OpenShift¶
DB_POD=$(oc get pod -l app=sentari-db -o jsonpath='{.items[0].metadata.name}')
oc exec "$DB_POD" -- pg_dump \
-U sentari \
-d sentari \
-F custom \
-f /tmp/sentari-backup.dump
oc cp "$DB_POD":/tmp/sentari-backup.dump ./sentari-backup-$(date +%Y%m%d).dump
Restore — Docker Compose¶
Stop
sentari-api,sentari-worker, andsentari-beatbefore restoring to prevent writes during the operation.
# Copy the dump into the container
docker cp ./sentari-backup-YYYYMMDD.dump sentari-db:/tmp/restore.dump
# Drop and recreate the database
docker exec -e PGPASSWORD="$POSTGRES_PASSWORD" sentari-db \
psql -U sentari -c "DROP DATABASE IF EXISTS sentari;"
docker exec -e PGPASSWORD="$POSTGRES_PASSWORD" sentari-db \
psql -U sentari -c "CREATE DATABASE sentari;"
# Restore
docker exec sentari-db pg_restore \
-U sentari \
-d sentari \
--no-privileges \
--no-owner \
/tmp/restore.dump
# Restart all services
docker compose start sentari-api sentari-worker sentari-beat
Restore — OpenShift¶
DB_POD=$(oc get pod -l app=sentari-db -o jsonpath='{.items[0].metadata.name}')
oc cp ./sentari-backup-YYYYMMDD.dump "$DB_POD":/tmp/restore.dump
oc exec "$DB_POD" -- psql -U sentari -c "DROP DATABASE IF EXISTS sentari;"
oc exec "$DB_POD" -- psql -U sentari -c "CREATE DATABASE sentari;"
oc exec "$DB_POD" -- pg_restore -U sentari -d sentari --no-privileges --no-owner /tmp/restore.dump
Recommended backup schedule¶
| Frequency | Retention | Notes |
|---|---|---|
| Daily | 7 days | Minimum for compliance environments |
| Weekly | 4 weeks | Before any upgrade |
| Pre-upgrade | Keep until next upgrade | Taken manually before every Sentari update |
Store backups outside the Sentari server — on a network share, object storage, or tape — to protect against host failure.
5. Secret Rotation¶
Rotating secrets requires restarting the affected services. Plan a brief maintenance window.
JWT secret key (SENTARI_SECRET_KEY)¶
The JWT secret key signs all user session tokens. Rotating it immediately invalidates all active sessions — all logged-in users will be signed out.
Before rotating: this key may also protect the internal CA. Unless
SENTARI_CA_PASSPHRASE_KEYis set, the server falls back toSENTARI_SECRET_KEYas the passphrase that encrypts the internal CA's private key on disk. RotatingSENTARI_SECRET_KEYwithout handling the CA key first makes the CA key unreadable at the next startup — agent certificate issuance fails and/api/v1/agent/registerreturns 503.Choose one of:
- Recommended (one-time setup): set a dedicated
SENTARI_CA_PASSPHRASE_KEYand re-encrypt the CA key under it before the rotation (see "CA key passphrase" below). After that,SENTARI_SECRET_KEYrotations never touch the CA.- Otherwise: in the same maintenance window, re-encrypt the CA private key from the old value to the new one before restarting:
openssl pkey -in ca/ca.key -passin pass:<old SENTARI_SECRET_KEY> \ -aes256 -passout pass:<new SENTARI_SECRET_KEY> -out ca/ca.key.new \ && mv ca/ca.key.new ca/ca.key && chmod 600 ca/ca.key
Docker Compose:
- Generate a new key:
python3 -c "import secrets; print(secrets.token_hex(32))" - Update
SENTARI_SECRET_KEYindeploy/.env - Restart all three application services:
docker compose restart sentari-api sentari-worker sentari-beat
OpenShift:
- Update the Kubernetes Secret (or the value in
values.yamland re-runhelm upgrade) - Trigger a rolling restart:
oc rollout restart deployment/sentari-api deployment/sentari-worker deployment/sentari-beat
Inform users in advance that they will be signed out.
CA key passphrase (SENTARI_CA_PASSPHRASE_KEY)¶
The internal CA's private key (ca/ca.key) is encrypted at rest with a
passphrase. By default that passphrase falls back to SENTARI_SECRET_KEY;
setting a dedicated SENTARI_CA_PASSPHRASE_KEY isolates the CA from JWT-key
rotations and limits the blast radius if one secret leaks.
To adopt a dedicated CA passphrase on an existing deployment:
- Generate a key:
python3 -c "import secrets; print(secrets.token_hex(32))" - Re-encrypt the CA key from the current passphrase (the active
SENTARI_SECRET_KEY, unless a dedicated key was already set) to the new one:openssl pkey -in ca/ca.key -passin pass:<current passphrase> \ -aes256 -passout pass:<new SENTARI_CA_PASSPHRASE_KEY> -out ca/ca.key.new \ && mv ca/ca.key.new ca/ca.key && chmod 600 ca/ca.key - Set
SENTARI_CA_PASSPHRASE_KEYindeploy/.env(or the Kubernetes Secret) and restartsentari-api.
Rotating SENTARI_CA_PASSPHRASE_KEY later follows the same re-encrypt-then-
restart procedure. Take a backup of ca/ca.key before any re-encryption —
agents pin this CA, and a lost CA key means re-enrolling the entire fleet.
Database password (POSTGRES_PASSWORD)¶
Changing the database password is a two-step operation: update the password in PostgreSQL, then update the application configuration.
Docker Compose:
- Change the password inside PostgreSQL:
docker exec -it sentari-db psql -U sentari -c "ALTER USER sentari PASSWORD 'new-strong-password';" - Update
POSTGRES_PASSWORDindeploy/.env - Restart all services that connect to the database:
docker compose restart sentari-api sentari-worker sentari-beat
OpenShift: Update the Kubernetes Secret or Helm values, then run helm upgrade and restart the deployments.
Agent enrollment token (SENTARI_ENROLLMENT_TOKEN)¶
The enrollment token is checked only when an agent registers for the first time. Existing enrolled agents are not affected — they authenticate via their mTLS client certificates, which are issued at registration time.
Docker Compose:
- Update
SENTARI_ENROLLMENT_TOKENindeploy/.env - Restart only the API:
docker compose restart sentari-api - Distribute the new token to any devices that have not yet enrolled.
Rotate the enrollment token after the initial rollout to prevent unauthorised devices from registering.
Redis password (REDIS_PASSWORD)¶
- Update the password in Redis:
docker exec -it sentari-redis redis-cli CONFIG SET requirepass "new-redis-password" - Update
REDIS_PASSWORDindeploy/.env - Restart all services that connect to Redis:
docker compose restart sentari-api sentari-worker sentari-beat redis
Note: The
redis-cli CONFIG SETchange takes effect immediately but is lost on container restart unless Redis is also restarted with the new password in its startup command. The compose file passes the password via the--requirepassflag, so updating.envand restarting Redis is the correct sequence.
6. User Management¶
Bootstrap admin (first startup)¶
On first startup, Sentari creates an initial owner account if SENTARI_BOOTSTRAP_ADMIN_EMAIL and SENTARI_BOOTSTRAP_ADMIN_PASSWORD are set and no users exist in the database. This account has full administrative access.
The bootstrap process runs once. If users already exist, the bootstrap step is skipped silently. You can safely leave these variables set in production — they have no effect after the first startup.
Bootstrap admin password requirements: minimum 10 characters, at least one uppercase letter, one lowercase letter, one digit, and one special character.
Create additional users (dashboard)¶
Log in to the dashboard at https://<server-hostname> with the bootstrap admin credentials. Navigate to Settings → Users to create new accounts.
Available roles:
| Role | Access level |
|---|---|
viewer |
Read-only access to inventory, CVE, and compliance data |
analyst |
Viewer access plus audit log and compliance report access, alert acknowledgement, and CVE suppression |
admin |
Full access including policy management and user management |
owner |
Full access including bootstrap operations (one per deployment) |
LDAP / Active Directory integration¶
Set the following variables in deploy/.env (Docker Compose) or Helm values (OpenShift):
SENTARI_LDAP_URL=ldap://ad.example.com:389
SENTARI_LDAP_BASE_DN=DC=example,DC=com
SENTARI_LDAP_BIND_DN=CN=sentari-svc,OU=ServiceAccounts,DC=example,DC=com
SENTARI_LDAP_BIND_PASSWORD=<service-account-password>
After restarting sentari-api, create users in the dashboard with Identity Provider set to ldap. When those users log in, Sentari authenticates their password against the LDAP server using the service account to locate their entry, then re-authenticates with their own credentials.
If SENTARI_LDAP_URL is not set, the LDAP option returns HTTP 501. If the LDAP server is unreachable at login time, the response is HTTP 503 with an error message.
OIDC / SSO integration¶
Sentari supports any OIDC-compliant identity provider: Microsoft Entra ID (Azure AD), Keycloak, Ping Identity, Okta, and others.
SENTARI_OIDC_ISSUER_URL=https://login.microsoftonline.com/<tenant-id>/v2.0
SENTARI_OIDC_CLIENT_ID=<application-client-id>
SENTARI_OIDC_CLIENT_SECRET=<client-secret>
SENTARI_OIDC_SCOPES=openid email profile
SENTARI_OIDC_AUTO_CREATE_USERS=true
SENTARI_OIDC_DEFAULT_ROLE=viewer
# Optional: map an IdP claim to a Sentari role
SENTARI_OIDC_ROLE_CLAIM=roles
When SENTARI_OIDC_AUTO_CREATE_USERS=true, a Sentari account is created automatically on the user's first SSO login, assigned the role in SENTARI_OIDC_DEFAULT_ROLE. If SENTARI_OIDC_ROLE_CLAIM is set, the role is read from that claim in the ID token.
Multi-factor authentication (MFA / TOTP)¶
MFA is configured per user. After logging in, a user navigates to Profile → Enable MFA and scans the displayed QR code with an authenticator application (Microsoft Authenticator, Google Authenticator, or any TOTP-compatible app). Once verified, MFA is required at every subsequent login.
Administrators cannot enforce MFA globally via the current UI. To require MFA for a specific role, coordinate with users directly or set it as an onboarding requirement for your organisation.
7. Agent Management¶
Monitor enrolled devices¶
The Dashboard → Devices page lists all enrolled devices with their last seen timestamp, OS, and scan status. A device with a last_seen value older than your configured scan interval (default: 24 hours) indicates a connectivity or agent problem.
Agent configuration¶
The agent is configured via an INI-style file (agent.conf) on each endpoint. The key fields for connectivity:
[server]
url = https://<sentari-server-hostname>:8000
poll_interval = 900 ; seconds between policy/config polls
[scanner]
interval = 3600 ; seconds between scans
The agent's mTLS device certificate is obtained automatically during
enrollment and stored under the agent data directory
(/var/lib/sentari/certs on Linux/macOS, C:\ProgramData\Sentari\certs on
Windows) — there are no certificate paths to set by hand. The enrollment
token is supplied once via the --enroll-token CLI flag on first run
(see Agent install), not through agent.conf.
Rotate the enrollment token¶
See Section 5 — Agent enrollment token. Existing agents are not affected.
Check agent connectivity¶
From the dashboard, go to Devices and sort by Last Seen. Devices that have not checked in recently appear at the top when sorted ascending.
To investigate a specific device, check the agent log on that endpoint:
Linux:
journalctl -u sentari-agent -n 100
Windows:
Get-EventLog -LogName Application -Source sentari-agent -Newest 50
Common connectivity issues: - Firewall blocking outbound HTTPS (port 443 or 8000) from the endpoint to the server - Expired or revoked agent certificate (re-enrol the device) - Server hostname not resolvable from the endpoint
Re-enrol a device¶
If an agent's certificate has expired or been lost, delete the device record from Dashboard → Devices, then re-run the enrollment command on the endpoint with a valid enrollment token. A new certificate will be issued.
Enabling container-image scanning (agent-side only)¶
Agents can extend their inventory to include every Docker, Podman, and CRI-O container present on the endpoint. Each image's merged rootfs is walked through the same Python + JVM + system-package plugins that scan the host.
Not yet available end-to-end. The agent emits container signals today, but server-side persistence has not shipped: there are no container columns on the
packagestable, no container-origin attribution, and no dashboard filters. Enabling container scanning will increase scan upload size, but the Inventory/CVE pages do not split container-origin records out and the container fields are not stored server-side.
Container scanning is OFF BY DEFAULT. Enable it only if you have a specific reason to exercise the agent path.
Enable via config file:
[scanner]
containers = true
Or via environment variable (one-host trials):
SENTARI_SCAN_CONTAINERS=true sentari-agent --scan
Tuning knobs:
| Setting | Default | Meaning |
|---|---|---|
MaxContainersPerCycle |
100 | Hard cap on how many targets (images + containers) the agent sub-scans per scan cycle. |
PerContainerTimeout |
60s | Per-target timeout. Exceeded targets surface a ScanError, the loop continues with the next target. |
Supported runtimes: Docker (/var/lib/docker), Podman — both rootful and rootless, CRI-O.
Rollback. Flip containers = false in config and restart the agent. No schema or state cleanup required.
8. Dashboard Navigation¶
The dashboard is organised into three top-level sections in the sidebar: Fleet, Security, and Compliance. This section describes the Fleet area in detail, as it is the primary operational view for administrators managing enrolled devices.
Fleet section¶
The Fleet section contains six tabs:
| Tab | Description |
|---|---|
| Overview | Landing page. At-a-glance stats: total devices, active devices, packages inventoried, open CVE count, and recent alert summary. Start here during incident triage. |
| Devices | Paginated list of all enrolled devices. Columns include hostname, OS, Python version, last seen timestamp, and scan status. Click a device to view its full detail page including installed packages and CVE findings. |
| Packages | Fleet-wide package inventory. Search and filter across all packages on all devices. Use this view to answer "which devices have package X installed?" or to assess exposure for a newly disclosed CVE before correlation runs. |
| Runtime | Runtime version distribution across the fleet, covering Python, Node.js, and JDK. Shows a version breakdown chart and a trend view over time. Includes EOL (end-of-life) tracking — runtime versions past their upstream support date are flagged against endoflife.date. Supports Excel and CSV export of the full runtime inventory. |
| Scan History | Timeline of scan events per device. Use this to confirm that devices are scanning on schedule and to identify devices that have missed their expected scan window. |
| Diagnostics | Scan error analysis. Lists devices reporting scan errors, error types, and frequency. Use this tab first when investigating why package data appears stale or incomplete for a specific device. |
Runtime version tracking and export¶
The Runtime tab tracks Python, Node.js, and JDK versions across the fleet. This is relevant for NIS2 and DORA compliance: running a runtime version that has reached end-of-life means security patches are no longer issued by the upstream maintainer.
To export the runtime inventory:
- Navigate to Fleet → Runtime
- Click Export in the top-right corner of the page
- Select Excel (
.xlsx) or CSV depending on your reporting requirements
The export includes: device hostname, OS, runtime kind (Python / Node / JDK), interpreter or install path, version, EOL date (where applicable), and the date of the most recent scan.
Navigation reference¶
| Section | Page | Minimum role |
|---|---|---|
| Fleet | Overview | viewer |
| Fleet | Devices | viewer |
| Fleet | Packages | viewer |
| Fleet | Runtime | viewer |
| Fleet | Scan History | viewer |
| Fleet | Diagnostics | analyst |
| Security | CVE | viewer |
| Security | Alerts | viewer |
| Security | Policy | admin |
| Compliance | NIS2 / DORA dashboards | analyst |
| Admin | Settings | admin |
9. CVE Feed Configuration¶
Online mode (default)¶
In online mode, Sentari syncs CVE feeds into a local, ecosystem-keyed cache automatically. A daily background task (cve-feed-sync) runs at 02:00 UTC, scheduled by sentari-beat and executed by sentari-worker. Per-scan CVE correlation runs in the worker immediately after each agent scan upload and matches against the local cache offline — it does not query OSV live per request.
No configuration is required beyond network access from sentari-worker to https://api.osv.dev for the daily feed sync.
To also query the NVD (NIST National Vulnerability Database), set an NVD API key in the dashboard under Settings → CVE → NVD API Key. Without a key, NVD queries are rate-limited to a low threshold that may cause failures at scale.
Manual sync trigger¶
To run a CVE sync immediately without waiting for the scheduled task:
- Log in to the dashboard as an admin
- Navigate to Settings → CVE
- Click Trigger Sync
The sync runs asynchronously. Check Dashboard → CVE for updated correlation results within a few minutes.
Offline / air-gap mode¶
For deployments with no internet access, download an OSV bundle on a connected machine and transfer it to the server.
Download the bundle (on a connected machine):
curl -L https://osv-vulnerabilities.storage.googleapis.com/PyPI/all.zip \
-o osv-pypi-bundle.zip
Transfer the bundle to the Sentari server via your approved secure transfer method.
Configure the bundle path in the dashboard:
- Navigate to Settings → CVE → OSV Bundle Path
- Enter the full path to the extracted bundle file (accessible from the
sentari-workercontainer) - Click Save
- Click Trigger Sync
For Docker Compose deployments, mount the bundle into the worker container by adding a bind mount to docker-compose.yml (or an override file):
services:
sentari-worker:
volumes:
- /data/sentari/osv-bundle:/opt/sentari/osv-bundle:ro
Then set the bundle path in Settings to /opt/sentari/osv-bundle/osv-pypi-bundle.ndjson.
Runtime-EOL feed (air-gap)¶
The daily runtime-EOL sync (sync_runtime_eol_feeds, 03:00 UTC) normally
fetches end-of-life data from endoflife.date. For air-gapped deployments,
supply a pre-fetched NDJSON bundle instead and the sync reads it locally
rather than reaching the network.
- On an internet-connected host, fetch the
endoflife.datecycle data for the runtimes you track (python, node, jdk) and assemble it into the NDJSON bundle format the worker expects. - Transfer the bundle to the Sentari server via your approved secure
transfer method and make it readable from the
sentari-workercontainer (bind-mount it the same way as the OSV bundle above). - Set the
runtime_eol.bundle_pathkey insystem_configto the full in-container path of the bundle (via the dashboard Settings or the config API). When set, the sync loads the bundle on each run; when empty, it falls back to the onlineendoflife.datefetch.
10. Alert Configuration¶
Sentari generates alerts for CVE findings (critical/high severity) and policy violations. Alerts appear in the dashboard under Alerts. You can also route them to email and SIEM systems.
Email alerts¶
Configure SMTP in the dashboard under Settings → SMTP:
| Setting | Description |
|---|---|
| SMTP Host | Mail server hostname (e.g. smtp.yourorganisation.be) |
| SMTP Port | Typically 587 (STARTTLS) or 465 (TLS) |
| From address | Sender address (e.g. sentari-alerts@yourorganisation.be) |
| To address | Recipient — a shared mailbox or distribution list is recommended |
| Username | SMTP authentication username |
| Password | SMTP authentication password |
| Use TLS | Enable for STARTTLS (port 587) |
Email alerts are sent by sentari-worker via Celery tasks with three automatic retries on failure.
SIEM webhook¶
Configure a webhook URL in the dashboard under Settings → SIEM Webhook URL. Sentari sends a JSON POST request to this URL for each alert. This is compatible with Splunk HTTP Event Collector, Elastic SIEM, Microsoft Sentinel, and similar systems.
Test the alert pipeline¶
- Navigate to Policy → New Rule
- Create a rule that bans a package name that you know is installed on at least one device (for example, a test package)
- Click Evaluate Fleet
- A policy alert should appear in Alerts within seconds
- If email and SIEM are configured, check that the notification was received
If no alert appears, check sentari-worker logs for task errors:
docker compose logs --tail=100 sentari-worker
11. Proxy Configuration¶
In environments where all internet-bound traffic must pass through a forward proxy, configure the proxy in two places: at the system level (for tools inside containers) and at the application level (for Sentari's own HTTP client).
Docker Compose¶
In deploy/.env:
# System-level proxy (used by tools inside containers: curl, pip, etc.)
HTTP_PROXY=http://proxy.yourorganisation.be:3128
HTTPS_PROXY=http://proxy.yourorganisation.be:3128
NO_PROXY=sentari-db,sentari-redis,localhost,127.0.0.1
# Application-level proxy (used by Sentari for CVE feeds, SIEM webhooks)
SENTARI_HTTP_PROXY=http://proxy.yourorganisation.be:3128
SENTARI_HTTPS_PROXY=http://proxy.yourorganisation.be:3128
SENTARI_NO_PROXY=localhost,127.0.0.1
If your proxy requires authentication:
SENTARI_HTTPS_PROXY=http://username:password@proxy.yourorganisation.be:3128
Restart all application services after making changes.
OpenShift (Helm)¶
In values.yaml:
proxy:
httpProxy: "http://proxy.yourorganisation.be:3128"
httpsProxy: "http://proxy.yourorganisation.be:3128"
noProxy: "localhost,127.0.0.1,.cluster.local"
Run helm upgrade to apply. The chart automatically appends internal Kubernetes service names to noProxy to prevent internal traffic from being routed through the proxy.
Agent proxy¶
Configure the proxy in agent.conf on each endpoint:
[proxy]
https_proxy = http://proxy.yourorganisation.be:3128
no_proxy = localhost,127.0.0.1
Verify proxy connectivity¶
After configuration, trigger a CVE sync from Settings → CVE → Trigger Sync and monitor sentari-worker logs for connection errors:
docker compose logs -f sentari-worker | grep -i "proxy\|connect\|error"
A successful sync produces a log line similar to:
CVE feed sync completed: N packages correlated
12. Log Management¶
Docker Compose¶
View live logs for a service:
docker compose logs -f sentari-api
docker compose logs -f sentari-worker
docker compose logs -f sentari-beat
View the last N lines without following:
docker compose logs --tail=200 sentari-api
Logs from all services at once:
docker compose logs --tail=50
OpenShift¶
# Get the pod name first
oc get pods -l app=sentari-api
# Follow logs
oc logs -f <pod-name>
# Previous pod (if it has restarted)
oc logs --previous <pod-name>
Log level¶
The default log level is info. To increase verbosity for troubleshooting, set SENTARI_LOG_LEVEL=debug in the environment and restart the API container. This enables debug-level logging across the application without affecting security controls.
# Docker Compose
docker compose down && SENTARI_LOG_LEVEL=debug docker compose up -d
# Check logs
docker compose logs -f sentari-api
Note: Use
SENTARI_LOG_LEVEL=debugfor verbose troubleshooting logs. This only changes log verbosity — it does not disable any security controls.
What to look for¶
On startup:
| Log message | Meaning |
|---|---|
Bootstrap owner created: <email> |
First admin account created successfully |
CA initialisation failed |
Internal CA could not load or generate. Agent registration will fail. |
FATAL: SENTARI_SECRET_KEY is set to the insecure default |
SENTARI_SECRET_KEY was not set. The server will refuse to start in production mode. |
Startup license validation completed |
License verified successfully against the license server |
During operation:
| Log message | Meaning |
|---|---|
CVE feed sync completed |
Daily CVE sync ran successfully |
Health check: database unreachable |
API cannot reach TimescaleDB — check container status and network |
Health check: Redis unreachable |
API cannot reach Redis — check container status |
Task retry (in worker logs) |
A Celery task failed and is being retried. Check the error message that precedes it. |
LicenseMiddleware: failed to read license status |
Database connectivity issue during a write request |
13. Updating Sentari¶
Before every upgrade¶
- Read the release notes for the new version
- Back up the database (see Section 4)
- Note the current image tag in use (
VERSIONin.envor theimage.taginvalues.yaml)
Database migrations run automatically on startup via Alembic. You do not need to run migrations manually. If a migration fails, the service will log the error and exit — restore the database backup and contact support before retrying.
Docker Compose¶
-
Update
VERSIONindeploy/.envto the target release tag (e.g.1.2.0):# In deploy/.env VERSION=1.2.0 -
Pull the new images and restart:
cd deploy docker compose --env-file .env pull docker compose --env-file .env up -d -
Verify the update:
curl -s https://<server-hostname>/api/health docker compose ps -
Check the API logs for migration output:
docker compose logs sentari-api | grep -i "alembic\|migration\|Running upgrade"
OpenShift (Helm)¶
-
Update
image.taginvalues.yaml:image: tag: "1.2.0" -
Run
helm upgrade:helm upgrade sentari ./sentari -f values.yaml --namespace sentari -
Monitor the rollout:
oc rollout status deployment/sentari-api oc rollout status deployment/sentari-worker oc rollout status deployment/sentari-beat -
Verify:
curl -s https://<route-hostname>/api/health
Rolling back¶
If the update causes problems, roll back to the previous image tag.
Docker Compose: Set VERSION back to the previous tag and run docker compose up -d. If the new version ran migrations that are incompatible with the old version, restore the database backup instead of simply rolling back the image.
OpenShift:
oc rollout undo deployment/sentari-api
oc rollout undo deployment/sentari-worker
oc rollout undo deployment/sentari-beat
After rolling back, restore the database backup if any migrations ran against the schema.
14. Task Monitoring with Flower¶
Flower is a web UI for inspecting the Celery task queue — pending tasks, failures, per-task throughput, worker heartbeats. It is opt-in and not exposed to end users: Flower's admin REST API can revoke, replay, and introspect tasks, so it stays off by default and behind HTTP basic auth when enabled. There is deliberately no Ingress/Route — operators access it via kubectl port-forward or a local Docker Compose profile.
When you need it¶
- Triaging "my alert never arrived" — check whether
deliver_alertis backlogged or failing. - Post-incident forensics — which tasks fired during a CVE-sync storm, how long did each take.
- Verifying a rollout — after upgrading the worker image, watch success/failure rates before declaring done.
Enabling on Docker Compose¶
# Set a strong basic-auth credential in your .env
echo "SENTARI_FLOWER_BASIC_AUTH=admin:$(openssl rand -base64 24 | tr -d '=+/')" >> .env
# Flower is in the "ops" profile — not started by default
docker compose --profile ops up -d sentari-flower
# Open http://127.0.0.1:5555/flower/ and authenticate with the credential above.
Flower binds to 127.0.0.1:5555 by default. Do not set SENTARI_FLOWER_BIND=0.0.0.0 unless you've put a reverse proxy with its own auth in front.
Enabling on Helm / OpenShift¶
Add to your values override:
flower:
enabled: true
# Option 1 — let the chart manage the Secret (dev / simple deploys).
secrets:
flowerBasicAuth: "admin:longrandompasswordhere"
# Option 2 — use an externally-managed Secret (GitOps, vault-injected).
# The referenced Secret MUST include a key named ``flower-basic-auth``
# whose value is ``user:password``.
# secrets:
# existingSecretName: "sentari-shared-secrets"
Upgrade the release:
helm upgrade <release> deploy/helm/sentari -f values-override.yaml
Access pattern — the Service is ClusterIP-only, so tunnel from your workstation:
kubectl port-forward svc/<release>-flower 5555:5555
# then http://127.0.0.1:5555/flower/
What to look at first¶
- Active / Scheduled — are any tasks stuck? A Celery worker restart normally releases them.
- Failures — the red counter on the top bar. Click through to see the traceback.
- Workers — heartbeat status. A worker that stops beating is either OOMed or its network to Redis is broken.
- Broker — queue length per task. An unusual spike in
correlate_scanmeans CVE correlation is backlogged (check for the fleet-wide scan that just landed).
Disabling¶
Docker Compose: docker compose --profile ops down sentari-flower.
Helm: set flower.enabled: false and run helm upgrade. The Secret key stays in place but goes unused.
For agent installation, see Agent Install. For support, contact your Sentari account team.