Architecture
- Configuration comes from PostgreSQL, not from a config-sync stream. Each product’s data plane reads its configuration directly from that product’s database, which its own in-cluster control plane owns and migrates.
- DataCore replaces DataAgent. There is no SaaS pushing queries over an
outbound stream, so an in-cluster HTTP API serves tenant-scoped queries from
ClickHouse instead, plus deployment metadata from its own
datacoredatabase.
What runs
A complete platform install. Every table below is deployed by the same umbrella chart in one release.Request path
Control plane
Analytics
global.products is ignored in External mode — the full stack always deploys.
DataAgent does not run at all.
Prerequisites
- A Kubernetes cluster with an ingress controller, and Helm 3.8+
- Roughly 4–5 workers at 8 vCPU / 16–32 GiB — the console and analytics stack on top of the data path. See Capacity
- A base domain you can point at the cluster ingress
- PostgreSQL, Redis, and ClickHouse — see Datastores
- The registry key NeuralTrust sends you, or a mirror of the images for an air-gapped cluster — Container images
- An SMTP or email provider, for console invitations and password resets
Decide the console hostname first
APP_URL and NEXTAUTH_URL drive email links, SSO redirects, and OAuth
callbacks. Changing them later invalidates in-flight invitations and breaks
configured SSO redirect URIs, so pick the hostname before installing.
One limitation to know about: a handful of console values are NEXT_PUBLIC_*,
which Next.js inlines into the JavaScript bundle at image build time. Helm
cannot set them. In practice two matter, and both are cosmetic rather than
blocking — the SCIM tenant URL shown to administrators and the meta.location
returned to your IdP will show app.neuraltrust.ai. Enter your own host in your
IdP rather than copying what the screen displays.
Network
External needs no outbound connectivity to NeuralTrust. There are no hostnames or IPs to allowlist and no inbound source IP to admit. What you do need reachable:
Inbound, clients reach the TrustGate LLM and MCP hosts, and your operators reach
the console — see Public routing.
Air-gapped installs mirror the images into an internal registry and set
global.imageRegistry. Two collector images are pinned in full and need separate
overrides — see
Mirror to your own registry.Datastores
Recommended for production: managed PostgreSQL and Redis outside the cluster, with ClickHouse in-cluster. The chart defaults to in-cluster PostgreSQL and Redis (deploy: true) so a proof of concept can helm install
without provisioning anything first — that is convenience, not the production
shape.
ClickHouse is mandatory here, unlike a Hybrid data plane where analytics stay on
the hosted path. Nearly everyone runs the in-cluster subchart, because it is
telemetry storage the platform owns end to end.
Each service owns its own PostgreSQL database and migrations. The
endpoint is shared: since chart 2.6.0 an empty per-service
host, port or
sslMode (and Redis host / port / username / tls) inherits from
global.postgresql / global.redis before falling back to the in-cluster
Service names. Declare a managed datastore once on the global blocks; add a
per-service database: / redis: block only to send one service somewhere else.
In-cluster PostgreSQL (proof of concept)
Leaveglobal.postgresql.deploy: true. From chart 2.7.0 a
control-plane-postgresql-bootstrap Job creates each service role and database
using the password already in that service’s Secret, so you run no SQL by hand.
Expect a few restarts on the Postgres-backed workloads while the Job waits for
PostgreSQL, then they become Ready.
Managed PostgreSQL and Redis (production)
Name the endpoints once, disable the in-cluster stores you are replacing, and leave ClickHouse alone:deploy: false, a named host, or IAM
auth all stop it rendering). Required pairs:
No datastore password belongs in the values file. Point each service at a Secret
you created, including the control-plane role through
global.postgresql.passwordSecret (chart 2.8.0+) — see
External per-service datastore credentials.
On chart 2.7.x and earlier the control-plane password had to stay inline as
global.postgresql.password, because the chart composed the console’s connection
string while rendering.
For minimum sizes see
Managed stores and
values-managed-datastores.yaml.example,
which ships with the chart. On AWS, RDS IAM authentication needs a per-gateway
setting as well as the global one — see
Cloud notes.
Running ClickHouse outside the cluster is supported but uncommon. Only if your
policy requires it, add:
Install
External needs no console setup, no config-sync tokens, and no DataAgent
enrollment. The platform is its own configuration source.
1
Create the namespace and image pull secret
2
Create the bootstrap administrator Secret
There is no hosted console to sign in from and no sign-up flow, so seed the first
super-admin. A pre-created Secret keeps the credentials out of Helm release
history:The feature activates only when
DEPLOYMENT_MODE=external and both values are
non-empty. On password login the console checks these before normal user
authentication, and on a match upserts the user with a verified email and grants
OWNER on every team.Treat it as a break-glass account: it bypasses the normal user table by design.
Create a personal administrator through the UI afterwards.3
Write your values file
The chart ships With the defaults above, PostgreSQL and Redis stay in-cluster and need no extra
Secrets beyond the pull secret and
values-external.yaml.example. Copy it and set your platform and
domain:onprem-superadmin. For the production shape,
start from values-managed-datastores.yaml.example and follow
Managed PostgreSQL and Redis.4
Install, and watch the ordering
- A pre-install Helm hook Job generates the MCP OAuth RSA signing key into a Secret. It checks for an existing key first, so upgrades do not rotate it and invalidate live access tokens. It only ever writes its own Secret — the Role is name-scoped.
- An init container runs
prisma migrate deployfollowed by the seed.
maxUnavailable: 0, so a failed migration
blocks the rollout rather than serving against a half-migrated schema.
control-plane-api reads the same schema and runs no migrations of its own —
it assumes the console has already applied them.The chart registry is public; only the container images are private. Always
pass --version so the release is reproducible.Verify
agentgateway-proxy,
agentgateway-mcp, trustguard-data-plane, firewall plus its workers,
data-plane-api), the in-cluster control plane (agentgateway-admin,
trustguard-control-plane, control-plane-api, control-plane-app), and the
analytics stack (clickstack-collector, clickhouse, datacore,
alertengine-api, alertengine-worker). No dataagent pod appears.
In-cluster control-plane-postgresql and redis appear only while
deploy: true.
Data-plane readiness has no snapshot gate here, so Running and Ready track
each other closely. Point DNS at the ingress address, sign in with the
super-admin credentials, and create the organization.
Configuration comes from PostgreSQL
Config sync is off by default in External mode, and each product’s data plane reads configuration from its own database. Practical consequences:- There is no config-sync token to create and no snapshot cache to reason about
- Each product needs its own database and role, not one shared credential
kubernetes.io/tls Secret including ca.crt through
configSync.grpcTls.existingSecret; setting autoGenerate: false without one is
rejected at render time.
DataCore is reached by the console at DATACORE_URL with a JWT signed by a
secret that must equal DataCore’s AUTH_JWT_HS256_SECRET. The chart wires both
ends from a single generated value. If you override one by hand you must
override the other, or every dashboard returns an authorization error.
Telemetry
Product telemetry stays in your in-cluster ClickHouse. To run with no outbound NeuralTrust telemetry — the air-gapped default — disable hosted export:Public routing
AgentGateway exposes three surfaces in External mode: admin, proxy, and MCP.global.domain combines with default prefixes to render hostnames, and
the chart can auto-add wildcard hosts (*.llm.<domain> / *.mcp.<domain>) for
slug-based discovery.
DNS, certificates, and cloud controller settings remain operator prerequisites —
see Ingress.
What you have taken on
Worth stating plainly, since it is the real cost of running External:- Database migrations are yours to run and to roll back
- Backups of PostgreSQL and ClickHouse are yours
- Certificate rotation for anything you supplied yourself
- The bootstrap credential is a standing break-glass path into every team
- Email deliverability — invitations and password resets stop working silently if it breaks
Known rough edges
External is newer than Hybrid, and these are the issues you are most likely to meet. Each has a workaround in Troubleshooting.- Login lockout after repeated failed password attempts
- SCIM setup screens display the SaaS host instead of yours
- Alert evaluation does not currently run
- Firewall complexity state silently disables itself without a Redis URL
- Trace export returns 404 when the OTLP endpoint includes a signal path
imagePullSecretsis only honoured on the console undercontrol-plane-app- IAM database auth needs setting per gateway, not only globally
High availability
Availability is a ladder, not a single design. Climb it only as far as the failure you actually have to survive.Tier 1 — one cluster across zones
Spread the node pool over three availability zones, run at least two replicas of the request path and both product control planes, and use managed PostgreSQL and Redis with automatic failover inside the region. No promotion procedure, no DNS work. This is enough for most deployments.Tier 2 — twin clusters in one region
Two clusters against one PostgreSQL primary and one Redis primary. Sharing both stores inside a region costs no extra hop and keeps state identical from either side, which is what makes a blue/green upgrade safe here: External keeps its entire configuration state in PostgreSQL, so the second cluster is already looking at the same policies the moment it starts.Tier 3 — two regions, active/passive
Two consequences to accept: rate limits are counted per region, and console
sessions live in the region that issued them, so a promotion signs operators out
and they sign in again against the same PostgreSQL.
Upgrades and migrations with two clusters
Both consoles runprisma migrate deploy in an init container against the same
database. Upgrade one cluster at a time, active first, and let its rollout
complete before starting the second. A migration is applied once and the second
cluster’s init container no-ops, but running both simultaneously against one
schema is worth avoiding — and the console rolls with maxUnavailable: 0, so a
failed migration blocks that cluster rather than serving a half-migrated schema.
Promote the passive cluster
1
Detect and fence
Health check both request paths and the console. Remove the failed cluster from
the traffic manager so it cannot take traffic during a partial recovery.
2
Point PostgreSQL at a writable primary
If the primary is in the failed region, promote the read replica and update
global.postgresql.host in the surviving cluster. If the primary is unaffected,
there is nothing to do here. Redis needs no attention either way, because the
surviving cluster already has its own.3
Switch traffic
Route the gateway, MCP, and console hostnames to the promoted cluster. Keep them
together.
4
Verify
Sign in to the console, run representative allowed and blocked requests, and
confirm new telemetry is arriving in the promoted cluster’s ClickHouse.
Before you rely on it
- Both clusters are deployed and health checked against the same primary.
- PostgreSQL is managed, with one primary and a cross-region read replica.
- Each region has its own managed Redis, and you accept per-region counters and sessions.
- Certificates and DNS cover the published hostnames from both clusters.
- You have decided whether ClickHouse history needs replicating.
- Backups of PostgreSQL and ClickHouse are running and have been restored once.
- You have rehearsed a promotion, including the datastore step.
Next steps
Configuration
Managed stores, ingress, TLS, and every values switch.
Secrets
Per-service datastore credentials and what the chart generates.
Requirements
Dependencies, ports, and capacity.
Cloud notes
Ingress, certificates, and managed stores per provider.
Troubleshooting
Login, migration, and telemetry failures.