Skip to content

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

  1. Service Overview
  2. Health Checks
  3. Starting and Stopping
  4. Database Backup and Restore
  5. Secret Rotation
  6. User Management
  7. Agent Management
  8. Dashboard Navigation
  9. CVE Feed Configuration
  10. Alert Configuration
  11. Proxy Configuration
  12. Log Management
  13. Updating Sentari
  14. 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-beat deployment is always set to exactly one replica. Do not scale it above 1. The Helm chart's values.yaml does 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, and sentari-beat before 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
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_KEY is set, the server falls back to SENTARI_SECRET_KEY as the passphrase that encrypts the internal CA's private key on disk. Rotating SENTARI_SECRET_KEY without handling the CA key first makes the CA key unreadable at the next startup — agent certificate issuance fails and /api/v1/agent/register returns 503.

Choose one of:

  • Recommended (one-time setup): set a dedicated SENTARI_CA_PASSPHRASE_KEY and re-encrypt the CA key under it before the rotation (see "CA key passphrase" below). After that, SENTARI_SECRET_KEY rotations 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:

  1. Generate a new key: python3 -c "import secrets; print(secrets.token_hex(32))"
  2. Update SENTARI_SECRET_KEY in deploy/.env
  3. Restart all three application services:
    docker compose restart sentari-api sentari-worker sentari-beat
    

OpenShift:

  1. Update the Kubernetes Secret (or the value in values.yaml and re-run helm upgrade)
  2. 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:

  1. Generate a key: python3 -c "import secrets; print(secrets.token_hex(32))"
  2. 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
    
  3. Set SENTARI_CA_PASSPHRASE_KEY in deploy/.env (or the Kubernetes Secret) and restart sentari-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:

  1. Change the password inside PostgreSQL:
    docker exec -it sentari-db psql -U sentari -c "ALTER USER sentari PASSWORD 'new-strong-password';"
    
  2. Update POSTGRES_PASSWORD in deploy/.env
  3. 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:

  1. Update SENTARI_ENROLLMENT_TOKEN in deploy/.env
  2. Restart only the API:
    docker compose restart sentari-api
    
  3. 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)

  1. Update the password in Redis:
    docker exec -it sentari-redis redis-cli CONFIG SET requirepass "new-redis-password"
    
  2. Update REDIS_PASSWORD in deploy/.env
  3. Restart all services that connect to Redis:
    docker compose restart sentari-api sentari-worker sentari-beat redis
    

Note: The redis-cli CONFIG SET change 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 --requirepass flag, so updating .env and 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 packages table, 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:

  1. Navigate to Fleet → Runtime
  2. Click Export in the top-right corner of the page
  3. 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.

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:

  1. Log in to the dashboard as an admin
  2. Navigate to Settings → CVE
  3. 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:

  1. Navigate to Settings → CVE → OSV Bundle Path
  2. Enter the full path to the extracted bundle file (accessible from the sentari-worker container)
  3. Click Save
  4. 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.

  1. On an internet-connected host, fetch the endoflife.date cycle data for the runtimes you track (python, node, jdk) and assemble it into the NDJSON bundle format the worker expects.
  2. Transfer the bundle to the Sentari server via your approved secure transfer method and make it readable from the sentari-worker container (bind-mount it the same way as the OSV bundle above).
  3. Set the runtime_eol.bundle_path key in system_config to 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 online endoflife.date fetch.

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

  1. Navigate to Policy → New Rule
  2. Create a rule that bans a package name that you know is installed on at least one device (for example, a test package)
  3. Click Evaluate Fleet
  4. A policy alert should appear in Alerts within seconds
  5. 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=debug for 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

  1. Read the release notes for the new version
  2. Back up the database (see Section 4)
  3. Note the current image tag in use (VERSION in .env or the image.tag in values.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

  1. Update VERSION in deploy/.env to the target release tag (e.g. 1.2.0):

    # In deploy/.env
    VERSION=1.2.0
    

  2. Pull the new images and restart:

    cd deploy
    docker compose --env-file .env pull
    docker compose --env-file .env up -d
    

  3. Verify the update:

    curl -s https://<server-hostname>/api/health
    docker compose ps
    

  4. Check the API logs for migration output:

    docker compose logs sentari-api | grep -i "alembic\|migration\|Running upgrade"
    

OpenShift (Helm)

  1. Update image.tag in values.yaml:

    image:
      tag: "1.2.0"
    

  2. Run helm upgrade:

    helm upgrade sentari ./sentari -f values.yaml --namespace sentari
    

  3. Monitor the rollout:

    oc rollout status deployment/sentari-api
    oc rollout status deployment/sentari-worker
    oc rollout status deployment/sentari-beat
    

  4. 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_alert is 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_scan means 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.