Kubernetes Deployment (Helm)¶
Audience: Administrators deploying Sentari on Kubernetes
OpenShift users: See OpenShift Deployment instead.
Sentari includes a production-grade Helm chart that deploys the API server, Celery workers, Celery Beat scheduler, TimescaleDB, and Redis.
Prerequisites¶
- Helm 3.14+ installed
kubectlconfigured for your cluster- A namespace created for Sentari
- Persistent storage available in the cluster (standard StorageClass)
Step 1 — Create a namespace¶
kubectl create namespace sentari
Step 2 — Choose a deployment mode¶
Option A: Bundled database (evaluation / smaller deployments)¶
Deploys TimescaleDB and Redis as StatefulSets alongside the application. Equivalent to Docker Compose but on Kubernetes.
helm install sentari deploy/helm/sentari/ \
--namespace sentari \
--set secrets.secretKey="$(python3 -c 'import secrets; print(secrets.token_hex(32))')" \
--set secrets.dbPassword="$(python3 -c 'import secrets; print(secrets.token_hex(16))')" \
--set secrets.redisPassword="$(python3 -c 'import secrets; print(secrets.token_hex(16))')" \
--set secrets.enrollmentToken="$(python3 -c 'import secrets; print(secrets.token_hex(16))')" \
--set secrets.bootstrapAdminEmail="admin@yourorganisation.com" \
--set secrets.bootstrapAdminPassword="ChangeMe123!"
Option B: External managed database (recommended for production)¶
Use this when you have an existing managed TimescaleDB / PostgreSQL and Redis service.
helm install sentari deploy/helm/sentari/ \
--namespace sentari \
--set database.external=true \
--set redis.external=true \
--set secrets.databaseUrl="postgresql+psycopg2://sentari:<password>@<host>:5432/sentari" \
--set secrets.redisUrl="redis://:<password>@<host>:6379/0" \
--set secrets.secretKey="$(python3 -c 'import secrets; print(secrets.token_hex(32))')" \
--set secrets.enrollmentToken="$(python3 -c 'import secrets; print(secrets.token_hex(16))')" \
--set secrets.bootstrapAdminEmail="admin@yourorganisation.com" \
--set secrets.bootstrapAdminPassword="ChangeMe123!"
The chart creates the Kubernetes Secret for you from these values — no separate step required.
Enterprise secrets management (Vault, Sealed Secrets, Argo CD)¶
If your organisation requires secrets to never appear in Helm's release history
(Helm stores all --set values in the cluster and helm get values can expose
them), pre-create the Secret outside Helm and reference it by name:
# Create the Secret independently (e.g. via Vault, Sealed Secrets, or kubectl)
kubectl create secret generic sentari-credentials \
--namespace sentari \
--from-literal=database-url="postgresql+psycopg2://sentari:<password>@<host>:5432/sentari" \
--from-literal=redis-url="redis://:<password>@<host>:6379/0" \
--from-literal=secret-key="<64-hex-char JWT key>" \
--from-literal=enrollment-token="<enrollment token>" \
--from-literal=bootstrap-admin-email="admin@yourorganisation.com" \
--from-literal=bootstrap-admin-password="<password>"
# Install — no secrets in Helm values
helm install sentari deploy/helm/sentari/ \
--namespace sentari \
--set database.external=true \
--set redis.external=true \
--set secrets.existingSecretName=sentari-credentials
Option C: OCI registry (recommended for internet-connected deployments)¶
Install directly from the published Helm chart on the GitHub Container Registry. This avoids maintaining a local copy of the chart directory and always pulls the specified version.
Authenticate first:
# Authenticate to the Sentari OCI registry with your pull token
echo "PULL_TOKEN" | helm registry login ghcr.io -u sentari-customer --password-stdin
Install:
helm install sentari oci://ghcr.io/sentari-dev/sentari/charts/sentari \
--version 1.0.0 \
-f values.yaml \
--namespace sentari \
--create-namespace
Where values.yaml contains the secrets and configuration for your environment
(see Option A or B above for the required values). Keeping configuration in a
values file rather than --set flags avoids secrets appearing in shell history.
Upgrade to a new version:
helm upgrade sentari oci://ghcr.io/sentari-dev/sentari/charts/sentari \
--version <new-version> \
-f values.yaml \
--namespace sentari
Option D: Air-gapped / enterprise registry¶
If your cluster cannot reach the internet or requires images from an internal registry (Nexus, Artifactory, Harbor):
helm install sentari deploy/helm/sentari/ \
--namespace sentari \
--set image.registry=registry.corp.internal \
--set database.image.registry=registry.corp.internal \
--set redis.image.registry=registry.corp.internal \
... (other values as above)
Mirror these images to your internal registry before deploying:
ghcr.io/sentari-dev/sentari/server:<version>ghcr.io/sentari-dev/sentari/docs:<version>docker.io/timescale/timescaledb:2.14.2-pg16docker.io/redis:7.2-alpine
Step 3 — Verify the deployment¶
# Watch pods come up
kubectl get pods -n sentari -w
# Check the API health endpoint
kubectl port-forward svc/sentari-api 8000:8000 -n sentari &
curl http://localhost:8000/api/health
# Expected: {"status": "ok", "version": "..."}
License required for write operations: Without a valid license, the server boots in a degraded read-only mode — reads work, but writes return HTTP 402. Set
secrets.licenseKey(or includelicense-keyin your pre-created Secret) to activate full functionality.
Proxy configuration¶
If your cluster routes outbound traffic through a corporate proxy (non-transparent),
configure the proxy section in your Helm values. This is required for Sentari to
reach external CVE feeds, SIEM webhooks, or the license server.
When to configure¶
Set these values when pods cannot reach the internet directly — for example, in locked-down enterprise clusters with egress filtering.
Helm values¶
proxy:
httpProxy: "http://proxy.corp.internal:3128"
httpsProxy: "http://proxy.corp.internal:3128"
noProxy: "localhost,127.0.0.1,.cluster.local"
Or via --set flags:
helm install sentari deploy/helm/sentari/ \
--namespace sentari \
--set proxy.httpProxy="http://proxy.corp.internal:3128" \
--set proxy.httpsProxy="http://proxy.corp.internal:3128" \
... (other values)
The chart automatically appends release-prefixed service names (e.g. sentari-db,
sentari-redis) to NO_PROXY so that internal traffic is never sent through the proxy.
If your proxy requires authentication, include credentials in the URL:
proxy:
httpsProxy: "http://username:password@proxy.corp.internal:3128"
Verifying proxy connectivity¶
After deploying, log in to the dashboard, navigate to Settings, and trigger a CVE sync. Check the worker logs for confirmation:
kubectl logs -n sentari deployment/sentari-worker -f
Key Helm values reference¶
| Value | Default | Description |
|---|---|---|
secrets.existingSecretName |
"" |
Use a pre-created K8s Secret instead of chart values |
secrets.dbPassword |
"" |
PostgreSQL password (bundled DB mode) |
secrets.redisPassword |
"" |
Redis password (bundled Redis mode) |
secrets.secretKey |
"" |
JWT signing key (always required) |
secrets.licenseKey |
"" |
License key — without it writes return HTTP 402 |
database.external |
false |
Use external DB instead of bundled TimescaleDB |
redis.external |
false |
Use external Redis instead of bundled |
image.registry |
ghcr.io |
Registry for the server image (repository defaults to sentari-dev/sentari/server) |
database.image.registry |
docker.io |
Registry for the TimescaleDB image |
redis.image.registry |
docker.io |
Registry for the Redis image |
api.replicas |
1 |
Number of API pod replicas |
worker.replicas |
1 |
Number of Celery worker replicas |
proxy.httpProxy |
"" |
HTTP proxy URL for outbound connections |
proxy.httpsProxy |
"" |
HTTPS proxy URL for outbound connections |
proxy.noProxy |
"localhost,127.0.0.1,.cluster.local" |
Hosts to bypass the proxy |
Upgrading¶
helm upgrade sentari deploy/helm/sentari/ \
--namespace sentari \
--reuse-values \
--set image.tag=<new-version>
Database migrations run automatically on startup. Downgrading is not supported — always back up the database before upgrading.
Troubleshooting¶
Pods not starting¶
kubectl describe pod -n sentari <pod-name>
kubectl logs -n sentari <pod-name>
API does not become healthy¶
Check if database migrations succeeded:
kubectl logs -n sentari deployment/sentari-api | grep -i "migration\|alembic\|error"
Agent cannot connect to server¶
- Verify the server URL is reachable from the endpoint:
curl https://<server>:8000/api/health - Check the agent log:
/var/log/sentari/agent.log - If certificates are corrupted, re-enroll: delete
/var/lib/sentari/certs/and run with--enroll-token
No scans appearing in dashboard¶
- Confirm the agent service is running:
systemctl status sentari-agent - Check the agent log for upload errors
- Verify the enrollment token matches between agent config and server
For additional assistance, contact your Sentari representative or visit the support portal.