ManagementPlane
Scope: namespaced · Optional (the console is deployed by default)
The Navique AI Core Management Plane is the admin console for the whole platform — a single web UI to see everything the operator manages, activate a license, and (when licensed) export how users used the AI gateway. The operator deploys it by default, even when no ManagementPlane resource exists; this resource only overrides defaults (host, ingress, SSO, image, discovery).
What the management plane is
It is a proprietary admin console — the closed-source counterpart to the open-source operator. Where the operator runs the platform, the management plane gives a human a single pane of glass over it:
- See every operator-managed resource and its live status in one place, instead of running
kubectlagainst a dozen custom resources across namespaces. - See and activate the platform license from a browser.
- For regulated buyers, export a user's gateway usage / conversation history over a time window as JSON or CSV (a licensed feature).
It is shipped only as a prebuilt container image and is admin-only in v1. Because it is proprietary, it deliberately does not link the operator's AGPL code — it reads the operator's resources through the Kubernetes API like any other client. (A build-time check fails if any operator package is linked.)
Why it is useful
| Capability | Availability |
|---|---|
| View operator-managed resources + live status across namespaces | Free baseline (any / no license) |
| Discover the running LiteLLM / Langfuse instances and their reachability | Free baseline |
View & activate a license (creates/updates the License resource) | Free baseline — the only write action |
| Export a user's gateway usage / conversation history (audit, JSON/CSV) | Licensed: management-plane-audit-export |
License-gated features fail closed without the entitlement; the free baseline is always available, even with no license at all.
How it works
The console is an API-aggregation BFF (backend-for-frontend), not an observability pipeline or a database. A Go backend serves a Nuxt + Vue single-page app (embedded in the binary, so there is no Node at runtime — good for air-gapped installs) and a JSON API. It reads from three sources and stores no platform data of its own:
Admin browser ──▶ Nuxt SPA (served by Go via embed)
│ JSON BFF API
▼
Go backend (auth · discovery · license · audit · api)
│ Kubernetes API │ LiteLLM API │ Langfuse API
▼ operator CRs + status ▼ usage / spend ▼ conversation traces
License CR (read+write) (audit primary) (audit supplement)- Kubernetes API (via the dynamic client + the console's ServiceAccount) — the operator's resources and their
.status, plus reading and writing theLicense. - LiteLLM API — usage, spend, and per-end-user activity (the primary audit source).
- Langfuse API — conversation traces (supplementary audit content).
Credentials for LiteLLM/Langfuse are read from Kubernetes Secrets via the console's ServiceAccount and never reach the browser. The backend caches the resource list and discovered instances so the dashboard is instant (see Cache tuning).
Login & access
Two login methods, both built in:
Local admin — a bootstrap administrator, for SSO-less or air-gapped clusters. Enable it under
auth.localAdmin. If you do not supply acredentialsSecretRef, the operator auto-generates the credentials for you: it creates an ownednavique-management-plane-consoleSecret containing theusername(fromlocalAdmin.username, defaultadmin) and a randompassword, and records the Secret name instatus.localAdminSecret. Read the generated password with:bashkubectl get secret navique-management-plane-console -n navique-system \ -o jsonpath='{.data.password}' | base64 -dSupply a
credentialsSecretRef(a Secret withusernameandpasswordkeys) only when you want to manage the credentials yourself.Microsoft Entra OIDC — configure the issuer, client ID, and client secret; the SSO button then appears automatically.
Configure either through this resource's auth block. The operator also generates a stable SESSION_KEY into the same owned console Secret, so logins survive console restarts and scale-out.
Activating a license from the console
License activation is the one write the console performs. From the License page an admin pastes or uploads a signed license token; the backend verifies the signature and previews the decoded entitlements (features + instance limits) before anything changes; on confirm it creates or updates the License resource and its backing Secret. The operator then picks up the new entitlements on its next reconcile.
This is the same signed token used everywhere — the console embeds the same Ed25519 public key as the operator, so a token is interpreted identically on both sides. See Managing a License for the CLI path and Editions & Licensing for what the features and limits mean.
Audit & usage export (licensed)
The first licensed feature (management-plane-audit-export) lets an admin export how an end-user used the gateway over a time window. It is aimed at the regulated organizations that need to answer "what did this user send through the AI platform, and when?"
- End-user identity is the user's email (
x-litellm-end-user-id), carried LibreChat → LiteLLM → Langfuse. - LiteLLM is the primary source (timestamps, model, tokens, spend, status, and request content where stored); Langfuse supplements it with richer conversation content where available. If Langfuse is absent, the export still works from LiteLLM alone and notes it.
- Output is normalized JSON or CSV, streamed (not buffered), with a
metablock recording who ran it, the target user, the window, the instance, and the sources used. - Exports are themselves audited. Every export writes a meta-audit record (operator identity, target user, window, format, row count, sources) to the app log and a durable in-cluster sink — answering "who exported whose data, when".
Conversation content is sensitive: the feature is admin-only, content is never logged in plaintext, and the export is meta-audited. The console respects the upstream tools' own retention — it reads what LiteLLM/Langfuse still hold and stores nothing itself.
Security & boundaries
- Least-privilege RBAC. The operator provisions the console a ServiceAccount whose only write is license activation; everything else is read-only (see What the controller reconciles).
- AGPL-safe. The proprietary console reads the operator's resources via the Kubernetes dynamic client and does not import the operator's AGPL packages, so the open-core boundary holds. The operator merely references and deploys the image.
- Not a replacement for Langfuse. Langfuse remains the LLM-tracing tool; the console is the cross-component admin surface that links to and pulls from it.
- v1 non-goals: multi-tenant RBAC, write-back management of instances/models/ teams, and a built-in observability store — possible later, out of scope today.
Spec
| Field | Type | Description |
|---|---|---|
image | string | Override image/tag (default: operator-pinned) |
ingress | object | Public route for the console — host, TLS (cert-manager), className, and api (Ingress / Gateway). See Routing |
auth | object | OIDC (Entra) and/or a bootstrap local admin |
discovery | object | Explicit endpoint overrides, merged with CR auto-discovery. See Discovery |
resources | object | CPU/memory requests & limits applied to the console container |
replicas | int | Console replica count (default 1) |
Routing
The console is operator-built (not a Helm chart), so the operator emits its public route itself. Both routing APIs are supported and selected per the cluster-wide PlatformConfig.spec.routing default, overridable per-console with ingress.api:
- Classic Ingress (
api: Ingress, or the default when no mesh is active) — the operator creates anetworking.k8s.io/v1Ingress (named after the CR) routinghost→ the console Service.className, cert-manager TLS (tls+clusterIssuer), nginxbasicAuthSecret, and customannotationsare honored. - Gateway API (
api: Gateway, or the default when a mesh is active) — the operator emits anHTTPRouteattached to the shared managed Gateway. Requires the Gateway API CRDs; until they are present the console reports aWaitingcondition.
Discovery
By default the console auto-discovers the running LiteLLM/Langfuse instances from their Gateway/Observability CRs. discovery.litellmEndpoints / discovery.langfuseEndpoints add explicit endpoint URLs that are merged with that auto-discovery — useful for external or cross-cluster instances that are not operator CRs. These manual endpoints appear on the dashboard and are reachability-probed; because they have no associated credential Secret, the credentialed features (usage/audit export) remain available only for CR-discovered instances.
auth
| Field | Description |
|---|---|
oidc | Entra: issuerURL, clientID, clientSecretRef |
localAdmin | Bootstrap admin for SSO-less / air-gapped setups |
auth.localAdmin
| Field | Description |
|---|---|
enabled | Turn on the local-admin login |
username | Login username (default admin) |
credentialsSecretRef | Optional. A Secret with username and password keys. Omit to have the operator auto-generate the credentials into the owned navique-management-plane-console Secret |
What the controller reconciles
- A Deployment + Service + optional Ingress for the management-plane image — one console per cluster (see Cluster singleton & relocation). With no
ManagementPlaneresource it lives in the system namespace (e.g.navique-system); with a resource it lives in that resource's namespace. - A ServiceAccount with least-privilege RBAC:
- cluster
get/list/watchon all*.core.navique.comresources and/status; geton the LiteLLM/Langfuse credential Secrets;create/update/getonlicenses.core.navique.comand the license Secret (the console's only write — license activation);create/patchonevents(a meta-audit sink).
- cluster
- Config from the
ManagementPlaneresource if present; otherwise sensible defaults.
Cluster singleton & relocation
The console holds cluster-wide RBAC, so running more than one is never useful. The operator enforces exactly one console per cluster:
- Default (no resource): the console runs in the system namespace (
navique-system). - Relocation: apply a
ManagementPlanein another namespace and the operator moves the single console there — it creates the console in your namespace and deletes the default innavique-system. There is never a second console. Delete the resource and the console returns tonavique-system. - More than one resource: the oldest
ManagementPlanewins and governs the console; every younger resource reportsstatus.phase: Superseded(Ready=False, reasonSuperseded) and deploys nothing. Delete the active one and the next-oldest is promoted automatically.
This is purely a controller behavior — there is no admission policy forcing a particular name, and any name is accepted.
Example
apiVersion: core.navique.com/v1alpha1
kind: ManagementPlane
metadata:
name: management-plane
namespace: navique-system
spec:
ingress:
enabled: true
host: console.forge.example.com
className: nginx # classic Ingress; use api: Gateway for an HTTPRoute
tls: true
clusterIssuer: letsencrypt-prod
resources:
requests: { cpu: 100m, memory: 128Mi }
limits: { memory: 256Mi }
discovery:
# External / cross-cluster instances merged with CR auto-discovery.
litellmEndpoints: [ "https://litellm.other-cluster.example.com" ]
auth:
oidc:
enabled: true
issuerURL: https://login.microsoftonline.com/<tenant>/v2.0
clientID: <app-id>
clientSecretRef: { name: mp-oidc, key: client-secret }
localAdmin:
enabled: true
username: admin
# credentialsSecretRef omitted → the operator auto-generates the
# username + a random password into navique-management-plane-console.Cache tuning
The console caches the resource list and discovered instances so the dashboard is instant. These are tunable via the deployment's environment (each is a Go duration; defaults shown):
| Env var | Default | Controls |
|---|---|---|
RESOURCE_RESYNC_INTERVAL | 10s | Background resync of the resource list cache |
INSTANCES_CACHE_TTL | 15s | TTL for instance discovery + reachability probes |
LICENSE_REFRESH_INTERVAL | 60s | How often the License is re-read and verified |
Status
Deployment availability, the resolved console URL, the localAdminSecret holding the local-admin credentials (when local admin is enabled), and the standard conditions and observedGeneration. A non-active resource (see Cluster singleton & relocation) reports phase: Superseded.