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
Every product deploys unless you turn it off, and DataAgent never runs.
TrustGuard only
Turn TrustGate off to run TrustGuard on its own:values-external-trustguard-only.yaml.example. It
removes TrustGate’s workloads, hosts and Secrets, plus what only TrustGate uses:
the Firewall complexity worker, MCP OAuth and the Admin API machine credentials.
Leave dataPlane on: the console reads runtime activity from the data-plane
API. The audit trail does not depend on it; audit events are sent as OTLP logs
and shown under Telemetry → Logs.
Prerequisites
- A Kubernetes cluster with an ingress controller, and Helm 3.8+
- 4 nodes of 8 vCPU / 32 GiB — the console and analytics stack on top of the data path — as the minimum of an autoscaled node pool; GPU options are in 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 with global.imageRegistryScope: all, so the collector
images follow — 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: 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. 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:
The
trustguard database needs the pgcrypto extension: TrustGuard’s
migrations create it and fail without it. The control-plane database uses it
when it is available. The owner of a database may create it, since pgcrypto is
a trusted extension. On Azure Database for PostgreSQL, first allow-list it in the
azure.extensions server parameter.
Let the chart create the roles
WithmanagedBootstrap on, the chart runs a Job after install and after every
upgrade that creates any missing role and database in the table above, using
the passwords the services read, and creates pgcrypto in each database. Roles
and databases that already exist are kept, except that each role’s password is
set to the one in its service’s Secret, so the two cannot drift and a password
rotated in the Secret reaches the database on the next upgrade. Re-running it
is safe, so leave it on. Application tables stay with each service’s own
migrations.
It logs in with an administrator you name in a Secret. That login needs
CREATEROLE and CREATEDB, not superuser:
authMode: iam the roles are principals your cloud tooling creates, and the
chart refuses to render with both set. The Job is a Helm post-install and
post-upgrade hook, which Argo CD runs as a PostSync hook. Until it finishes,
the services restart while they wait for their databases.
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 — see
External per-service datastore credentials.
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.
The checks above confirm the install came up. Before handing it over, work
through the validation checklist — it
covers what kubectl cannot see: DNS and TLS from the caller’s network, MCP
tested separately from the LLM route, policy decisions, backup ownership, and a
rehearsed restore.
Telemetry
Product telemetry stays in your in-cluster ClickHouse. To run with no outbound NeuralTrust telemetry — the air-gapped default — disable hosted export:global.observability.operationalTelemetry: true, which is off by default.
In External, both stay in your environment. See
Operational telemetry.
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
- IAM database auth needs setting per gateway, not only globally
High availability
The availability ladder is the same for every self-hosted model, so it lives on one page: what each tier survives, the replica and disruption settings the chart does and does not expose, the failure table, and the promotion runbook.High availability
The four tiers, from one cluster across zones to two active regions, the two invariants, and exactly what you change in the chart.
Configuration lives in PostgreSQL
External keeps its entire configuration state in the database rather than pulling it from anywhere, so a second cluster is already looking at the same policies the moment it starts. Nothing dials NeuralTrust, and there is no last-known-good cache to worry about — the trade is that the database is now the thing that must not be lost.ClickHouse does not follow a promotion
Console sessions live in the region that issued them
A promotion signs operators out. They sign in again against the same PostgreSQL and everything is there — but plan for it in the runbook rather than discovering it mid-incident.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.
External at tier 3
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.
Validation checklist
What to prove before the install counts as done.
Troubleshooting
Login, migration, and telemetry failures.