Skip to content

Gateway ​

Geltungsbereich: namespaced · Workload: LiteLLM über den litellm-operator oder Wäg über den waeg-operator

Das KI-Gateway — die Eingangstür für Modell-Traffic, mit Modellen, Teams, Organisationen, Budgets und optionalem Langfuse-Trace-Export.

spec.type wählt die Implementierung aus. Der Standardwert ist litellm, daher beschreibt der Rest dieser Seite das LiteLLM-Gateway, sofern nicht anders angegeben; die Unterschiede finden Sie unter Wäg-Gateway (type: waeg).

Spec ​

FeldTypBeschreibung
typelitellm | waegGateway-Implementierung. Standard litellm.
waegobjectAusschließlich Wäg-spezifische Verdrahtung (Topologie, ClickHouse-/Redis-Ebenen, OpenFGA). Erforderlich bei type: waeg
secretsRefLocalRef (optional)SecretsManagement im selben Namespace, auf die gewartet wird. Weglassen, um selbst verwaltete, gewöhnliche Kubernetes-Secrets zu verwenden — siehe secretsRef
databaseobject (erforderlich)Wo LiteLLM seinen Zustand speichert
instanceobjectImage/Tag, Replicas, Ressourcen, Master-/Salt-Keys, SSO
organizationobjectLiteLLM-Organisation + Budgets
teams[]listTeams mit teamspezifischen Budgets
models[]listDer Modellkatalog
guardrailRefs[]ObjectRefGuardrail-CRs, die in dieses Gateway verdrahtet werden (lizenziert guardrail; als LiteLLMGuardrail über den Lizenz-Gate-Proxy jedes Guardrails emittiert)
observabilityRefObjectRefEin Observability für den Trace-Export (auto-wired, sofern lizenziert)
observabilityobjectManueller Fallback für den Langfuse-Callback
ssoobjectOIDC/SSO-Login für die LiteLLM-Admin-UI (siehe SSO)
enableEntraSSOboolVeraltet — verwenden Sie sso mit provider: azure-entra

database ​

FeldBeschreibung
modepostgresCluster (Verweis auf ein PostgresCluster) oder external
postgresClusterRefDer zu verwendende Cluster (Modus postgresCluster)
databaseNameDatenbank innerhalb des gemeinsam genutzten Clusters
connectionSecretRefDATABASE_URL-Secret (Modus external)

models[] ​

FeldBeschreibung
name / modelName / modelAnzeigename, LiteLLM-Modellname und Provider-Modell-ID
refSecretKeySchlüssel im Modell-Anmeldedaten-Secret, der den API-Key enthält
credentials.apiBaseProvider-Endpunkt, für jeden Provider, der einen expliziten benötigt (Azure OpenAI / AI Foundry, selbst gehostet, ein Proxy)
credentials.apiVersionProvider-API-Version, wenn der Provider eine benötigt (z. B. Azure OpenAI / AI Foundry)
rpm / tpm / timeout / maxTokensModellspezifische Limits (nur LiteLLM)
provider / providerName / modelId / fallbacks / weightAusschließlich Wäg-Katalogfelder — siehe Wäg-Gateway

Wenn ein Modell einen eigenen Endpunkt und/oder eine API-Version benötigt, setzen Sie diese unter credentials — der Operator reicht sie zusammen mit dem API-Key aus refSecretKey an das Gateway weiter. Lassen Sie apiBase den reinen Endpunkt und tragen Sie die Version in apiVersion ein (kein ?api-version= in der URL). Das ist providerunabhängig: Der Operator gibt aus, was Sie angeben, und behandelt keinen Provider gesondert.

instance.healthCheck ​

Steuert die Hintergrund-Health-Checks der Modelle in LiteLLM. Standardmäßig deaktiviert: GET /health prüft die Modelle bei Bedarf, statt eine Hintergrundschleife auszuführen. Hintergrund-Checks erzeugen periodischen Upstream-Verkehr und können bei manchen Providern Kosten verursachen oder Rate-Limits auslösen — aktivieren Sie sie also nur, wenn /health zwischengespeicherte Ergebnisse liefern soll.

FeldTypBeschreibung
enabledboolHintergrund-Health-Checks einschalten. Standard false (deaktiviert).
intervalSecondsintSekunden zwischen den Checks (LiteLLM-Standard 300). Gilt nur bei enabled: true.
yaml
instance:
  healthCheck:
    enabled: true
    intervalSeconds: 300

Wird auf generalSettings.backgroundHealthChecks / healthCheckInterval der LiteLLMInstance abgebildet. Bei deaktiviertem Zustand setzt der Operator explizit backgroundHealthChecks: false.

Was es emittiert ​

Der Controller löst die Datenbank auf, stellt den litellm-operator sicher (wartet, bis dessen CRDs Established sind) und emittiert anschließend in folgender Reihenfolge:

LiteLLMInstance → LiteLLMOrganization → LiteLLMTeam(s)
               → LiteLLMCredential(s) → LiteLLMModel(s)

(Alle in der API-Gruppe litellm.palena.ai/v1alpha1.)

Datenbank-Verdrahtung ​

  • postgresCluster — der Operator löst den referenzierten Cluster auf, bereitet die litellm-Datenbank und -Rolle bereit, generiert das Passwort und injiziert das Anmeldedaten-Secret. Es ist kein manuelles Secret erforderlich.
  • external — geben Sie eine connectionSecretRef an, die eine DATABASE_URL enthält.

Langfuse-Trace-Export ​

  • Mit dem Feature auto-wiring und einer observabilityRef verdrahtet der Operator den Langfuse-Callback von LiteLLM (Host + Public-/Secret-Keys) aus dem referenzierten Observability, sodass Traces automatisch exportiert werden.
  • Ohne dieses Feature (oder gegen ein Community-Langfuse, das keine Projektschlüssel ausstellen kann) erstellen Sie das Projekt + den Schlüssel in der Langfuse-UI und setzen spec.observability.{host, callbackSecretRef} (Schlüssel publicKey / secretKey).

Siehe Auto-Wiring für die beiden beteiligten Gates.

SSO / OIDC login ​

spec.sso aktiviert Single Sign-On für die LiteLLM-Admin-UI und wird in den Block LiteLLMInstance.spec.sso übersetzt. Die OAuth-Client-Anmeldedaten stammen aus einem Secret im selben Namespace (über SecretsManagement — niemals inline).

FeldBeschreibung
issuerURLOIDC-Issuer-/Discovery-Basis-URL
clientSecretRef.nameSecret mit dem OAuth-Client (Schlüssel standardmäßig client-id / client-secret, überschreibbar mit clientIDKey / clientSecretKey)
providergeneric-oidc (Standard), azure-entra, google oder okta
tenantIDDirectory-/Tenant-ID (für azure-entra)
authorizationEndpoint / tokenEndpoint / userinfoEndpointExplizite Endpunkte — erforderlich für generic-oidc (LiteLLM führt keine Discovery durch)
scopesAngeforderte Scopes (Standard openid, profile, email)
providerNameAnzeigebezeichnung
yaml
spec:
  sso:
    provider: generic-oidc
    issuerURL: https://idp.example.com
    authorizationEndpoint: https://idp.example.com/authorize
    tokenEndpoint: https://idp.example.com/token
    userinfoEndpoint: https://idp.example.com/userinfo
    clientSecretRef: { name: gateway-oidc }

Lizenzierung

LiteLLM-SSO ist für bis zu 5 Benutzer kostenlos; vollständiges/unbegrenztes SSO erfordert eine LiteLLM-Enterprise-Lizenz. Der Navique-Operator schränkt das Feld selbst nicht ein.

Redirect-URL bei öffentlichem Zugriff

LiteLLM bildet die OAuth-redirect_uri aus PROXY_BASE_URL, die aus dem ingress des Gateways abgeleitet wird. Für SSO über öffentlichen Zugriff muss das Gateway unter seinem öffentlichen Host mit TLS bereitgestellt werden — spec.ingress.enabled: true, spec.ingress.host: <öffentlicher-host> und spec.ingress.tls: true — sodass der Callback zu https://<öffentlicher-host>/sso/callback auflöst. Registrieren Sie genau diese URL bei Ihrem IdP. Ohne ingress.tls: true fällt der Redirect auf eine reine http-/clusterinterne Adresse zurück und der OAuth-Callback schlägt fehl. (status.endpoint der zugrunde liegenden LiteLLMInstance zeigt immer die clusterinterne .svc-URL — das ist die Admin-API-Adresse des Operators selbst, nicht die Basis des SSO-Redirects.)

Das veraltete Boolean enableEntraSSO: true funktioniert weiterhin, solange sso nicht gesetzt ist — es synthetisiert eine azure-entra-Konfiguration, die das althergebrachte Secret entra-sso-credentials liest. Bevorzugen Sie sso mit provider: azure-entra.

JWT-API-Authentifizierung & RBAC ​

spec.instance.jwtAuth aktiviert die JWT-basierte API-Authentifizierung: LiteLLM prüft bei jeder Anfrage ein Bearer-JWT Ihres IdP und bildet dessen Claims auf Rollen/Teams ab (getrennt von sso, dem Browser-Login der Admin-UI). Kombinieren Sie es mit spec.instance.rolePermissions, um einzuschränken, welche Modelle eine Rolle aufrufen darf.

FeldAbbildung auf (litellm_jwtauth)
jwtAuth.enabledgeneral_settings.enable_jwt_auth
jwtAuth.publicKeyURLJWKS-Endpunkt (JWT_PUBLIC_KEY_URL) — erforderlich: ohne ihn kann LiteLLM kein Token validieren
jwtAuth.issuererwarteter Token-Aussteller iss (JWT_ISSUER)
jwtAuth.audienceerwartete Token-Zielgruppe aud (JWT_AUDIENCE)
jwtAuth.userRolesJWTFielduser_roles_jwt_field — JWT-Claim mit der Rollenliste
jwtAuth.userAllowedRolesuser_allowed_roles — Rollen, die auf internal_user abbilden
jwtAuth.enforceRBACenforce_rbac — Aufrufer mit unzulässigen Rollen ablehnen
jwtAuth.userRoleJWTFielduser_role_jwt_field (einzelne Rolle)
jwtAuth.userIDJWTFielduser_id_jwt_field — Claim, der als Benutzer-ID dient (sub / oid / preferred_username)
jwtAuth.userIDUpsertuser_id_upsert — legt den LiteLLM-Benutzer beim ersten Login automatisch an
jwtAuth.teamIDsJWTFieldteam_ids_jwt_field
jwtAuth.adminJWTScopeadmin_jwt_scope
rolePermissions.<rolle>.models / .routesgeneral_settings.role_permissions
yaml
spec:
  instance:
    licenseSecretRef: { name: litellm-enterprise-license, key: license }
    jwtAuth:
      enabled: true
      publicKeyURL: https://login.microsoftonline.com/<tenant>/discovery/v2.0/keys  # ERFORDERLICH (JWKS)
      issuer: https://login.microsoftonline.com/<tenant>/v2.0
      audience: <client-id>
      userIDJWTField: sub          # Claim, der den Benutzer identifiziert (sub / oid / preferred_username)
      userIDUpsert: true           # legt den LiteLLM-Benutzer beim ersten Login automatisch an
      userRolesJWTField: roles
      userAllowedRoles: ["basic_user"]
      enforceRBAC: true
    rolePermissions:
      internal_user:
        models: ["anthropic-claude"]

Auf einem Wäg-Gateway schaltet derselbe jwtAuth-Block Wägs eigenes JWT-Modul für die Datenebene ein; die Wäg-spezifischen Einstellungen liegen unter spec.waeg.jwt — siehe JWT-Authentifizierung auf der Datenebene.

Nur Enterprise

enable_jwt_auth, enforce_rbac und role_permissions sind LiteLLM-Enterprise- Funktionen — setzen Sie instance.licenseSecretRef auf eine gültige LiteLLM- Enterprise-Lizenz, sonst bleiben sie wirkungslos. Ein gesetzter rolePermissions- Eintrag aktiviert general_settings.enforce_rbac, damit die Beschränkungen greifen.

Beispiel ​

yaml
apiVersion: core.navique.com/v1alpha1
kind: Gateway
metadata:
  name: gateway
  namespace: forge-gateway
spec:
  secretsRef: { name: forge-secrets }
  database:
    mode: postgresCluster
    postgresClusterRef: { name: forge-pg, namespace: forge-data }
    databaseName: litellm
  instance:
    image: { repository: ghcr.io/berriai/litellm, tag: v1.86.1 }
    replicas: 1
    masterKey: { autoGenerate: true }
    saltKey: { autoGenerate: true }
  observabilityRef: { name: observability, namespace: forge-langfuse }
  organization:
    name: navique-ag
    maxBudget: 2000
    budgetDuration: 30d
    rpmLimit: 1000
    tpmLimit: 200000
  teams:
    - { name: data-engineering, maxBudgetMonthly: 1000, budgetDuration: 30d }
  models:
    - name: gpt-5.4
      modelName: gpt-5.4
      model: azure/gpt-5.4            # Provider-/Deployment-ID (hier: ein Azure-OpenAI-Deployment)
      refSecretKey: OPENAI_API_KEY
      rpm: 300
      tpm: 80000
      timeout: 120
      credentials:
        apiBase: "https://forge-foundry.cognitiveservices.azure.com"
        apiVersion: "2024-10-21"

Wäg-Gateway (type: waeg) ​

Wäg ist ein alternatives KI-Gateway, betrieben vom mitgelieferten waeg-operator (gateway.waeg.ai). Es ist ein anderes Produkt, kein LiteLLM-Klon, und diese CRD tut nicht so, als wäre es eines: alles Folgende ist ein echter Unterschied, und alles, was Wäg nicht kann, wird gemeldet — niemals stillschweigend verworfen.

Was sich ändert ​

AspektLiteLLMWäg
Speicherein Postgres (+ optional Redis)standardmäßig zwei Ebenen (storageMode: split): Postgres und ClickHouse. storageMode: single hält die Analysedaten im Postgres der Steuerungsebene und braucht kein ClickHouse
Redisoptionalerforderlich, sobald die API mehr als ein Replica bedient (HA-Kontingente)
AutorisierungProxy-Rollen / virtuelle KeysOpenFGA — extern oder ein Postgres-gestütztes, das der Operator ausrollt
Prozessmodellein Proxy-DeploymentAllInOne oder Split (api + optionaler worker)
Katalogein ModellobjektProvider (Verbindung + Credential) und Modell-Alias, der darauf verweist
Budgetsan den Org-/Team-Objektenseparate organisationsverankerte Budget-Richtlinien

spec.waeg ​

FeldBeschreibung
topologyAllInOne (Standard) oder Split (*-api plus optionales *-worker-Deployment)
jobWorkersIn-Process-Worker für dauerhafte Jobs (nur AllInOne)
workerDas dedizierte Worker-Deployment (enabled, replicas, jobWorkers, resources) — erfordert topology: Split
storageModeWo die Analysedaten liegen: split (Standard — ClickHouse) oder single (Postgres der Steuerungsebene, ganz ohne ClickHouse) — siehe Analyse-Speichermodus
clickhouseDie Analyse-Ebene — erforderlich bei storageMode: split, bei single ignoriert und nicht erforderlich: mode: ref auf ein ClickHouseCluster oder mode: external mit einem Verbindungs-Secret
clickhouseDatabaseDie ClickHouse-Datenbank, in die im split-Modus geschrieben wird. Standard waeg; der Operator legt sie auf einem managed- oder adopt-Cluster an
redisDer HA-Kontingentspeicher: mode: ref auf eine RedisInstance oder external. Erforderlich bei mehr als einem API-Replica
openfgaExterne apiUrl / apiUrlSecretRef — oder weglassen, dann rollt der Operator ein Postgres-gestütztes OpenFGA aus (image, replicas, resources, storeId, modelId)
autoscalingAPI-HPA auf CPU/Speicher (enabled, minReplicas, maxReplicas, Zielwerte). Skalierung nach Warteschlangentiefe benötigt KEDA und ist nicht verdrahtet
artifactsVolume für Jobs/Medien: emptyDir (Standard), pvc (ein bestehender Claim) oder none
bootstrapAdminLegt den ersten Konsolen-Admin aus einem Secret an (secretRef, emailKey, passwordKey)
dataEncryptionKeySecretRefDer Schlüssel, mit dem Wäg Konfigurationsrevisionen versiegelt (Wägs Gegenstück zum Salt-Key von LiteLLM)
configYAMLÜberschreibt den waeg.yaml-Bootstrap-Seed. Nur nicht-geheime Werte — der Inhalt landet in einer ConfigMap
brandingConfigMapRefIhr eigenes Enterprise-Theme-Pack (JSON), das der Operator nach Erreichen von Ready an die Admin-API sendet. Ersetzt das eingebaute Navique-Pack — lizenziertes Feature custom-branding; siehe Konsolen-Branding
defaultBrandingWendet das eingebaute Navique-Theme-Pack an, wenn das Gateway Enterprise-lizenziert ist und kein brandingConfigMapRef gesetzt ist. Standard true
modelAccessDie organisationsverankerte Modell-ACL (openByDefault, fallbackMode, grants[]). Erfordert spec.organization
scimSCIM-v2-Benutzerbereitstellung (enabled, tokenSecretRef, defaultRole, defaultOrgID, orgSource, roleMap, orgMap) — siehe SCIM-Bereitstellung
jwtDie Wäg-spezifischen JWT-Einstellungen der Datenebene (appClaim, appClaimFallbacks, tenantClaim, requireRegisteredApplication, allowMasterKey, allowVirtualKeys, insecureSkipVerify) — siehe JWT-Authentifizierung auf der Datenebene

Postgres kommt weiterhin aus spec.database — dasselbe Feld, identisch aufgelöst. Der Operator fasst alle Verbindungszeichenfolgen in einem eigenen Secret <gateway>-waeg-storage zusammen und referenziert es per Schlüssel, sodass nie eine Zugangsdaten-URL in der CR landet.

Analyse-Speichermodus ​

Wäg hält seine Steuerungsebene (Konfiguration, Keys, Organisationen, Teams, Anwendungen) in Postgres und seine Analyse-Ebene (Request-Logs, Nutzung, Kosten) in einem Speicher, den spec.waeg.storageMode auswählt:

ModusAnalysedaten liegen inClickHouse nötig
split (Standard)ClickHouse — spec.waeg.clickhouse muss darauf zeigenja
singledemselben Postgres wie die Steuerungsebene (spec.database)nein

split ist der Standard dieses Operators: es ist das, was das Gateway schon immer emittiert hat, und es trägt bei hohem Volumen. Wägs eigener Upstream- Standard ist single und gilt dort als empfohlener Einstieg — genau dafür gibt es dieses Feld. Für jedes Gateway ein ClickHouse zu verlangen erzwang eine Abhängigkeit, die Upstream längst fallen gelassen hatte; für eine kleine oder evaluierende Installation verdoppelt sie die Datenspeicher, die Sie betreiben, dimensionieren und sichern müssen — ohne Gegenwert.

Mit single enthält die emittierte WaegInstance überhaupt keinen clickhouse-Block; spec.waeg.clickhouse wird ignoriert und ist nicht erforderlich.

Ein Moduswechsel migriert die Analysehistorie nicht

Die beiden Ebenen sind getrennte Speicher. Ein geänderter storageMode an einem laufenden Gateway zeigt auf den jeweils anderen — die bereits geschriebenen Analysedaten bleiben, wo sie sind, und sind in der Konsole nicht mehr sichtbar. Weder der Operator noch Wäg kopiert sie hinüber. Entscheiden Sie sich für einen Modus, bevor Sie Daten sammeln, die Ihnen wichtig sind — oder exportieren Sie sie vorher.

single — nur Postgres ​

yaml
apiVersion: core.navique.com/v1alpha1
kind: Gateway
metadata:
  name: waeg-gateway
  namespace: forge-gateway
spec:
  type: waeg
  secretsRef: { name: forge-secrets }
  database:
    mode: postgresCluster
    postgresClusterRef: { name: forge-pg, namespace: forge-data }
    databaseName: waeg
  instance:
    replicas: 1
    masterKey: { autoGenerate: true }
  waeg:
    storageMode: single         # Analysedaten landen in forge-pg, neben der Steuerungsebene
    # kein clickhouse-Block — keiner wird gebraucht, und einer hier würde ignoriert

split — Analysedaten in ClickHouse ​

yaml
spec:
  type: waeg
  secretsRef: { name: forge-secrets }
  database:
    mode: postgresCluster
    postgresClusterRef: { name: forge-pg, namespace: forge-data }
    databaseName: waeg
  instance:
    replicas: 2
    masterKey: { autoGenerate: true }
  waeg:
    storageMode: split          # der Standard; kann weggelassen werden
    clickhouse: { mode: ref, ref: { name: forge-ch, namespace: forge-data } }
    clickhouseDatabase: waeg    # der Standard
    redis:      { mode: ref, ref: { name: forge-redis, namespace: forge-data } }

Wäg legt nur seine Tabellen an, niemals seine Datenbank. Auf einem managed- oder adopt-ClickHouseCluster deklariert der Operator diese Datenbank unter spec.databases und legt sie für Sie an; auf einem external-Cluster müssen Sie sie selbst anlegen, sonst beendet sich das Gateway beim Start mit Database waeg does not exist.

Modelle: Provider + Alias ​

Wägs Katalog trennt die Upstream-Verbindung vom clientseitigen Alias, daher emittiert jeder Eintrag in spec.models sowohl einen WaegProvider als auch ein WaegModel. Modelle mit demselben Treiber teilen sich einen Provider.

FeldBeschreibung
providerProvider-Treiber (openai, azure, anthropic, …). Standard ist das Präfix von model (azure/gpt-4o → azure), sonst openai
providerNameBenennt den Provider-Katalogeintrag, sodass mehrere Modelle eine Verbindung teilen können. Standard ist der Treiber
modelIdProviderseitige Modell-ID. Standard ist model ohne Präfix (azure/gpt-4o → gpt-4o)
fallbacksModell-Aliase, die bei einem Fehler versucht werden
weightGewichtet dieses Deployment gegenüber anderen desselben Alias

Was es emittiert ​

WaegInstance → WaegOrganization → WaegBudget (Org-Limits) → WaegTeam(s)
             → WaegProvider(s)  → WaegModel(s)            → WaegModelAccess

(Alle in der API-Gruppe gateway.waeg.ai/v1alpha1.)

Enterprise-Lizenz ​

spec.instance.licenseSecretRef trägt die Wäg-Enterprise-Lizenz des Gateways. Sie erreicht die Instanz als WaegInstance.spec.secrets.licenseKey; der Secret-Schlüssel ist standardmäßig license.

Jedes Wäg-Enterprise-Modul hängt daran — SSO, SCIM, Audit, CMEK, FIPS und Branding gleichermaßen — und die Durchsetzung ist bedingungslos: ein Gateway-Image mit gelinktem EE-Binary, aber ohne Lizenz, antwortet mit 402 license_required. Der Enterprise-Build allein genügt also nicht; meldet ein Modul LicenseRequired, fehlt genau dieses Feld.

yaml
spec:
  instance:
    licenseSecretRef: { name: waeg-enterprise-license, key: license }

Die Lizenz wird referenziert, nie eingebettet: lassen Sie Ihr SecretsManagement-Backend das Secret materialisieren (ESO aus dem Key Vault oder ein SealedSecret) wie jedes andere Credential. In einem Stack wird sie einmalig als spec.gateway.licenseSecretRef deklariert und an das Gateway durchgereicht.

SSO und Trace-Export ​

Beides funktioniert — über andere Wege als bei LiteLLM.

SSO (spec.sso) wird über eine WaegEnterpriseConfig-CR angewendet, die Wägs Enterprise-Module über dessen Admin-API konfiguriert statt über Instanz-Umgebungsvariablen. Der Operator liest die Client-ID aus Ihrem Secret und setzt sie als einfaches Feld (eine Client-ID ist konstruktionsbedingt öffentlich — sie steht in der Authorize-URL im Browser), während das Client-Secret eine Secret-Referenz bleibt und als WAEG_EE_OIDC_CLIENT_SECRET auf den Pod projiziert wird. Das ist Absicht: die CR könnte das Secret auch in den versiegelten Config-Store des Gateways schreiben, womit es in dessen Config-Revisionen läge statt in Kubernetes.

Die Redirect-URI wird als <öffentlicher Origin>/waeg/ui/v1/ee/sso/callback gebildet — das Gateway lehnt jeden Wert ab, der diesen Pfad nicht enthält. SSO benötigt daher spec.ingress mit einem Host; fehlt er, warnt der Operator, statt einen Callback zu erzeugen, der nie aufgelöst werden kann. Registrieren Sie genau diese URL bei Ihrem IdP.

Erfordert den Enterprise-Build und eine Lizenz; die CR meldet pro Modul EnterpriseNotLinked bzw. LicenseRequired, falls eines davon fehlt.

Trace-Export (observabilityRef / observability) wird auf WaegInstance.spec.observability.langfuse abgebildet, wobei die Projekt-Keys als Secret-Referenz übergeben werden. Umgebungsvariablen sind der einzige deklarative Weg des Gateways — es liest seine Konfigurationsdatei nur beim ersten Start und danach gewinnt die Konsole — daher wird die Senke einmal beim Start gebaut und eine Key-Änderung rollt die Pods. Die Auflösungsreihenfolge ist wie bei LiteLLM: zuerst manuelle Keys, dann lizenziertes Auto-Wiring aus einer referenzierten Observability.

Erfordert ein aktuelles Gateway

Die WAEG_LANGFUSE_*-Variablen kamen nach Gateway 1.0.0-rc.7. Ein älteres Image meldet LangfuseRequiresNewerGateway, statt eine Einstellung anzunehmen, die nie wirksam würde.

SCIM-Bereitstellung ​

spec.waeg.scim aktiviert Wägs SCIM-v2-Endpunkte, sodass Ihr IdP Konsolenbenutzer direkt anlegt, aktualisiert und wieder entfernt, statt dass das jemand von Hand tut. SCIM ist unabhängig von spec.sso: es funktioniert auch auf einem Gateway, für das überhaupt kein interaktives Login konfiguriert ist — die übliche Form einer kopflosen Bereitstellungsintegration.

FeldBeschreibung
enabledSchaltet die Endpunkte ein. Standard true; ausgeschaltet antworten sie mit 404
tokenSecretRefErforderlich. Das Bearer-Token, das Ihr IdP vorlegt. Schlüssel standardmäßig scim-token
defaultRoleKonsolenrolle für neu bereitgestellte Benutzer: viewer, operator oder admin
defaultOrgIDWäg-Organisation, in der bereitgestellte Benutzer landen. Standard ist die eigene Organisation des Gateways, sofern spec.organization gesetzt ist
orgSourceWoher die Organisation eines bereitgestellten Benutzers kommt: waeg (das Gateway entscheidet), enterprise (aus der IdP-Nutzlast) oder none
roleMapIdP-Gruppenname → Wäg-Konsolenrolle. Wird als vollständige Ersetzung der Map gesendet
orgMapIdP-Wert → Wäg-Organisations-ID. Ebenfalls vollständige Ersetzung

roleMap und orgMap werden bei jedem Apply vollständig ersetzt statt zusammengeführt. Das Gateway trägt also exakt das, was hier deklariert ist — ein entfernter Eintrag entfernt die Zuordnung.

defaultOrgID kann entfallen, wenn das Gateway eine organization hat: Benutzer landen dann dort statt organisationslos. Das ist wichtig, denn ein Benutzer ohne Organisation verfehlt jede organisationsverankerte Modell-Berechtigung.

Die Endpunkte liegen unter /waeg/admin/v1/ee/scim/v2:

/waeg/admin/v1/ee/scim/v2/Users
/waeg/admin/v1/ee/scim/v2/Groups
/waeg/admin/v1/ee/scim/v2/ServiceProviderConfig

Richten Sie den SCIM-Konnektor Ihres IdP auf diese Basis-URL und hinterlegen Sie das Bearer-Token aus tokenSecretRef. Ohne Token antwortet jeder Aufruf mit 401.

Das Token ist eine Umgebungsvariable, kein gespeicherter Konfigurationswert

Der Operator projiziert das Token als WAEG_EE_SCIM_TOKEN auf die Gateway-Pods, statt es in den versiegelten Config-Store des Gateways zu schreiben. Dieser Store lässt sich nie wieder auslesen — eine dort abgelegte Kopie würde beim Rotieren des Secrets still veralten. Als Umgebungsvariable besteht die gesamte Rotation darin, das Secret zu erneuern und die Pods neu starten zu lassen.

Erfordert die Enterprise-Lizenz des Gateways — ohne sie antwortet das Modul mit 402 — und sonst nichts.

Nicht das Plattform-Feature sso-scim

Die AI-Core-Lizenz kennt ein eigenes Feature sso-scim. Dabei handelt es sich um eine separate, noch nicht implementierte Plattformfunktion, die mit dem hier beschriebenen Gateway-Modul nichts zu tun hat.

yaml
spec:
  organization: { name: navique-ag }
  instance:
    licenseSecretRef: { name: waeg-enterprise-license, key: license }
  waeg:
    scim:
      enabled: true
      tokenSecretRef: { name: waeg-scim-token, key: scim-token }
      defaultRole: viewer
      orgSource: waeg
      roleMap:
        "AI Platform Admins": admin
        "AI Platform Users": viewer

JWT-Authentifizierung auf der Datenebene ​

Wäg kann bei Datenebenen-Anfragen ein Bearer-JWT Ihres IdP validieren, sodass Aufrufer ein Token statt eines Schlüssels — oder zusätzlich dazu — vorlegen. Eingeschaltet wird das über den gemeinsamen Block spec.instance.jwtAuth (dasselbe Feld, das auch LiteLLM verwendet); feinjustiert wird es über das Wäg-spezifische spec.waeg.jwt.

spec.instance.jwtAuthWägs EE-Modul jwt
enabledenabled
publicKeyURLjwksUrl — der JWKS-Endpunkt, von dem die Signaturschlüssel geladen werden
issuerissuer — der erwartete iss
audienceaudience — die erwartete aud
userIDJWTFieldsubjectClaim — welcher Claim den Aufrufer identifiziert
spec.waeg.jwtBeschreibung
appClaimClaim, der die aufrufende Anwendung identifiziert. Standard azp
appClaimFallbacksClaims, die der Reihe nach probiert werden, wenn appClaim fehlt. Vollständige Ersetzung der Liste — eine leere Liste löscht Wägs eigene Standards (appid, client_id)
tenantClaimClaim mit Organisation/Mandant (sonst fällt Wäg auf tenant_id, dann tid zurück)
requireRegisteredApplicationWeist Token ab, deren Anwendung keine registrierte WaegApplication ist
allowMasterKeyLässt den Master-Key auf der Datenebene weiter funktionieren. Standard true
allowVirtualKeysLässt virtuelle Keys auf der Datenebene weiter funktionieren. Standard true
insecureSkipVerifyAkzeptiert ungeprüfte Token-Signaturen. Nur für die Entwicklung — Wäg verweigert das in einer Produktionsumgebung und in Kombination mit jedem Härtungsschalter

Die Härtungsschalter können den Start des Gateways verhindern

allowMasterKey: false und allowVirtualKeys: false beschränken die Datenebene auf JWTs, und Wäg startet nicht, solange der Rest nicht stimmig ist: jwtAuth.enabled: true, eine publicKeyURL (JWKS), eine audience und insecureSkipVerify: false. Ein halb konfigurierter Härtungsschalter legt das Gateway lahm, statt sich abzustufen — setzen Sie daher beide Hälften im selben Apply.

allowVirtualKeys: false legt außerdem jeden Anwendungsschlüssel still, auch den der ChatUI. Ändern Sie das bewusst.

Die LiteLLM-spezifischen Claim-Zuordnungen werden nicht angewendet.userRolesJWTField, userRoleJWTField, userAllowedRoles, enforceRBAC, userIDUpsert, teamIDsJWTField und adminJWTScope haben kein Wäg-Gegenstück: Wäg validiert das Token, leitet daraus aber weder Rollen noch Teams ab — die Autorisierung kommt aus OpenFGA und registrierten Anwendungen. Diese Felder werden über die Bedingung FeaturesSupported und in status.unsupportedFeatures gemeldet statt stillschweigend verworfen. Verwenden Sie stattdessen spec.waeg.jwt.requireRegisteredApplication und spec.waeg.modelAccess.

Erfordert die Enterprise-Lizenz des Gateways (Berechtigung jwt_api); ohne sie antwortet das Modul mit 402.

yaml
spec:
  instance:
    licenseSecretRef: { name: waeg-enterprise-license, key: license }
    jwtAuth:
      enabled: true
      publicKeyURL: https://login.microsoftonline.com/<tenant>/discovery/v2.0/keys
      issuer: https://login.microsoftonline.com/<tenant>/v2.0
      audience: <client-id>
      userIDJWTField: sub        # -> subjectClaim von Wäg
  waeg:
    jwt:
      appClaim: azp
      tenantClaim: tid
      requireRegisteredApplication: true
      # allowMasterKey: false    # nur zusammen mit den vier Einstellungen oben

Konsolen-Branding ​

Eine Enterprise-lizenzierte Wäg-Konsole trägt standardmäßig das Navique-Theme-Pack. Der Operator schreibt das eingebaute Pack in eine ConfigMap, die ihm gehört — <gateway-name>-branding, Schlüssel theme-pack.json — und verweist die Instanz darauf; der waeg-operator sendet es anschließend an die Branding-API.

SituationErgebnis
waeg.brandingConfigMapRef ist gesetzt, Lizenz enthält custom-brandingIhr Pack gewinnt. Der Operator legt nichts Eigenes an; CustomBranding=True
waeg.brandingConfigMapRef ist gesetzt, Lizenz enthält custom-branding nichtDas Navique-Pack wird angewendet, und CustomBranding=False (CustomBrandingUnlicensed) nennt den Grund. Der Verweis bleibt bestehen, sodass Ihr Pack greift, sobald die Lizenz es erlaubt
waeg.defaultBranding: falseAbwahl — die Konsole behält Wägs eigenes Erscheinungsbild
Kein instance.licenseSecretRefEs wird überhaupt nichts angelegt. Wäg verweigert Branding ohne Lizenz, eine ConfigMap würde hier also nur ein Aussehen ankündigen, das die Konsole nie zeigen kann
Sonst (Standard)Das Navique-Pack wird angewendet

Die ConfigMap wird bei jedem Reconcile neu geschrieben. Das Pack ist Teil des Operators, daher zieht ein Operator-Upgrade die Konsole mit, statt das zuerst installierte Pack für immer festzuschreiben — womit auch Handänderungen sinnlos sind, der nächste Reconcile setzt sie zurück. Für eigenes Styling (White-Label, lizenziertes Feature custom-branding) veröffentlichen Sie eine ConfigMap und verweisen mit brandingConfigMapRef darauf — oder nutzen Sie Gateway-Branding auf der Seite des Gateways in der Management-Konsole, das das Pack validiert, eine Vorschau zeigt und es anbindet (am Stack des Gateways, sofern ein Stack es verwaltet). Ein Stack reicht spec.gateway.waeg.brandingConfigMapRef / defaultBranding durch.

yaml
spec:
  instance:
    licenseSecretRef: { name: waeg-enterprise-license, key: license }
  waeg:
    defaultBranding: true          # Standard; false behält Wägs Erscheinungsbild
    # brandingConfigMapRef: { name: my-theme-pack, key: theme-pack.json }

ChatUI verbindet sich als Anwendung ​

Eine ChatUI mit gatewayRef auf ein Wäg-Gateway wird automatisch verdrahtet — allerdings über ein anderes Objekt als bei LiteLLM.

Wäg kennt keinen eigenständigen virtuellen Schlüssel: ein Schlüssel gehört zu einer Anwendung — einem organisationsverankerten Tenancy-Objekt mit eigenem Modellzugriff, eigenen Budgets und eigenem Audit-Trail. Der Operator registriert die ChatUI daher als WaegApplication und erzeugt einen WaegVirtualKey dazu:

WaegApplication (Identität der Chat-UI)  →  WaegVirtualKey (ihr Credential)

Der praktische Unterschied ist die Zuordnung: Verbrauch, Rate Limits und Audit-Einträge laufen auf „die Chat-UI" statt auf einen anonymen Schlüssel, und die Anwendung erscheint mit deklariertem Zweck in Wägs EU-AI-Act-Deployer-Inventar.

Das erfordert spec.organization am Gateway, denn Anwendungen sind organisationsverankert. Fehlt sie, wird die ChatUI mit genau dieser Begründung abgelehnt, statt auf einen Schlüssel zu warten, der nie erzeugt werden kann — setzen Sie stattdessen spec.gateway.{url, apiKeySecretRef}, um einen selbst erzeugten Schlüssel zu verwenden.

Die Credential-Rotation funktioniert wie bei LiteLLM: ein erhöhter Rotationsindex erzeugt einen neuen Schlüssel in einem frischen Secret, statt in place zu überschreiben. Die Anwendung bleibt über Rotationen hinweg stabil — sie ist die Identität, nicht das Credential.

Verschlüsselung im Transit ​

Sobald die Plattform-CA ein Zertifikat ausgestellt hat, aktiviert der Operator WaegInstance.spec.tls, sodass das Gateway HTTPS im Pod ausliefert — der Verkehr ist bis zum Pod verschlüsselt, nicht nur bis zum Edge. Das Gateway hat einen einzigen Listener, daher schaltet das alles gemeinsam um, und der waeg-operator zieht nach: Probes, appProtocol des Service, status.endpoint, der ServiceMonitor und die KEDA-Scale-URL.

Das CA-Bundle der Plattform geht mit. Die eigenen Admin-API-Aufrufe des Operators laufen über diese Verbindung; ohne die CA scheiterten sie an der x509-Prüfung gegen die clusterinterne CA und rissen Branding und jede Produkt-CR mit.

Erfordert Gateway 1.0.0-rc.9 oder neuer

In-Pod-TLS funktioniert erst ab Gateway 1.0.0-rc.9. Frühere Images stürzten beim Start ab, sobald spec.tls aktiviert war (rustls fand zwei eingebundene Crypto-Provider und keinen installiert). Der waeg-operator aktiviert es auf älteren Images nicht und meldet TLSUnsupportedGateway, statt eine Crash-Loop zu liefern — ein gepinntes älteres instance.image bleibt also bei Klartext, statt kaputtzugehen. waeg-operator 1.3.0 setzt rc.9 als Standard, der Standardpfad ist damit in Ordnung.

Guardrails ​

spec.guardrailRefs funktioniert an einem Wäg-Gateway, die Form unterscheidet sich aber. LiteLLM erwartet ein Objekt pro Ausführungsmodus, Wäg drei:

WaegGuardrailItem (eines pro Guardrail)  →  WaegGuardrailChain (Reihenfolge)
                                         →  WaegGuardrailBinding (wendet die Chain an)

Der Operator gibt alle drei mit scope: platform aus — eine Organisation ist nicht erforderlich. Das Binding nutzt mode: floor, läuft also immer: ein später in der Wäg-Konsole ergänztes Org- oder Team-Binding kann ein von der Plattform gesetztes Guardrail nicht abschalten.

Drei Item-Einstellungen sind entscheidend; der Operator wählt sie für Sie:

EinstellungWarum
roletransform-Engines schreiben Inhalte um. Als policy-Item behandelt Wäg die Umschreibung als Redact-Entscheidung, und die Ersetzung mitten im Stream passiert stillschweigend nicht. Katalog-Engines deklarieren ihre eigene Rolle
onErrorAus unreachableFallback übernommen (Standard fail_closed). Wäg ist standardmäßig fail-open, sodass bei einer Engine, die bewusst mit 502 antwortet, sonst der ursprüngliche Prompt an den Provider ginge
modeWäg kennt eine during_call-Phase, die LiteLLM fehlt. Eine Transform-Engine braucht sie, sonst bleiben gestreamte Antworten unverändert. Der mitgelieferte pseudonymizer läuft unter Wäg in allen drei Phasen

Externe Guardrails brauchen spec.waeg.path. Wäg sendet an eine vollständig angegebene URL, während LiteLLM /beta/litellm_basic_guardrail_api anhängt — der Operator kann also nicht erraten, wo ein selbst betriebener Endpunkt das Wäg-Protokoll bedient. Ohne den Pfad wird das Guardrail übersprungen und ein Event sagt das, statt dass der Operator einen Pfad rät und jeder Scan fehlschlägt, während das Gateway gesund aussieht. Katalog-Engines liefern ihren Pfad selbst (der pseudonymizer bedient /v1/waeg/check).

spec.waeg an einem Guardrail trägt zusätzlich optional role, timeoutMs, forwardIdentity und forwardSessionId. Die beiden letzten sind für Engines mit Sitzungszustand wichtig: die Namenszuordnungen des Pseudonymizers bleiben nur dann über mehrere Turns konsistent, wenn Wäg eine Identität weiterreicht — sonst fällt er auf die Request-ID zurück, die eine einzelne Anfrage zusammenhält, aber kein Gespräch.

Was nicht angewendet wird ​

Einige wenige Felder dieser CRD werden auf ein Wäg-Gateway weiterhin nicht angewendet. Eines davon zu setzen bricht nichts — es wird in status.unsupportedFeatures aufgeführt, die Bedingung FeaturesSupported wird False mit dem Grund UnsupportedByBackend, und ein Event wird ausgelöst.

FeldWarum
instance.saltKeyWäg hat keinen Salt-Key — verwenden Sie waeg.dataEncryptionKeySecretRef
instance.storePromptsInLogsKeine entsprechende Laufzeiteinstellung
instance.healthCheckWäg hat feste /healthz- und /readyz-Probes und keine konfigurierbare Hintergrundschleife
instance.jwtAuth — nur die Claim-ZuordnungenDie JWT-Authentifizierung selbst wird angewendet (siehe JWT-Authentifizierung auf der Datenebene). Abgelehnt werden nur userRolesJWTField, userRoleJWTField, userAllowedRoles, enforceRBAC, userIDUpsert, teamIDsJWTField und adminJWTScope: Wäg autorisiert über OpenFGA und registrierte Anwendungen, statt Rollen aus dem Token abzuleiten
instance.rolePermissionsWäg kennt keine LiteLLM-role_permissions — verwenden Sie waeg.modelAccess für organisationsverankerte Modell-ACLs
models[].rpm / tpm / timeout / maxTokensDas Wäg-Modellobjekt kennt keine Rate- oder Token-Limits, und das Gateway hat überhaupt kein Timeout pro Modell. Ein modellspezifisches Limit ist ein WaegBudget mit scope: model (ein organisationsweiter Topf für den Alias), das dieser Operator nicht ausgibt
organization.budgetDurationWäg-Budget-Richtlinien haben kein Zeitraumfeld

Außerhalb der Gateway-Spec sind die Identitätsressourcen auf Wäg vollständig unterstützt: Identity, Organization und Team emittieren WaegUser, WaegOrganization, WaegTeam sowie die org- und team-bezogenen WaegBudget-Richtlinien. Richten Sie sie mit type: gateway auf dieses Gateway aus, dann folgen sie dessen spec.type — siehe Backend-Auswahl.

Zwei Identitätsfelder werden auf Wäg nicht angewendet: teamRefs und budget einer Identity. Wäg führt die Mitgliedschaft am Team (tragen Sie die Adresse in members des Teams ein), und ein Limit pro Benutzer ist ein WaegBudget mit scope: user. Eine Wäg-Identity erhält außerdem ein erzeugtes Secret mit dem Konsolen-Passwort und meldet erst dann Ready, wenn der WaegUser Synced ist — siehe Wäg-Konten.

Vorab abgelehnt ​

Statt eine Ressource zu emittieren, die sich festfahren würde, lehnt der Operator Folgendes mit Ready=False und dem Grund InvalidTarget ab:

  • type: waeg ohne spec.waeg oder ohne spec.waeg.clickhouse
  • waeg.worker.enabled bei topology: AllInOne
  • mehr als ein API-Replica ohne waeg.redis
  • waeg.modelAccess ohne spec.organization

Beispiel ​

yaml
apiVersion: core.navique.com/v1alpha1
kind: Gateway
metadata:
  name: waeg-gateway
  namespace: forge-gateway
spec:
  type: waeg
  secretsRef: { name: forge-secrets }
  database:
    mode: postgresCluster
    postgresClusterRef: { name: forge-pg, namespace: forge-data }
    databaseName: waeg          # niemals ein Schema mit einem LiteLLM-Gateway teilen
  instance:
    replicas: 2
    masterKey: { autoGenerate: true }
    licenseSecretRef: { name: waeg-enterprise-license, key: license }   # schaltet jedes EE-Modul frei
    jwtAuth:
      enabled: true
      publicKeyURL: https://login.microsoftonline.com/<tenant>/discovery/v2.0/keys
      issuer: https://login.microsoftonline.com/<tenant>/v2.0
      audience: <client-id>
      userIDJWTField: sub
  waeg:
    topology: Split
    worker: { enabled: true, replicas: 2, jobWorkers: 4 }
    storageMode: split          # der Standard; `single` verzichtet ganz auf ClickHouse
    clickhouse: { mode: ref, ref: { name: forge-ch, namespace: forge-data } }
    redis:      { mode: ref, ref: { name: forge-redis, namespace: forge-data } }
    # openfga weggelassen -> der Operator rollt ein Postgres-gestütztes OpenFGA aus
    # defaultBranding ist standardmäßig true -> das Navique-Theme-Pack wird angewendet
    scim:
      enabled: true
      tokenSecretRef: { name: waeg-scim-token, key: scim-token }
      defaultRole: viewer
      roleMap: { "AI Platform Admins": admin }
    jwt:
      appClaim: azp
      requireRegisteredApplication: true
    modelAccess:
      openByDefault: false
      fallbackMode: deny
      grants:
        - models: [premium, economy]
  organization: { name: navique-ag, maxBudget: 2000, rpmLimit: 1000 }
  teams:
    - { name: data-engineering }
  models:
    - name: gpt-5-4
      modelName: premium
      model: azure/gpt-5.4      # -> Provider "azure", modelId "gpt-5.4"
      refSecretKey: OPENAI_API_KEY
      credentials: { apiBase: "https://forge-foundry.openai.azure.com/openai/v1" }
      fallbacks: [economy]

Prüfen, was übersprungen wurde:

bash
kubectl -n forge-gateway get gateway waeg-gateway \
  -o jsonpath='{.status.conditions[?(@.type=="FeaturesSupported")].message}'

In einem Stack ​

Stack.spec.gateway.type: waeg wählt Wäg für einen ganzen Stack. Der Stack erfordert dann datastores.clickhouse.enabled (die Admission lehnt ihn sonst ab), verdrahtet sein eigenes ClickHouse und Redis automatisch als zweite Ebene und nennt die logische Datenbank des Gateways waeg, damit sie nie auf einem LiteLLM-Schema landet. Stack.spec.gateway.waeg reicht die Topologie-, Worker-, OpenFGA- und Autoscaling-Einstellungen sowie scim und jwt durch; die Enterprise-Lizenz wird einmalig als Stack.spec.gateway.licenseSecretRef deklariert, und Stack.spec.gateway.jwtAuth schaltet die JWT-Authentifizierung der Datenebene ein.

Status ​

status.url stellt den Gateway-Endpunkt bereit (öffentlich, wenn Ingress aktiviert ist, ansonsten clusterintern), zusätzlich zur Bereitschaft der Instanz, den Modell-/Team-Anzahlen und der Bereitschaft der Datenbank. status.unsupportedFeatures listet jedes konfigurierte Feld auf, das der gewählte Gateway-Typ nicht umsetzen kann (bei type: litellm immer leer); die Bedingung FeaturesSupported spiegelt dies wider.

Lizenzhinweise ​

Teams, Organisationen und Budgets sind Teil des Features multi-tenancy; mehr als ein Gateway erfordert ein gateways-Limit oberhalb des Community-Standards von 1. Siehe Editions & Licensing.

Open Core unter AGPL-3.0. Enterprise-Komponenten sind proprietär und lizenzgebunden.