Skip to content

Gateway ​

Ambito: namespaced · Workload: LiteLLM tramite il litellm-operator, oppure Wäg tramite il waeg-operator

Il gateway AI — il punto d'ingresso del traffico verso i modelli, con modelli, team, organization, budget ed export opzionale delle trace verso Langfuse.

spec.type sceglie l'implementazione. Il valore predefinito è litellm, quindi il resto di questa pagina descrive il gateway LiteLLM salvo diversa indicazione; vedi Gateway Wäg (type: waeg) per le differenze.

Spec ​

CampoTipoDescrizione
typelitellm | waegImplementazione del gateway. Predefinito litellm.
waegobjectWiring specifico di Wäg (topologia, piani ClickHouse/Redis, OpenFGA). Obbligatorio con type: waeg
secretsRefLocalRef (facoltativo)SecretsManagement nello stesso namespace da attendere. Omettilo per usare normali Secret Kubernetes gestiti da te — vedi secretsRef
databaseobject (obbligatorio)Dove LiteLLM conserva il proprio stato
instanceobjectImmagine/tag, repliche, risorse, chiavi master/salt, SSO
organizationobjectOrganization LiteLLM + budget
teams[]listTeam con budget per team
models[]listIl catalogo dei modelli
guardrailRefs[]ObjectRefCR Guardrail da collegare a questo gateway (soggetto alla licenza guardrail; emessi come LiteLLMGuardrail tramite il proxy license-gate di ciascun guardrail)
observabilityRefObjectRefUna risorsa Observability per l'export delle trace (auto-wiring se previsto dalla licenza)
observabilityobjectFallback manuale per la callback Langfuse
ssoobjectLogin OIDC/SSO per la LiteLLM Admin UI (vedi SSO)
enableEntraSSOboolDeprecato — usa sso con provider: azure-entra

database ​

CampoDescrizione
modepostgresCluster (riferimento a un PostgresCluster) oppure external
postgresClusterRefIl cluster da usare (modalità postgresCluster)
databaseNameDatabase all'interno del cluster condiviso
connectionSecretRefSecret con DATABASE_URL (modalità external)

models[] ​

CampoDescrizione
name / modelName / modelNome visualizzato, nome del modello in LiteLLM e id del modello presso il provider
refSecretKeyChiave, nel Secret delle credenziali dei modelli, che contiene la API key
credentials.apiBaseEndpoint del provider, per qualsiasi provider che ne richieda uno esplicito (Azure OpenAI / AI Foundry, self-hosted, un proxy)
credentials.apiVersionVersione dell'API del provider, quando il provider la richiede (ad es. Azure OpenAI / AI Foundry)
rpm / tpm / timeout / maxTokensLimiti per modello (solo LiteLLM)
provider / providerName / modelId / fallbacks / weightCampi di catalogo specifici di Wäg — vedi Gateway Wäg

Quando un modello richiede un endpoint personalizzato e/o una versione dell'API, impostali in credentials — l'operatore li passa al gateway insieme alla API key presa da refSecretKey. Mantieni in apiBase il solo endpoint e metti la versione in apiVersion (non inserire ?api-version= nell'URL). Il meccanismo è indipendente dal provider: l'operatore emette ciò che fornisci e non tratta mai un provider come caso speciale.

instance.healthCheck ​

Regola i controlli di salute in background dei modelli di LiteLLM. Disattivati per impostazione predefinita: GET /health interroga i modelli su richiesta invece di eseguire un ciclo in background. I controlli in background generano traffico periodico verso l'upstream e, con alcuni provider, possono comportare costi o raggiungere i rate limit; attivali quindi solo se vuoi che /health restituisca risultati in cache.

CampoTipoDescrizione
enabledboolAttiva i controlli di salute in background. Predefinito false (disattivati).
intervalSecondsintSecondi tra un controllo e l'altro (predefinito LiteLLM 300). Si applica solo con enabled: true.
yaml
instance:
  healthCheck:
    enabled: true
    intervalSeconds: 300

Corrisponde a generalSettings.backgroundHealthChecks / healthCheckInterval del LiteLLMInstance. Quando sono disattivati, l'operatore imposta esplicitamente backgroundHealthChecks: false.

Cosa emette ​

Il controller risolve il database, garantisce la presenza del litellm-operator (attendendo che i suoi CRD siano Established), quindi emette, in ordine:

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

(Tutti nel gruppo API litellm.palena.ai/v1alpha1.)

Collegamento del database ​

  • postgresCluster — l'operatore risolve il cluster referenziato, crea il database e il ruolo litellm, genera la password e inietta il Secret delle credenziali. Nessun secret manuale necessario.
  • external — fornisci un connectionSecretRef che contenga un DATABASE_URL.

Export delle trace verso Langfuse ​

  • Con la funzionalità auto-wiring e un observabilityRef, l'operatore collega la callback Langfuse di LiteLLM (host + chiavi pubblica/segreta) a partire dall'Observability referenziata, così le trace vengono esportate automaticamente.
  • Senza di essa (o con un Langfuse community che non può generare chiavi di progetto), crea il progetto e la chiave nella UI di Langfuse e imposta spec.observability.{host, callbackSecretRef} (chiavi publicKey / secretKey).

Vedi Auto-Wiring per i due gate coinvolti.

Login SSO / OIDC ​

spec.sso abilita il single sign-on per la Admin UI di LiteLLM, tradotto nel blocco LiteLLMInstance.spec.sso. Le credenziali del client OAuth provengono da un Secret nello stesso namespace (tramite SecretsManagement — mai inline).

CampoDescrizione
issuerURLIssuer OIDC / URL base di discovery
clientSecretRef.nameSecret che contiene il client OAuth (chiavi predefinite client-id / client-secret, sovrascrivibili con clientIDKey / clientSecretKey)
providergeneric-oidc (predefinito), azure-entra, google oppure okta
tenantIDID della directory/del tenant (per azure-entra)
authorizationEndpoint / tokenEndpoint / userinfoEndpointEndpoint espliciti — obbligatori per generic-oidc (LiteLLM non esegue la discovery)
scopesScope richiesti (predefiniti openid, profile, email)
providerNameEtichetta visualizzata
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 }

Licenze

L'SSO di LiteLLM è gratuito fino a 5 utenti; l'SSO completo/illimitato richiede una licenza LiteLLM Enterprise. L'operatore Navique non applica alcun gating sul campo stesso.

URL di redirect con accesso pubblico

LiteLLM costruisce il redirect_uri OAuth a partire da PROXY_BASE_URL, derivato dall'ingress del Gateway. Per l'SSO con accesso pubblico, esponi il Gateway sul suo host pubblico con TLS — spec.ingress.enabled: true, spec.ingress.host: <public-host> e spec.ingress.tls: true — in modo che la callback si risolva in https://<public-host>/sso/callback. Registra **esattamente quell'**URL presso il tuo IdP. Senza ingress.tls: true il redirect ripiega su un indirizzo in http semplice/interno al cluster e la callback OAuth fallisce. (status.endpoint sul LiteLLMInstance sottostante riporta sempre l'URL .svc interno al cluster — è l'indirizzo della admin API usato dall'operatore stesso, non la base del redirect SSO.)

Il booleano deprecato enableEntraSSO: true funziona ancora quando sso non è impostato — genera una configurazione azure-entra che legge il Secret legacy entra-sso-credentials. Preferisci sso con provider: azure-entra.

Autenticazione API tramite JWT e RBAC ​

spec.instance.jwtAuth attiva l'autenticazione API basata su JWT: LiteLLM convalida un JWT bearer del tuo IdP a ogni richiesta e ne mappa i claim su ruoli/team (a differenza di sso, che è il login via browser per la Admin UI). Combinalo con spec.instance.rolePermissions per limitare quali modelli può chiamare ciascun ruolo.

CampoCorrisponde a (litellm_jwtauth)
jwtAuth.enabledgeneral_settings.enable_jwt_auth
jwtAuth.publicKeyURLEndpoint JWKS (JWT_PUBLIC_KEY_URL) — obbligatorio: senza di esso LiteLLM non può convalidare alcun token
jwtAuth.issuerissuer iss atteso del token (JWT_ISSUER)
jwtAuth.audienceaudience aud attesa del token (JWT_AUDIENCE)
jwtAuth.userRolesJWTFielduser_roles_jwt_field — claim JWT che contiene l'elenco dei ruoli
jwtAuth.userAllowedRolesuser_allowed_roles — ruoli mappati su un internal_user
jwtAuth.enforceRBACenforce_rbac — nega i chiamanti i cui ruoli non sono ammessi
jwtAuth.userRoleJWTFielduser_role_jwt_field (ruolo singolo)
jwtAuth.userIDJWTFielduser_id_jwt_field — claim usato come id utente (sub / oid / preferred_username)
jwtAuth.userIDUpsertuser_id_upsert — crea automaticamente l'utente LiteLLM al primo login
jwtAuth.teamIDsJWTFieldteam_ids_jwt_field
jwtAuth.adminJWTScopeadmin_jwt_scope
rolePermissions.<role>.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  # REQUIRED (JWKS)
      issuer: https://login.microsoftonline.com/<tenant>/v2.0
      audience: <client-id>
      userIDJWTField: sub          # claim identifying the user (sub / oid / preferred_username)
      userIDUpsert: true           # auto-create the LiteLLM user on first login
      userRolesJWTField: roles
      userAllowedRoles: ["basic_user"]
      enforceRBAC: true
    rolePermissions:
      internal_user:
        models: ["anthropic-claude"]

Su un gateway Wäg lo stesso blocco jwtAuth attiva il modulo JWT del data plane di Wäg, con le opzioni specifiche di Wäg in spec.waeg.jwt — vedi Autenticazione JWT del data plane.

Solo Enterprise

enable_jwt_auth, enforce_rbac e role_permissions sono funzionalità LiteLLM Enterprise — imposta instance.licenseSecretRef su una licenza LiteLLM Enterprise valida, altrimenti non hanno alcun effetto. Impostare una qualsiasi voce di rolePermissions attiva general_settings.enforce_rbac, così le restrizioni vengono effettivamente applicate.

Esempio ​

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 (here: an 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"

Gateway Wäg (type: waeg) ​

Wäg è un gateway AI alternativo, gestito dal waeg-operator incluso (gateway.waeg.ai). È un prodotto diverso, non un clone di LiteLLM, e questo CRD non finge il contrario: tutto ciò che segue è una differenza reale, e qualsiasi cosa Wäg non sappia fare viene segnalata, mai scartata silenziosamente.

Cosa cambia ​

AspettoLiteLLMWäg
Storageun Postgres (+ Redis facoltativo)doppio piano per impostazione predefinita (storageMode: split): Postgres e ClickHouse. storageMode: single mantiene i dati analitici nel Postgres del control plane e non richiede ClickHouse
Redisfacoltativoobbligatorio non appena l'API gira con più di una replica (quote HA)
Autorizzazioneruoli del proxy / virtual keyOpenFGA — esterno, oppure un'istanza basata su Postgres distribuita dall'operatore
Modello di processoun solo Deployment proxyAllInOne, oppure Split (api + worker facoltativo)
Catalogoun unico oggetto modelloprovider (connessione + credenziale) e alias di modello che vi punta
Budgetsugli oggetti organization/teampolicy di budget con radice nell'organization, separate

spec.waeg ​

CampoDescrizione
topologyAllInOne (predefinito) oppure Split (*-api più un Deployment *-worker facoltativo)
jobWorkersWorker in-process per i job durevoli (solo AllInOne)
workerIl Deployment worker dedicato (enabled, replicas, jobWorkers, resources) — richiede topology: Split
storageModeDove risiedono i dati analitici: split (predefinito — ClickHouse) oppure single (il Postgres del control plane, nessun ClickHouse) — vedi Modalità di storage analitico
clickhouseIl piano analitico — obbligatorio per storageMode: split, ignorato e non richiesto per single: mode: ref verso un ClickHouseCluster, oppure mode: external con un Secret di connessione
clickhouseDatabaseIl database ClickHouse in cui vengono scritti i dati analitici in modalità split. Predefinito waeg; l'operatore lo crea su un cluster managed o adopt
redisLo store delle quote HA: mode: ref verso un RedisInstance, oppure external. Obbligatorio con più di una replica API
openfgaapiUrl / apiUrlSecretRef esterni, oppure omettilo e l'operatore distribuisce un OpenFGA basato su Postgres (image, replicas, resources, storeId, modelId)
autoscalingHPA dell'API su CPU/memoria (enabled, minReplicas, maxReplicas, target). Lo scaling sulla profondità della coda richiede KEDA e non è collegato
artifactsVolume per job/media: emptyDir (predefinito), pvc (un claim esistente) oppure none
bootstrapAdminCrea il primo admin della console da un unico Secret (secretRef, emailKey, passwordKey)
dataEncryptionKeySecretRefLa chiave con cui Wäg sigilla le revisioni di configurazione (l'equivalente Wäg della salt key di LiteLLM)
configYAMLSovrascrive il seed di bootstrap waeg.yaml. Solo dati non segreti — viene renderizzato in una ConfigMap
brandingConfigMapRefIl tuo theme pack Enterprise (JSON), che l'operatore invia via POST alla Admin API una volta Ready. Sostituisce il pack Navique integrato — funzionalità soggetta a licenza custom-branding; vedi Branding della console
defaultBrandingApplica il theme pack Navique integrato quando il gateway ha una licenza Enterprise e nessun brandingConfigMapRef è impostato. Predefinito true
modelAccessL'ACL dei modelli con radice nell'organization (openByDefault, fallbackMode, grants[]). Richiede spec.organization
scimProvisioning utenti SCIM v2 (enabled, tokenSecretRef, defaultRole, defaultOrgID, orgSource, roleMap, orgMap) — vedi Provisioning SCIM
jwtLe opzioni JWT del data plane specifiche di Wäg (appClaim, appClaimFallbacks, tenantClaim, requireRegisteredApplication, allowMasterKey, allowVirtualKeys, insecureSkipVerify) — vedi Autenticazione JWT del data plane

Postgres proviene sempre da spec.database — lo stesso campo, risolto allo stesso modo. L'operatore assembla ogni stringa di connessione in un unico Secret <gateway>-waeg-storage di sua proprietà e vi fa riferimento per chiave, così nessun URL contenente credenziali finisce mai nel CR.

Modalità di storage analitico ​

Wäg mantiene il suo control plane (configurazione, chiavi, organization, team, applicazioni) in Postgres e il suo piano analitico (log delle richieste, utilizzo, spesa) in uno store selezionato da spec.waeg.storageMode:

ModalitàDati analitici inClickHouse necessario
split (predefinito)ClickHouse — spec.waeg.clickhouse deve puntarvisì
singlelo stesso Postgres del control plane (spec.database)no

split è il valore predefinito di questo operatore: è ciò che il Gateway ha sempre emesso, ed è ciò che regge i volumi elevati. Il valore predefinito di Wäg upstream è invece single, ed è il suo punto di partenza consigliato — ed è proprio per questo che esiste questo campo. Richiedere un ClickHouse per ogni gateway imponeva una dipendenza che upstream aveva già eliminato e, per un deployment piccolo o di valutazione, raddoppia i datastore da gestire, dimensionare e sottoporre a backup senza alcun beneficio.

Con single il WaegInstance emesso non contiene alcun blocco clickhouse; spec.waeg.clickhouse viene ignorato e non è richiesto.

Cambiare modalità non migra lo storico analitico

I due piani sono store separati. Cambiare storageMode su un gateway in esecuzione lo fa puntare all'altro — i dati analitici già scritti restano dove erano e non sono più visibili nella console. Né l'operatore né Wäg li copiano. Scegli una modalità prima di raccogliere dati a cui tieni, oppure esportali prima.

single — solo 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         # analytics land in forge-pg, next to the control plane
    # no clickhouse block — none is needed, and one here would be ignored

split — dati analitici 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          # the default; may be omitted
    clickhouse: { mode: ref, ref: { name: forge-ch, namespace: forge-data } }
    clickhouseDatabase: waeg    # the default
    redis:      { mode: ref, ref: { name: forge-redis, namespace: forge-data } }

Wäg crea solo le proprie tabelle, mai il proprio database. Su un ClickHouseCluster managed o adopt l'operatore dichiara quel database in spec.databases e lo crea per te; su un cluster external devi crearlo tu, altrimenti il gateway termina all'avvio con Database waeg does not exist.

Modelli: provider + alias ​

Il catalogo di Wäg separa la connessione upstream dall'alias esposto ai client, quindi ogni voce di spec.models emette un WaegProvider e un WaegModel. I modelli che condividono un driver condividono un unico provider.

CampoDescrizione
providerDriver del provider (openai, azure, anthropic, …). Predefinito: il prefisso di model (azure/gpt-4o → azure), altrimenti openai
providerNameDà il nome alla voce di catalogo del provider, così più modelli possono condividere una connessione. Predefinito: il driver
modelIdId del modello lato provider. Predefinito: model senza prefisso (azure/gpt-4o → gpt-4o)
fallbacksAlias di modello da provare quando questo fallisce
weightBilancia questo deployment rispetto ad altri sullo stesso alias

Cosa emette ​

WaegInstance → WaegOrganization → WaegBudget (org caps) → WaegTeam(s)
             → WaegProvider(s)  → WaegModel(s)          → WaegModelAccess

(Tutti nel gruppo API gateway.waeg.ai/v1alpha1.)

Licenza Enterprise ​

spec.instance.licenseSecretRef contiene la licenza Wäg Enterprise del gateway. Arriva all'istanza come WaegInstance.spec.secrets.licenseKey; la chiave del Secret è per impostazione predefinita license.

Ogni modulo Wäg Enterprise dipende da essa — SSO, SCIM, audit, CMEK, FIPS e branding allo stesso modo — e l'applicazione è incondizionata: un'immagine del gateway con EE collegato ma senza licenza risponde 402 license_required. Eseguire la build Enterprise non basta di per sé: se un modulo riporta LicenseRequired, è questo campo a mancare.

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

La licenza è referenziata, mai inline: lascia che il backend SecretsManagement materializzi il Secret (ESO da Key Vault, oppure un SealedSecret) come per ogni altra credenziale. In uno Stack viene dichiarata una sola volta come spec.gateway.licenseSecretRef e passata al Gateway.

SSO ed export delle trace ​

Entrambi funzionano, attraverso percorsi diversi da quelli di LiteLLM.

L'SSO (spec.sso) viene applicato tramite un CR WaegEnterpriseConfig, che configura i moduli Enterprise di Wäg attraverso la sua admin API anziché tramite le variabili d'ambiente dell'istanza. L'operatore legge il client id dal tuo Secret e lo imposta come campo in chiaro (un client id è pubblico per costruzione — viaggia nell'URL di autorizzazione del browser), mentre il client secret resta un riferimento a un Secret, proiettato sul pod come WAEG_EE_OIDC_CLIENT_SECRET. È una scelta deliberata: il CR potrebbe anche scrivere il secret nello store di configurazione sigillato del gateway, il che lo metterebbe nelle revisioni di configurazione del gateway invece di lasciarlo in Kubernetes.

L'URI di redirect è derivato come <public origin>/waeg/ui/v1/ee/sso/callback — il gateway rifiuta qualsiasi valore che non contenga quel percorso. L'SSO richiede quindi spec.ingress con un host; in sua assenza l'operatore emette un avviso anziché una callback che non potrebbe mai risolversi. Registra esattamente quell'URL presso il tuo IdP.

Richiede la build Enterprise del gateway e una licenza; il CR riporta EnterpriseNotLinked o LicenseRequired per ciascun modulo se manca l'una o l'altra.

L'export delle trace (observabilityRef / observability) corrisponde a WaegInstance.spec.observability.langfuse, con le chiavi di progetto fornite come riferimento a un Secret. Le variabili d'ambiente sono l'unico percorso dichiarativo del gateway — che popola il proprio file di configurazione solo al primo avvio, dopodiché prevale la console — quindi il sink viene costruito una sola volta all'avvio e un cambio di chiave riavvia i pod. L'ordine di risoluzione è lo stesso di LiteLLM: prima le chiavi manuali, poi l'auto-wiring soggetto a licenza da un'Observability referenziata.

Richiede un gateway recente

Le variabili WAEG_LANGFUSE_* sono arrivate dopo il gateway 1.0.0-rc.7. Un'immagine più vecchia riporta LangfuseRequiresNewerGateway invece di accettare un'impostazione che non avrebbe mai effetto.

Provisioning SCIM ​

spec.waeg.scim attiva gli endpoint SCIM v2 di Wäg, così il tuo IdP crea, aggiorna e disattiva direttamente gli utenti della console invece di farlo fare a qualcuno a mano. SCIM è indipendente da spec.sso: funziona anche su un gateway senza alcun login interattivo configurato, che è la configurazione tipica di un'integrazione di provisioning headless.

CampoDescrizione
enabledAttiva gli endpoint. Predefinito true; quando disattivati rispondono 404
tokenSecretRefObbligatorio. Il bearer token presentato dal tuo IdP. Chiave predefinita scim-token
defaultRoleRuolo della console assegnato a un utente appena creato: viewer, operator oppure admin
defaultOrgIDOrganization Wäg in cui finiscono gli utenti creati. Predefinita: l'organization del Gateway stesso quando spec.organization è impostato
orgSourceDa dove proviene l'organization di un utente creato: waeg (decide il gateway), enterprise (il payload dell'IdP) oppure none
roleMapNome del gruppo nell'IdP → ruolo della console Wäg. Inviata come sostituzione dell'intera mappa
orgMapValore dell'IdP → id dell'organization Wäg. Sostituzione dell'intera mappa

roleMap e orgMap vengono sostituite per intero a ogni applicazione, non unite, così il gateway contiene sempre esattamente ciò che è dichiarato qui — eliminare una voce elimina la mappatura.

Lasciare defaultOrgID non impostato va bene quando il Gateway ha un'organization: gli utenti finiscono lì anziché senza organization, il che è importante perché un utente senza organization non riceve nessuno dei grant di accesso ai modelli con radice nell'organization.

Gli endpoint si trovano sotto /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

Punta il connettore SCIM del tuo IdP a quell'URL base con il bearer token di tokenSecretRef. Senza il token ogni chiamata risponde 401.

Il token è una variabile d'ambiente, non un valore di configurazione memorizzato

L'operatore proietta il token sui pod del gateway come WAEG_EE_SCIM_TOKEN invece di scriverlo nello store di configurazione sigillato del gateway. Quello store non può mai essere riletto, quindi una copia scritta lì diventerebbe silenziosamente obsoleta nel momento in cui ruoti il Secret. Come variabile d'ambiente, ruotare il Secret e lasciare che i pod si riavviino è l'intera procedura di rotazione.

Richiede la licenza Enterprise del gateway — senza di essa il modulo risponde 402 — e nient'altro.

Non è la funzionalità sso-scim della piattaforma

La licenza di AI Core ha una propria funzionalità sso-scim. Si tratta di una capacità di piattaforma separata, non ancora implementata, e non ha alcuna relazione con il modulo del gateway descritto qui.

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

Autenticazione JWT del data plane ​

Wäg può convalidare un JWT bearer del tuo IdP sulle richieste del data plane, così i chiamanti presentano un token invece di — o insieme a — una chiave. Si attiva con il blocco condiviso spec.instance.jwtAuth (lo stesso campo usato da LiteLLM) e si regola con spec.waeg.jwt, specifico di Wäg.

spec.instance.jwtAuthModulo EE jwt di Wäg
enabledenabled
publicKeyURLjwksUrl — l'endpoint JWKS da cui vengono recuperate le chiavi di firma dei token
issuerissuer — l'iss atteso
audienceaudience — l'aud attesa
userIDJWTFieldsubjectClaim — quale claim identifica il chiamante
spec.waeg.jwtDescrizione
appClaimClaim che identifica l'applicazione chiamante. Predefinito azp
appClaimFallbacksClaim provati in ordine quando appClaim è assente. Sostituzione dell'intero elenco — un elenco vuoto cancella i valori predefiniti di Wäg (appid, client_id)
tenantClaimClaim che contiene l'organization/il tenant (altrimenti Wäg ripiega su tenant_id, poi tid)
requireRegisteredApplicationRifiuta i token la cui applicazione non è un WaegApplication registrato
allowMasterKeyMantiene funzionante la master key sul data plane. Predefinito true
allowVirtualKeysMantiene funzionanti le virtual key sul data plane. Predefinito true
insecureSkipVerifyAccetta firme dei token non verificate. Solo per lo sviluppo — Wäg lo rifiuta in un ambiente di produzione e insieme a qualsiasi flag di hardening

Gli interruttori di hardening possono impedire l'avvio del gateway

allowMasterKey: false e allowVirtualKeys: false limitano il data plane ai soli JWT, e Wäg si rifiuta di avviarsi se il resto non è coerente: jwtAuth.enabled: true, un publicKeyURL (JWKS), un'audience e insecureSkipVerify: false. Un flag di hardening configurato a metà mette fuori servizio il gateway invece di degradarlo — imposta entrambe le parti nella stessa applicazione.

allowVirtualKeys: false blocca anche ogni chiave di applicazione, inclusa quella della ChatUI. Modificalo consapevolmente.

Le mappature dei claim specifiche di LiteLLM non vengono applicate.userRolesJWTField, userRoleJWTField, userAllowedRoles, enforceRBAC, userIDUpsert, teamIDsJWTField e adminJWTScope non hanno un equivalente in Wäg: Wäg convalida il token ma non ne ricava mai ruoli o team — l'autorizzazione proviene da OpenFGA e dalle applicazioni registrate. Impostarli viene segnalato nella condizione FeaturesSupported e in status.unsupportedFeatures invece di essere scartato silenziosamente. Usa invece spec.waeg.jwt.requireRegisteredApplication e spec.waeg.modelAccess.

Richiede la licenza Enterprise del gateway (entitlement jwt_api); senza di essa il modulo risponde 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        # -> Wäg's subjectClaim
  waeg:
    jwt:
      appClaim: azp
      tenantClaim: tid
      requireRegisteredApplication: true
      # allowMasterKey: false    # only together with the four settings above

Branding della console ​

Una console Wäg con licenza Enterprise adotta per impostazione predefinita il theme pack Navique. L'operatore materializza il pack integrato in una ConfigMap di sua proprietà — <gateway-name>-branding, chiave theme-pack.json — e vi fa puntare l'istanza; il waeg-operator la invia poi via POST alla API di branding.

SituazioneRisultato
waeg.brandingConfigMapRef è impostato, la licenza include custom-brandingPrevale il tuo pack. L'operatore non crea nulla di proprio; CustomBranding=True
waeg.brandingConfigMapRef è impostato, la licenza non include custom-brandingViene applicato il pack Navique e CustomBranding=False (CustomBrandingUnlicensed) ne indica il motivo. Il riferimento resta, così il tuo pack si applica non appena la licenza lo consente
waeg.defaultBranding: falseOpt-out — la console mantiene l'aspetto di Wäg
Nessun instance.licenseSecretRefNon viene creato nulla. Wäg rifiuta il branding senza licenza, quindi una ConfigMap qui pubblicizzerebbe soltanto uno stile che la console non potrà mai mostrare
Altrimenti (il caso predefinito)Viene applicato il pack Navique

La ConfigMap viene riscritta a ogni riconciliazione. Il pack è incluso nell'operatore, quindi un aggiornamento dell'operatore fa avanzare la console invece di bloccarla sul pack installato per primo — il che significa anche che modificarla a mano è inutile: la riconciliazione successiva annulla la modifica. Per usare uno stile tuo (white-label, funzionalità soggetta a licenza custom-branding), pubblica una ConfigMap e fai puntare brandingConfigMapRef ad essa — oppure usa Branding del gateway nella pagina del gateway della console di gestione, che convalida il pack, ne mostra un'anteprima e lo collega (sullo Stack del gateway, se è uno Stack a gestirlo). Uno Stack inoltra spec.gateway.waeg.brandingConfigMapRef / defaultBranding.

yaml
spec:
  instance:
    licenseSecretRef: { name: waeg-enterprise-license, key: license }
  waeg:
    defaultBranding: true          # the default; false keeps Wäg's own livery
    # brandingConfigMapRef: { name: my-theme-pack, key: theme-pack.json }

La ChatUI si connette come applicazione ​

Una ChatUI con gatewayRef che punta a un gateway Wäg viene collegata automaticamente, ma attraverso un oggetto diverso da quello usato con LiteLLM.

Wäg non ha virtual key autonome: una chiave appartiene a un'applicazione — un oggetto di tenancy con radice nell'organization, con propri accessi ai modelli, budget e audit trail. L'operatore registra quindi la ChatUI come WaegApplication e genera un WaegVirtualKey associato:

WaegApplication (the chat UI's identity)  →  WaegVirtualKey (its credential)

La differenza pratica è l'attribuzione: spesa, rate limit e voci di audit vengono imputati alla "chat UI" invece che a una chiave anonima, e l'applicazione compare nell'inventario dei deployer previsto dall'EU AI Act di Wäg con una finalità dichiarata.

Ciò richiede spec.organization sul Gateway, perché le applicazioni hanno radice nell'organization. In sua assenza la ChatUI viene rifiutata con questa motivazione invece di restare in attesa di una chiave che non potrà mai essere generata — imposta invece spec.gateway.{url, apiKeySecretRef} per usare una chiave generata da te.

La rotazione delle credenziali funziona come con LiteLLM: incrementare l'indice di rotazione genera una nuova chiave in un Secret nuovo invece di sovrascriverla. L'applicazione resta stabile attraverso le rotazioni — è l'identità, non la credenziale.

Crittografia in transito ​

Quando la CA di piattaforma ha emesso un certificato, l'operatore attiva WaegInstance.spec.tls in modo che il gateway serva HTTPS all'interno del pod — il traffico è cifrato fino al pod, non solo fino all'edge. Il gateway ha un unico listener, quindi questo cambia tutto insieme e il waeg-operator si adegua: probe, appProtocol del Service, status.endpoint, il ServiceMonitor e l'URL di scaling di KEDA.

Insieme viene fornito il bundle della CA di piattaforma. Le chiamate alla Admin API effettuate dall'operatore stesso passano su quella connessione, quindi senza la CA fallirebbero la verifica x509 rispetto alla CA interna al cluster, trascinando con sé il branding e ogni CR di prodotto.

Richiede il gateway 1.0.0-rc.9 o successivo

Il TLS all'interno del pod funziona solo a partire dal gateway 1.0.0-rc.9. Le immagini precedenti andavano in panic all'avvio ogni volta che spec.tls era abilitato (rustls trovava due crypto provider collegati e nessuno installato). Il waeg-operator si rifiuta di abilitarlo su un'immagine più vecchia e riporta TLSUnsupportedGateway invece di consegnarti un crash loop, quindi fissare un instance.image più vecchio lascia il gateway in chiaro invece di romperlo. waeg-operator 1.3.0 usa rc.9 come predefinito, quindi il percorso predefinito non presenta problemi.

Guardrail ​

spec.guardrailRefs funziona su un gateway Wäg, ma la struttura è diversa. LiteLLM prevede un oggetto per ciascuna modalità di esecuzione; Wäg ne prevede tre:

WaegGuardrailItem (one per Guardrail)  →  WaegGuardrailChain (orders them)
                                       →  WaegGuardrailBinding (applies the chain)

L'operatore li emette tutti e tre con scope: platform, quindi non è richiesta alcuna organization. Il binding usa mode: floor, cioè viene eseguito sempre — un binding a livello di organization o di team aggiunto in seguito nella console Wäg non può disattivare un guardrail collegato dalla piattaforma.

Tre impostazioni degli item sono determinanti, e l'operatore le sceglie per te:

ImpostazioneMotivo
roleI motori transform riscrivono il contenuto. Se configurato come item policy, Wäg tratta la riscrittura come una decisione di redazione e la sostituzione durante lo streaming silenziosamente non avviene. I motori del catalogo dichiarano il proprio ruolo
onErrorRicavato da unreachableFallback (predefinito fail_closed). Wäg usa per impostazione predefinita il fail-open, quindi con un motore che risponde deliberatamente 502 il prompt originale verrebbe altrimenti inoltrato al provider
modeWäg ha una fase during_call che LiteLLM non ha. Un motore di trasformazione ne ha bisogno, altrimenti le risposte in streaming non vengono riscritte. Il pseudonymizer incluso esegue tutte e tre le fasi su Wäg

I guardrail esterni richiedono spec.waeg.path. Wäg invia la POST a un URL indicato per intero, mentre LiteLLM aggiunge /beta/litellm_basic_guardrail_api — quindi l'operatore non può indovinare dove un endpoint gestito dall'utente espone il protocollo Wäg. In sua assenza il guardrail viene saltato e un Event lo segnala, invece di lasciare che l'operatore indovini un percorso facendo fallire ogni scansione mentre il gateway appare sano. I motori del catalogo forniscono il proprio percorso (il pseudonymizer espone /v1/waeg/check).

spec.waeg su un Guardrail contiene anche i campi facoltativi role, timeoutMs, forwardIdentity e forwardSessionId. Gli ultimi due contano per i motori che mantengono uno stato per sessione: le mappature dei nomi del pseudonymizer restano coerenti tra i turni solo quando Wäg inoltra un'identità, altrimenti ripiega sull'id della richiesta, che tiene insieme una singola richiesta ma non una conversazione.

Cosa non viene applicato ​

Alcuni campi di questo CRD non vengono ancora applicati a un gateway Wäg. Impostarne uno non rompe nulla — viene elencato in status.unsupportedFeatures, la condizione FeaturesSupported passa a False con motivo UnsupportedByBackend e viene generato un Event.

CampoMotivo
instance.saltKeyWäg non ha una salt key — usa waeg.dataEncryptionKeySecretRef
instance.storePromptsInLogsNessuna impostazione di runtime equivalente
instance.healthCheckWäg espone probe fisse /healthz e /readyz e nessun ciclo in background configurabile
instance.jwtAuth — solo le mappature dei claimL'autenticazione JWT in sé viene applicata (vedi Autenticazione JWT del data plane). Vengono rifiutati solo userRolesJWTField, userRoleJWTField, userAllowedRoles, enforceRBAC, userIDUpsert, teamIDsJWTField e adminJWTScope: Wäg autorizza tramite OpenFGA e le applicazioni registrate anziché ricavando i ruoli dal token
instance.rolePermissionsWäg non ha i role_permissions di LiteLLM — usa waeg.modelAccess per le ACL dei modelli con radice nell'organization
models[].rpm / tpm / timeout / maxTokensL'oggetto modello di Wäg non prevede limiti di richieste o di token, e il gateway non ha alcun timeout di richiesta per modello. Un limite per modello è un WaegBudget con scope: model (un pool a livello di organization per l'alias), che questo operatore non emette
organization.budgetDurationLe policy di budget di Wäg non hanno un campo per il periodo

Al di fuori della spec del Gateway, le risorse di identità sono pienamente supportate su Wäg: Identity, Organization e Team emettono WaegUser, WaegOrganization, WaegTeam e le policy WaegBudget a livello di organization e di team. Falle puntare a questo Gateway con type: gateway e seguiranno il suo spec.type — vedi Scegliere il backend.

Due campi di identità non vengono applicati su Wäg: teamRefs e budget di un'Identity. Wäg mantiene l'appartenenza sul team (elenca l'indirizzo nei members del Team), e un limite per utente è un WaegBudget con scope: user. Un'Identity Wäg riceve inoltre un Secret con una password della console generata e riporta Ready solo quando il WaegUser è Synced — vedi Account Wäg.

Rifiutato a monte ​

Invece di emettere una risorsa che resterebbe bloccata, l'operatore rifiuta questi casi con Ready=False, motivo InvalidTarget:

  • type: waeg senza spec.waeg o senza spec.waeg.clickhouse
  • waeg.worker.enabled con topology: AllInOne
  • più di una replica API senza waeg.redis
  • waeg.modelAccess senza spec.organization

Esempio ​

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          # never share a schema with a LiteLLM gateway
  instance:
    replicas: 2
    masterKey: { autoGenerate: true }
    licenseSecretRef: { name: waeg-enterprise-license, key: license }   # unlocks every EE module
    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          # the default; `single` drops ClickHouse entirely
    clickhouse: { mode: ref, ref: { name: forge-ch, namespace: forge-data } }
    redis:      { mode: ref, ref: { name: forge-redis, namespace: forge-data } }
    # openfga omitted -> the operator deploys a Postgres-backed OpenFGA
    # defaultBranding defaults to true -> the Navique theme pack is applied
    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]

Verifica cosa è stato saltato:

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

In uno Stack ​

Stack.spec.gateway.type: waeg lo seleziona per un intero Stack. Lo Stack allora richiede datastores.clickhouse.enabled (altrimenti l'admission lo rifiuta), collega automaticamente il proprio ClickHouse e il proprio Redis come secondo piano e assegna al database logico del gateway il nome waeg, così non finisce mai su uno schema LiteLLM. Stack.spec.gateway.waeg inoltra le opzioni di topologia/worker/OpenFGA/autoscaling, oltre a scim e jwt; la licenza Enterprise viene dichiarata una sola volta come Stack.spec.gateway.licenseSecretRef, e Stack.spec.gateway.jwtAuth attiva l'autenticazione JWT del data plane.

Status ​

status.url espone l'endpoint del gateway (pubblico quando l'ingress è abilitato, altrimenti interno al cluster), oltre alla readiness dell'istanza, al numero di modelli/team e alla readiness del database. status.unsupportedFeatures elenca ogni campo configurato che il tipo di gateway selezionato non può rispettare (sempre vuoto per type: litellm); la condizione FeaturesSupported lo rispecchia.

Note sulla licenza ​

Team, organization e budget fanno parte della funzionalità multi-tenancy; più di un Gateway richiede un limite gateways superiore al valore predefinito Community di 1. Vedi Edizioni e licenze.

Nucleo open source sotto AGPL-3.0. I componenti Enterprise sono proprietari e soggetti a licenza.