Documentation Index
Fetch the complete documentation index at: https://docs.neuraltrust.ai/llms.txt
Use this file to discover all available pages before exploring further.
This page is the single source of truth for the feature flags that change what the chart deploys. Use it when you need to decide between in-cluster and external infrastructure, mirror images, customize storage, or pre-create secrets.
For end-to-end install walkthroughs, see the per-cloud guides. For the deployment-model decision (hybrid vs self-hosted), see Deployment models.
Component on/off toggles
The chart’s primary enabled flags decide which subcharts are rendered.
| Component | Values key | Default | Notes |
|---|
| Data Plane | neuraltrust-data-plane.dataPlane.enabled | true | API + worker + Kafka Connect |
| Control Plane | neuraltrust-control-plane.controlPlane.enabled | false | Off = hybrid (CP on SaaS). On = self-hosted. |
| TrustGate | trustgate.enabled | true | admin + gateway + actions + Redis |
| Firewall | neuraltrust-firewall.firewall.enabled | true | gateway + 5 workers — always on in supported topologies; the choice is CPU vs GPU workers (see Firewall deployment) |
| SIEM Connectors | neuraltrust-siem-connectors.siemConnectors.enabled | false | Off — opt-in |
| Watchdog (self-healing) | neuraltrust-watchdog.enabled | false | Off — opt-in |
| OpenTelemetry Collector | global.observability.enabled | false | Off — opt-in |
A zero-config helm install deploys Data Plane + TrustGate + Firewall + in-cluster infra, without Control Plane — i.e. a hybrid-shaped stack ready for SaaS enrollment.
PostgreSQL — in-cluster or external
PostgreSQL stores:
- Control Plane schema (RBAC, integrations, dashboards) — only when CP is enabled
- TrustGate schema (gateways, routes, plugins) — when TrustGate is enabled
- Customer prompts and responses are never stored here — those go to ClickHouse.
In-cluster (default)
| Values key | Default |
|---|
neuraltrust-control-plane.infrastructure.postgresql.deploy | true |
neuraltrust-control-plane.controlPlane.components.postgresql.persistence.storageClass | "" (cluster default) |
neuraltrust-control-plane.controlPlane.components.postgresql.secrets.user | neuraltrust |
neuraltrust-control-plane.controlPlane.components.postgresql.secrets.password | "" → auto-generated 32-char |
neuraltrust-control-plane.controlPlane.components.postgresql.secrets.database | neuraltrust |
neuraltrust-control-plane.controlPlane.components.postgresql.secrets.host | control-plane-postgresql |
The in-cluster Postgres deploys regardless of controlPlane.enabled — TrustGate uses the same instance even in hybrid mode.
External (managed service)
neuraltrust-control-plane:
infrastructure:
postgresql:
deploy: false
controlPlane:
components:
postgresql:
secrets:
name: "postgresql-secrets"
host: "<external-host>"
port: "5432"
user: "neuraltrust"
password: "<password>" # or pre-create the secret
database: "neuraltrust"
trustgate:
global:
env:
DATABASE_HOST: "<external-host>"
DATABASE_PORT: "5432"
DATABASE_USER: "trustgate"
DATABASE_PASSWORD: "<password>"
DATABASE_NAME: "trustgate"
DATABASE_SSL_MODE: "require" # "disable" only for in-cluster
Required databases & users when external
Create these before running helm upgrade. Most managed services let you create the cluster admin then run the CREATE DATABASE / CREATE USER statements below.
| Database | User | Required when | Permissions |
|---|
neuraltrust | neuraltrust | Always | ALL PRIVILEGES ON DATABASE neuraltrust — Prisma migrations need DDL on public schema |
trustgate | trustgate | trustgate.enabled: true | ALL PRIVILEGES ON DATABASE trustgate, schema DDL |
Recommended SQL:
-- as the cluster admin
CREATE USER neuraltrust WITH PASSWORD '<strong-password>';
CREATE DATABASE neuraltrust OWNER neuraltrust;
GRANT ALL PRIVILEGES ON DATABASE neuraltrust TO neuraltrust;
CREATE USER trustgate WITH PASSWORD '<strong-password>';
CREATE DATABASE trustgate OWNER trustgate;
GRANT ALL PRIVILEGES ON DATABASE trustgate TO trustgate;
-- connect to each DB and grant on public schema (Postgres 15+)
\c neuraltrust
GRANT ALL ON SCHEMA public TO neuraltrust;
\c trustgate
GRANT ALL ON SCHEMA public TO trustgate;
The chart’s trustgate-postgresql-init Job can create the trustgate database/user automatically if the credentials in postgresql-secrets have CREATE USER and CREATE DATABASE rights on the external instance. Most managed Postgres services restrict these — pre-creating the DB/user is the safer path.
Cloud-managed Postgres notes
| Provider | Notes |
|---|
| AWS RDS / Aurora PostgreSQL | Set DATABASE_SSL_MODE: require. Use IRSA for password rotation via Secrets Manager if desired. |
| Azure Database for PostgreSQL Flexible Server | Set DATABASE_SSL_MODE: require. Use private endpoint for VNet-internal access. |
| Cloud SQL for PostgreSQL | Use Private IP. Authorize the GKE subnet. Set DATABASE_SSL_MODE: require. |
| CloudNativePG (on-prem) | Run CREATE DATABASE … OWNER from a privileged session; chart-side init Job works if the bootstrap user has CREATE rights. |
Redis — in-cluster or external
TrustGate uses Redis for caching gateways, plugins, and rate-limit state. Data Plane and Control Plane do not use Redis.
In-cluster (default)
Redis ships bundled with the TrustGate subchart as trustgate-redis (single StatefulSet, 10 GiB PVC). No additional configuration needed.
| Values key | Default |
|---|
trustgate.redis.replica.replicaCount | 1 |
trustgate.redis.image.tag | 7.2.0-v20 |
trustgate.redis.bind | 0.0.0.0 -:: (dual-bind) |
External Redis
Point TrustGate at a managed Redis (ElastiCache, Memorystore, Azure Cache for Redis) by setting env vars:
trustgate:
redis:
enabled: false # config-only flag (see caveat below)
global:
env:
REDIS_HOST: "<external-host>"
REDIS_PORT: "6379"
REDIS_PASSWORD: "<password>" # required for managed Redis
REDIS_DB: "0"
Current chart caveat: setting trustgate.redis.enabled: false changes the TrustGate env vars to point external, but the in-cluster trustgate-redis StatefulSet still deploys (the template isn’t guarded on the flag). The unused pod is small (~500m / 1 GiB) but it does consume cluster resources. A fix is planned for an upcoming chart release; until then, expect the in-cluster Redis pod to exist even when you target an external one.
Kafka — in-cluster or external
Kafka is the event backbone between TrustGate, Data Plane API, the Data Plane worker, Kafka Connect, and the Control Plane scheduler (audit events).
In-cluster (default)
| Values key | Default |
|---|
infrastructure.kafka.deploy | true |
kafka.replicaCount | 1 |
kafka.persistence.size | 10Gi |
In-cluster Kafka has no auth — ClusterIP-only and never exposed outside the namespace.
External Kafka
infrastructure:
kafka:
deploy: false
external:
bootstrapServers: "kafka.example.com:9092"
# 'brokers' (a list) is also accepted and joined with commas
This sets the bootstrapServers for components that read from infrastructure.kafka.external.*. Per-component Kafka env vars must also be overridden for components that use a hardcoded default (see below).
Authentication for external Kafka
The chart does not wire SASL/SCRAM/mTLS automatically. The infrastructure.kafka.external.secretName / secretKey keys exist in values.yaml but are not consumed by templates today. Use extraEnv on each Kafka consumer to inject the auth env vars yourself.
neuraltrust-data-plane:
dataPlane:
components:
api:
extraEnv:
- name: KAFKA_BOOTSTRAP_SERVERS
value: "kafka.example.com:9093"
- name: KAFKA_SECURITY_PROTOCOL
value: "SASL_SSL"
- name: KAFKA_SASL_MECHANISM
value: "SCRAM-SHA-512"
- name: KAFKA_SASL_USERNAME
valueFrom:
secretKeyRef: { name: kafka-auth, key: username }
- name: KAFKA_SASL_PASSWORD
valueFrom:
secretKeyRef: { name: kafka-auth, key: password }
worker:
extraEnv: *kafka-auth-env # same as api.extraEnv
kafka:
connect:
bootstrapServers: "kafka.example.com:9093"
Pre-create the kafka-auth Secret in your release namespace.
Per-component Kafka overrides
| Component | Hardcoded default | Override path |
|---|
| Data Plane API | KAFKA_BOOTSTRAP_SERVERS=kafka:9092 | neuraltrust-data-plane.dataPlane.components.api.extraEnv |
| Data Plane Worker | KAFKA_BOOTSTRAP_SERVERS=kafka:9092 | neuraltrust-data-plane.dataPlane.components.worker.extraEnv |
| Kafka Connect | bootstrapServers=kafka:9092 | neuraltrust-data-plane.dataPlane.components.kafka.connect.bootstrapServers |
| Control Plane Scheduler | KAFKA_BROKERS=kafka:9092, KAFKA_TOPIC=audit_events | neuraltrust-control-plane.controlPlane.components.scheduler.config.kafkaBrokers / .kafkaTopic |
| Control Plane App | KAFKA_HOST=kafka, KAFKA_PORT=9092 | neuraltrust-control-plane.controlPlane.components.app.config.kafkaHost / .kafkaPort |
Cloud-managed Kafka notes
| Provider | Notes |
|---|
| AWS MSK (IAM) | Use IRSA + aws-msk-iam-sasl-signer-java on consumers — currently requires custom image; chart does not bundle it. |
| Confluent Cloud | SASL/PLAIN over TLS; inject KAFKA_SECURITY_PROTOCOL=SASL_SSL and KAFKA_SASL_MECHANISM=PLAIN plus API key/secret. |
| Azure Event Hubs (Kafka surface) | SASL/PLAIN over TLS on port 9093; username $ConnectionString, password = Event Hubs connection string. Inject via extraEnv. |
ClickHouse — in-cluster or external
ClickHouse is the analytics database for the Data Plane — prompts, responses, traces, evals, metrics. All customer telemetry lives here.
In-cluster (default)
| Values key | Default |
|---|
infrastructure.clickhouse.deploy | true |
clickhouse.auth.username | neuraltrust |
clickhouse.auth.password | "" → auto-generated 32-char in Secret clickhouse / key admin-password |
clickhouse.auth.database | neuraltrust |
clickhouse.persistence.size | 50Gi |
External ClickHouse
infrastructure:
clickhouse:
deploy: false
external:
host: "<external-host>"
port: "8123" # HTTP port; "8443" for ClickHouse Cloud
user: "neuraltrust"
password: "" # use --set or pre-created secret
database: "neuraltrust"
secretName: "clickhouse"
secretKey: "admin-password"
neuraltrust-data-plane:
dataPlane:
components:
clickhouse:
enabled: true # keep true to render clickhouse-secrets + migrations Job
host: "<external-host>"
port: "8123"
user: "neuraltrust"
database: "neuraltrust"
Required ClickHouse Cloud caveat
The Data Plane API runs an init container that connects to ClickHouse on native port 9000 to apply migrations — this is hardcoded in the chart today. ClickHouse Cloud exposes native on port 9440 (TLS) instead, so the migrations init container fails out of the box against Cloud.Workarounds: (a) pre-provision the schema yourself and disable the init container, (b) run a port-translating proxy that exposes 9000→9440 inside your VPC, or (c) deploy ClickHouse in-cluster instead. A configurable native port is on the chart roadmap.
Required databases & users when external
| Database | User | Permissions |
|---|
neuraltrust | neuraltrust | GRANT ALL ON neuraltrust.* TO neuraltrust |
The clickhouse-migrations initContainer applies the schema automatically the first time the Data Plane API starts.
Image registry — NeuralTrust GCR or your internal mirror
By default, every NeuralTrust image is pulled from
europe-west1-docker.pkg.dev/neuraltrust-app-prod/nt-docker/<name>.
Default (NeuralTrust GCR)
Pre-create the gcr-secret image pull secret in your release namespace. The chart does not create this secret — you have to do it yourself with the JSON key NeuralTrust provides:
kubectl create secret docker-registry gcr-secret \
--docker-server=europe-west1-docker.pkg.dev \
--docker-username=_json_key \
--docker-password="$(cat path/to/gcr-keys.json)" \
[email protected] \
-n neuraltrust
The chart references this secret from every subchart’s imagePullSecrets (defaults: ["gcr-secret"]).
Internal mirror (one override)
global:
imageRegistry: "registry.internal.example.com/neuraltrust"
The chart’s image helper strips the default GCP prefix and prepends yours — so
europe-west1-docker.pkg.dev/neuraltrust-app-prod/nt-docker/control-plane-api
becomes
registry.internal.example.com/neuraltrust/control-plane-api
with no other override required.
Three escalating customization levels
| You mirror images with… | What to override |
|---|
| Same short names, same tags | only global.imageRegistry |
| Same short names, custom tags | global.imageRegistry + per-component image.tag |
Renamed paths (e.g. my-registry.corp/cp-api) | global.imageRegistry + per-component image.repository + image.tag |
Per-component override paths:
| Path | Component |
|---|
neuraltrust-control-plane.controlPlane.components.{api,app,scheduler,postgresql}.image.{repository,tag} | Control Plane |
neuraltrust-data-plane.dataPlane.components.{api,worker}.image.{repository,tag} | Data Plane |
neuraltrust-data-plane.dataPlane.components.kafka.connect.image.{repository,tag} | Kafka Connect |
neuraltrust-firewall.firewall.gateway.image.* / workerDefaults.image.* | Firewall |
trustgate.global.image.{image,tag} | TrustGate |
trustgate.redis.image.{repository,tag} | Redis |
clickhouse.image.{repository,tag} | ClickHouse |
kafka.image.{repository,tag} | Kafka |
Mirroring for air-gapped installs
helm template neuraltrust-platform \
oci://europe-west1-docker.pkg.dev/neuraltrust-app-prod/helm-charts/neuraltrust-platform \
--version <VERSION> \
-f my-values.yaml \
| yq '.. | select(has("image")) | .image' \
| sort -u
Mirror each image to your internal registry with crane, skopeo, or docker pull/push, then set global.imageRegistry. Verify rendered images:
helm template . -f my-values.yaml | grep -E '^\s+image:' | sort -u
Storage class — cluster default or explicit
PVCs are created for ClickHouse, Kafka, PostgreSQL, Redis, and the optional OpenTelemetry collector buffer.
Cluster default (default behavior)
| Values key | Default |
|---|
global.storageClass | "" |
When empty, the chart omits storageClassName from PVC specs, which falls back to the cluster’s default StorageClass. Confirm one exists:
kubectl get storageclass
# default class is marked with (default)
Explicit, cluster-wide
global:
storageClass: "pd-balanced" # GKE example
# storageClass: "gp3" # AWS EKS
# storageClass: "managed-csi-premium" # Azure AKS
# storageClass: "longhorn" # bare metal
Per-component overrides
| Component | Values key | Recommended for prod |
|---|
| ClickHouse | clickhouse.persistence.storageClass | SSD-backed (pd-ssd, io2, managed-csi-premium) for high-throughput |
| Kafka | kafka.persistence.storageClass | SSD-backed |
| PostgreSQL | neuraltrust-control-plane.controlPlane.components.postgresql.persistence.storageClass | SSD-backed |
| Redis (TrustGate) | trustgate.global.storageClass (inherits umbrella global.storageClass) | Default |
| OTel collector buffer (optional) | global.observability.collector.bufferPVC.storageClass | Default |
Per-component override wins over global.storageClass. Empty per-component = inherit global.storageClass = inherit cluster default.
Secrets — auto-generated, explicit, or pre-created
Two top-level flags control how the chart manages secrets.
| Values key | Default | Behavior |
|---|
global.autoGenerateSecrets | true | Chart generates random secrets on first install; reuses existing on upgrade. |
global.preserveExistingSecrets | false | When true, all secret templates are skipped (parent + subcharts). You must pre-create everything. |
Use autoGenerateSecrets: true for quick installs and dev/test. Use preserveExistingSecrets: true when you manage secrets with Vault, Sealed Secrets, External Secrets Operator, SOPS, or any other secret manager.
Required secrets per scenario
Always required, regardless of mode:
| Secret | Type | Created by |
|---|
gcr-secret | docker-registry | You (manual, pre-install) |
Auto-generated by default (when autoGenerateSecrets: true):
| Scenario | Secret | Keys |
|---|
| Hybrid (CP off) | data-plane-jwt-secret | DATA_PLANE_JWT_SECRET |
| trustgate-secrets | DATABASE_HOST, DATABASE_PORT, DATABASE_USER, DATABASE_PASSWORD, DATABASE_NAME, DATABASE_SSL_MODE, DATABASE_URL, SERVER_SECRET_KEY, NEURAL_TRUST_FIREWALL_URL, NEURAL_TRUST_FIREWALL_SECRET_KEY |
| firewall-secrets | JWT_SECRET (optional HUGGINGFACE_TOKEN) |
| postgresql-secrets | POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB, POSTGRES_HOST, POSTGRES_PORT, DATABASE_URL, POSTGRES_PRISMA_URL |
| clickhouse | admin-password |
| clickhouse-secrets | CLICKHOUSE_HOST, CLICKHOUSE_PORT, CLICKHOUSE_USER, CLICKHOUSE_DATABASE |
| neuraltrust-ingress-tls (if global.ingress.tls.autoGenerate: true) | tls.crt, tls.key |
| Self-hosted (adds CP) | control-plane-secrets | CONTROL_PLANE_JWT_SECRET, TRUSTGATE_JWT_SECRET, FIREWALL_API_URL (optional Resend / LLM keys) |
| Optional (only if non-empty values) | openai-secrets, google-secrets, resend-secrets, huggingface-secrets | provider-specific |
Pre-creating secrets (preserveExistingSecrets: true)
Required for: production setups with external secret managers, GitOps flows where chart-rendered Secrets cause drift, or air-gapped environments where you bake secrets into your golden state.
global:
preserveExistingSecrets: true # chart will not render any secret templates
You must pre-create the secrets above before helm upgrade --install. The chart ships create-secrets.sh and SECRETS.md as a starting template.
For per-secret keys and a worked example, see Secrets management.
Topology cheat sheet
A condensed view of the toggles people set on day one:
global:
platform: "gcp" # aws | gcp | azure | openshift | kubernetes
domain: "platform.example.com"
storageClass: "" # "" = cluster default
imageRegistry: "" # "" = NeuralTrust GCR
autoGenerateSecrets: true # false + preserveExistingSecrets for prod
preserveExistingSecrets: false
neuraltrust-control-plane:
controlPlane:
enabled: false # true = self-hosted
infrastructure:
postgresql:
deploy: true # false = external
neuraltrust-data-plane:
dataPlane:
enabled: true
trustgate:
enabled: true
redis:
enabled: true # false + REDIS_HOST env = external (see Redis caveat)
neuraltrust-firewall:
firewall:
enabled: true # always on in supported topologies (CPU or GPU workers)
infrastructure:
clickhouse:
deploy: true # false = external
kafka:
deploy: true # false = external