Skip to main content
The NeuralTrust Platform Helm chart can manage every required secret for you, or stay completely out of the way and let your existing secret management own the lifecycle. Pick the mode that fits your environment.
ModeFlag(s)BehaviorBest for
Auto-generated (default)global.autoGenerateSecrets: trueHelm creates and preserves secretsDev, staging, quick starts
Explicit valuesglobal.autoGenerateSecrets: true + values setYour values override auto-generationControlled environments
Pre-generatedglobal.preserveExistingSecrets: trueHelm never touches secretsProduction with Vault, Sealed Secrets, or External Secrets Operator

Required secrets per scenario

This is the single most useful table on the page. The chart creates these for you in default mode (auto-generated), or you create them yourself in pre-generated mode.
gcr-secret (the private image pull secret) is always pre-created manually — the chart never generates it. Run the kubectl create secret docker-registry gcr-secret … command from any per-cloud guide before installing.
ScenarioSecretAuto-generated when…
Alwaysgcr-secret (docker-registry)Never — you create it before install
Alwaysdata-plane-jwt-secretautoGenerateSecrets: true
TrustGate enabled (default)trustgate-secretsautoGenerateSecrets: true
Firewall enabled (default)firewall-secretsautoGenerateSecrets: true
In-cluster PostgreSQL (default)postgresql-secretsautoGenerateSecrets: true
In-cluster ClickHouse (default)clickhouseClickHouse subchart
Data Plane uses ClickHouse (always)clickhouse-secretsautoGenerateSecrets: true
Control Plane enabled (self-hosted)control-plane-secretsautoGenerateSecrets: true
TLS auto-generation on (default)neuraltrust-ingress-tlsglobal.ingress.tls.autoGenerate: true
Optional integrationsopenai-secrets, google-secrets, resend-secrets, huggingface-secretsOnly when corresponding values are set
For the on/off toggles that change which secrets are needed (in-cluster vs external Postgres, Kafka, Redis, ClickHouse; image registry; storage class; secret modes), see the Feature flags reference.

Auto-generated secrets (default)

No action required beyond gcr-secret. Deploy and all platform secrets are created automatically:
helm upgrade --install neuraltrust-platform \
  oci://europe-west1-docker.pkg.dev/neuraltrust-app-prod/helm-charts/neuraltrust-platform \
  --version <VERSION> \
  --namespace neuraltrust --create-namespace
SERVER_SECRET_KEY (TrustGate) and TRUSTGATE_JWT_SECRET (Control Plane) are always synchronized to the same value automatically. You can set either one explicitly and the other will follow.

How it works

  1. On first install, random 64-character alphanumeric values are generated for every required secret.
  2. On helm upgrade, existing values are read from the cluster via Helm lookup and reused — secrets are never overwritten.
  3. Explicit (non-empty) values in your values file always take priority and become the source of truth.

Overriding a specific secret

trustgate:
  global:
    env:
      SERVER_SECRET_KEY: "my-explicit-key"   # overrides auto-generation

Pre-generated secrets

For environments where Helm must not create or update secrets — e.g. Vault, Sealed Secrets, or External Secrets Operator owns the lifecycle:
global:
  autoGenerateSecrets: false
  preserveExistingSecrets: true   # Helm will NOT create or update secrets
When this flag is set, all required secrets must already exist in the namespace before deployment. Missing secrets cause workloads to fail.

Required secrets when preserveExistingSecrets: true

You must pre-create the secrets below before helm upgrade --install. Use create-secrets.sh as a starting template.
Kubernetes SecretRequired keysRequired for
gcr-secretdocker-registry typeAlways (pulling NeuralTrust images)
data-plane-jwt-secretDATA_PLANE_JWT_SECRETAlways
trustgate-secretsSERVER_SECRET_KEY, DATABASE_HOST, DATABASE_PORT, DATABASE_USER, DATABASE_PASSWORD, DATABASE_NAME, DATABASE_SSL_MODE, DATABASE_URL, NEURAL_TRUST_FIREWALL_URL, NEURAL_TRUST_FIREWALL_SECRET_KEYTrustGate enabled (default)
firewall-secretsJWT_SECRET (optional HUGGINGFACE_TOKEN)Always (Firewall is mandatory)
postgresql-secretsPOSTGRES_HOST, POSTGRES_PORT, POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB, DATABASE_URL, POSTGRES_PRISMA_URLIn-cluster or external Postgres
clickhouseadmin-passwordIn-cluster or external ClickHouse
clickhouse-secretsCLICKHOUSE_HOST, CLICKHOUSE_PORT, CLICKHOUSE_USER, CLICKHOUSE_DATABASEData Plane (always)
control-plane-secretsCONTROL_PLANE_JWT_SECRET, TRUSTGATE_JWT_SECRET (must equal TrustGate SERVER_SECRET_KEY), FIREWALL_JWT_SECRET (if Firewall enabled)Self-hosted only
neuraltrust-ingress-tlstls.crt, tls.keyIf global.ingress.tls.autoGenerate: false and using TLS
Optional (only if you use the corresponding integration): openai-secrets, google-secrets, resend-secrets, huggingface-secrets.
With preserveExistingSecrets: true, you are responsible for keeping SERVER_SECRET_KEY (in trustgate-secrets) and TRUSTGATE_JWT_SECRET (in control-plane-secrets) identical. The chart no longer enforces this for you.

Full secret reference

Data Plane

Kubernetes SecretKeyRequiredDescription
data-plane-jwt-secretDATA_PLANE_JWT_SECRETAuto-generatedJWT for Data Plane API auth
openai-secretsOPENAI_API_KEYNoOpenAI API key
google-secretsGOOGLE_API_KEYNoGoogle API key
resend-secretsRESEND_API_KEYNoResend email API key
huggingface-secretsHUGGINGFACE_TOKENNoHugging Face model access

Control Plane

Kubernetes SecretKeyRequiredDescription
control-plane-secretsCONTROL_PLANE_JWT_SECRETAuto-generatedJWT for Control Plane API auth
control-plane-secretsTRUSTGATE_JWT_SECRETAuto-generatedSynced with SERVER_SECRET_KEY
control-plane-secretsFIREWALL_JWT_SECRETIf Firewall enabledJWT shared with the firewall
control-plane-secretsMODEL_SCANNER_SECRETNoModel scanner service secret
control-plane-secretsOPENAI_API_KEYNoOpenAI API key
control-plane-secretsresend-api-keyNoResend API key
control-plane-secretsresend-alert-senderNoAlert notification email
control-plane-secretsresend-invite-senderNoInvitation email

PostgreSQL

Kubernetes SecretKeyRequiredDescription
postgresql-secretsPOSTGRES_HOSTIf pre-generatingDatabase hostname
postgresql-secretsPOSTGRES_PORTIf pre-generatingDatabase port
postgresql-secretsPOSTGRES_USERIf pre-generatingDatabase username
postgresql-secretsPOSTGRES_PASSWORDAuto-generatedDatabase password
postgresql-secretsPOSTGRES_DBIf pre-generatingDatabase name
postgresql-secretsDATABASE_URLIf pre-generatingConnection URL (URL-encoded)
postgresql-secretsPOSTGRES_PRISMA_URLIf pre-generatingPrisma-compatible URL

TrustGate

Kubernetes SecretKeyRequiredDescription
trustgate-secretsSERVER_SECRET_KEYAuto-generatedServer secret key (= TRUSTGATE_JWT_SECRET)
trustgate-secretsDATABASE_HOSTExternal DBPostgreSQL host
trustgate-secretsDATABASE_PORTExternal DBPostgreSQL port
trustgate-secretsDATABASE_USERExternal DBPostgreSQL user
trustgate-secretsDATABASE_PASSWORDAuto-generatedPostgreSQL password
trustgate-secretsDATABASE_NAMEExternal DBPostgreSQL database
trustgate-secretsDATABASE_URLExternal DBConnection URL
trustgate-secretsNEURAL_TRUST_FIREWALL_URLFirewall integrationFirewall base URL
trustgate-secretsNEURAL_TRUST_FIREWALL_SECRET_KEYFirewall integrationFirewall API key

Firewall

Created when neuraltrust-firewall.firewall.enabled: true — the default.
Kubernetes SecretKeyRequiredDescription
firewall-secretsJWT_SECRETYesShared with services calling the firewall
firewall-secretsHUGGINGFACE_TOKENNoHF token for model weights
Align controlPlane.secrets.firewallJwtSecret (FIREWALL_JWT_SECRET) with firewall-secrets.JWT_SECRET so the Control Plane validates firewall tokens correctly.

Docker registry

Kubernetes SecretTypeRequiredDescription
gcr-secretdocker-registryYesCredentials for NeuralTrust container images

Secret references in values

You can embed a secret value directly in values (less secure) or reference an existing secret (recommended).
neuraltrust-data-plane:
  dataPlane:
    secrets:
      dataPlaneJWTSecret: "your-secret-value"

TrustGate ↔ Firewall integration

TrustGate calls the NeuralTrust Firewall using two keys stored in trustgate-secrets:
trustgate:
  global:
    env:
      NEURAL_TRUST_FIREWALL_URL: "http://firewall:80"
      NEURAL_TRUST_FIREWALL_SECRET_KEY: "your-secret-key"
When global.autoGenerateSecrets: true, both keys are auto-populated. With preserveExistingSecrets: true, you must add them to a pre-created trustgate-secrets. After changing firewall secrets, restart TrustGate so pods pick up the new values:
kubectl rollout restart deployment/trustgate-control-plane -n neuraltrust
kubectl rollout restart deployment/trustgate-data-plane -n neuraltrust
kubectl rollout restart deployment/trustgate-actions -n neuraltrust

External Secrets Operator

Example syncing the Data Plane JWT from Vault:
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: data-plane-jwt-secret
  namespace: neuraltrust
spec:
  secretStoreRef:
    name: vault-backend
    kind: SecretStore
  target:
    name: data-plane-jwt-secret
  data:
    - secretKey: DATA_PLANE_JWT_SECRET
      remoteRef:
        key: neuraltrust/data-plane/jwt-secret
Apply equivalent ExternalSecret resources for every entry in the reference table you intend to manage externally, then deploy the chart with global.preserveExistingSecrets: true.

Pre-generation script

For environments that require all secrets created before deployment, the chart repo ships a helper script:
git clone --branch v<VERSION> --depth 1 https://github.com/NeuralTrust/neuraltrust-platform.git
cd neuraltrust-platform

# Interactive prompts
./create-secrets.sh --namespace neuraltrust

# Non-interactive via environment variables
export DATA_PLANE_JWT_SECRET="..."
export CONTROL_PLANE_JWT_SECRET="..."
export TRUSTGATE_JWT_SECRET="..."
export SERVER_SECRET_KEY="$TRUSTGATE_JWT_SECRET"   # must match
export POSTGRES_PASSWORD="..."
./create-secrets.sh --namespace neuraltrust

# Replace any existing secrets without prompting
./create-secrets.sh --namespace neuraltrust --replace-existing
After the script completes, deploy with preserveExistingSecrets: true.

Security best practices

  1. Default to auto-generation. It’s the safest starting point and the chart preserves existing secrets on every upgrade.
  2. Use external secret management for production. Vault, Sealed Secrets, or External Secrets Operator give you rotation, audit, and centralized control.
  3. Never commit secret values to git. Don’t store real values in version-controlled values files; use --set or pre-created secret references.
  4. Rotate secrets regularly — especially JWT secrets. Restart the affected workloads after each rotation.
  5. Restrict access with RBAC. Limit who can get/list/watch Kubernetes Secrets in the neuraltrust namespace.

Troubleshooting

Secret not found

kubectl get secret <secret-name> -n neuraltrust
kubectl get secrets -n neuraltrust
kubectl get secret <secret-name> -n neuraltrust -o yaml

TrustGate firewall env vars not updating

TrustGate reads NEURAL_TRUST_FIREWALL_URL and NEURAL_TRUST_FIREWALL_SECRET_KEY from trustgate-secrets at pod startup. After helm upgrade, restart TrustGate deployments to reload them (see TrustGate ↔ Firewall integration above).

Wrong secret value

kubectl patch secret <secret-name> -n neuraltrust \
  --type='json' \
  -p='[{"op": "replace", "path": "/data/<key>", "value": "<base64-encoded-value>"}]'

Secret format issues

When creating secrets manually:
  • URL-encode passwords inside DATABASE_URL.
  • Base64-encode all values stored in Kubernetes Secrets.
  • Avoid trailing newlines or whitespace — they break authentication silently.