Skip to content

Identity, Organization et Team ​

Portée : namespaced · Sous licence (fonctionnalité identity-management + quotas organizations / teams)

Ces resources gèrent les identités à travers les composants de la plateforme — la passerelle (LiteLLM ou Wäg), Langfuse et LibreChat — sous forme d'objets Kubernetes, de sorte que les accès et la tenance soient déclaratifs et auditables plutôt que configurés à la main dans chaque outil.

ResourceGère
UserUne personne / un siège — la clé naturelle (email) qui relie entre eux les comptes de cette personne
IdentityUn compte par backend pour une personne, sur la passerelle, Observability (Langfuse) ou LibreChat
OrganizationUne frontière de tenant / facturation de premier niveau
TeamUn groupe au sein d'une organisation, avec des budgets et un accès aux modèles

Personnes vs comptes

Un User est une personne (un siège sous licence). Un Identity est l'un des comptes backend de cette personne. Le quota users de la licence compte les sièges User ; les comptes Identity sont illimités, et chacun doit pointer vers un User via userRef. Une personne disposant d'une clé de passerelle, d'une appartenance Langfuse et d'une connexion LibreChat correspond à un siège, trois objets Identity.

Identity ​

Un Identity provisionne un compte unique pour une personne sur un backend. Son spec.type sélectionne le composant dans lequel vit le compte :

typeÉmet
gatewayRecommandé. Suit le spec.type du Gateway référencé — voir Choix du backend
litellmResources d'utilisateur LiteLLM (LiteLLMUser), vérifiées contre le Gateway référencé
waegUtilisateur de console Wäg (WaegUser), vérifié contre le Gateway référencé — voir Comptes Wäg
observabilityAppartenance à l'organisation Langfuse de l'Observability (nécessite une licence Langfuse Enterprise)
librechatConfiguration d'utilisateur / rôle LibreChat

Spec ​

ChampTypeDescription
typeenum (requis)gateway / litellm / waeg / observability / librechat
userRef{ name } (requis)Le User propriétaire dans le même namespace
emailstring (optionnel)Email du compte ; par défaut le spec.email du User propriétaire
displayNamestringNom lisible par un humain
userIdstringIdentifiant utilisateur externe stable pour le backend
rolestringRôle backend. Sur Wäg, seuls admin ou platform_admin exactement accordent le privilège d'administration de plateforme à l'échelle du cluster — rien d'autre n'est déduit
budgetobjectBudget par compte (lorsque le backend le supporte ; non appliqué sur Wäg)
teamRefslistÉquipes auxquelles ce compte appartient (LiteLLM ; non appliqué sur Wäg)
gatewayRefObjectRefLe Gateway sur lequel vit ce compte. Requis pour type: gateway / litellm / waeg, et il doit se trouver dans le même namespace — voir Règles d'admission
observabilityRefObjectRefUn Observability (pour type: observability)
chatUIRefObjectRefUn ChatUI (pour type: librechat)
passwordSecretRefSecretKeyRefSecret de mot de passe (pour type: librechat)

Choix du backend : type: gateway ​

Identity, Organization et Team acceptent tous type: gateway, et c'est la valeur à utiliser pour les nouvelles resources. Une resource d'identité adossée à une passerelle cible un Gateway — et ce Gateway sait déjà quelle implémentation il exécute. Avec type: gateway, l'opérateur lit le backend dans le spec.type du Gateway référencé, la seule source qui ne peut pas diverger.

yaml
spec:
  type: gateway               # résolu depuis le Gateway ci-dessous
  gatewayRef: { name: forge-gateway }

Les valeurs nommées d'après le produit, litellm et waeg, fonctionnent toujours et ne sont pas vouées à disparaître. Ce qui change, c'est qu'elles sont désormais vérifiées contre le Gateway au lieu d'être crues sur parole. Déclarer un type qui contredit le Gateway est refusé avec Ready=False :

type=litellm does not match Gateway "forge-gateway", which is type=waeg —
set type: gateway to follow the Gateway, or point gatewayRef at a litellm gateway

Le message nomme le type déclaré, le Gateway, le type réel du Gateway, et les deux issues : suivre le Gateway avec type: gateway, ou faire pointer gatewayRef vers une passerelle du type déclaré.

Pourquoi cette vérification existe

Rien ne comparait auparavant les deux valeurs. Une Organization / une Team / un Identity déclarant type: litellm face à une passerelle Wäg était accepté, et l'opérateur émettait une LiteLLMOrganization / LiteLLMTeam / LiteLLMUser dont l'instanceRef désignait une instance Wäg — un objet qui ne se lie à rien et ne se matérialise dans aucune passerelle.

Sur un cluster où les deux opérateurs sont installés, cet apply réussit : la CRD existe, l'objet est stocké, et rien ne révèle jamais l'erreur. Le compte n'apparaît tout simplement jamais dans la passerelle. L'incohérence est désormais un refus au lieu d'un objet silencieusement orphelin.

Règles d'admission ​

Deux règles sont appliquées par le serveur d'API sur Identity, Team etOrganization, de sorte qu'une mauvaise référence est refusée dès le kubectl apply plutôt que des heures plus tard dans une condition de statut.

1. Un type adossé à une passerelle requiert gatewayRef.

type gateway/litellm/waeg requires gatewayRef

gatewayRef était jusqu'ici optionnel sur chacune de ces resources. Une Team de type: waeg sans gatewayRef était admise et n'échouait qu'à la réconciliation avec « a gateway-backed identity resource requires gatewayRef » — la même information, des heures plus tard.

2. gatewayRef.namespace doit être vide.

gatewayRef.namespace must be empty: the Gateway must live in the same namespace as this resource

Le litellm-operator comme le waeg-operator résolvent l'instanceRef amont au sein du namespace local, une référence gatewayRef inter-namespaces ne pouvait donc jamais se lier à quoi que ce soit. Placez le Gateway dans le même namespace que les resources d'identité qui le ciblent, et ne renseignez que { name: … }.

Comptes LibreChat ​

LibreChat n'expose aucune API pour créer des comptes. Un Identity de type: librechat est donc provisionné en exécutant le script create-user fourni avec LibreChat sous la forme d'un Job Kubernetes éphémère. Le Job est cloné depuis le conteneur LibreChat en cours d'exécution (même image et même environnement), il atteint donc automatiquement la même base MongoDB.

  • Le ChatUI référencé (spec.chatUIRef) doit être Ready et se trouver dans le même namespace que l'Identity.
  • Le provisionnement est idempotent et en création seule (create-only) : un compte existant est considéré comme un succès, et les modifications ultérieures de l'Identity ne changent pas un compte déjà créé.
  • Mot de passe : définissez spec.passwordSecretRef (clé password par défaut) pour utiliser un mot de passe connu. Si vous l'omettez, l'opérateur en génère un et le stocke dans un Secret dédié nommé <identity>-librechat-password (clé password). Récupérez-le avec kubectl get secret <identity>-librechat-password -o jsonpath='{.data.password}' | base64 -d puis effectuez une rotation après la première connexion. Le mot de passe n'est jamais transmis en ligne de commande.

Comptes Wäg ​

Identity, Team et Organization sont pleinement supportés sur une passerelle Wäg. Ils émettent WaegUser, WaegTeam, WaegOrganization ainsi que les politiques WaegBudget au niveau de l'organisation et de l'équipe (toutes dans gateway.waeg.ai/v1alpha1).

Mot de passe de console. Wäg exige un mot de passe pour créer un utilisateur de console. Pour un Identity adossé à Wäg, l'opérateur en génère un dans un Secret dédié nommé <nom-de-l-identity>-waeg-password, clé password, et y fait pointer le WaegUser via spec.passwordSecretRef. Récupérez-le pour la première connexion de la personne avec :

bash
kubectl get secret <identity>-waeg-password \
  -o jsonpath='{.data.password}' | base64 -d

Le Secret est généré une seule fois et jamais renouvelé automatiquement — en effectuer la rotation fait tourner le mot de passe de la console. Rien d'autre n'est à renseigner ; il n'existe aucun champ permettant de fournir votre propre mot de passe pour un compte Wäg.

Ready signifie que le compte existe. Une resource d'identité Wäg ne signale Ready qu'une fois que le WaegUser émis signale lui-même Synced=True. Appliquer la CR amont était auparavant considéré comme un succès, ce qui masquait précisément la défaillance ci-dessus : sans Secret de mot de passe, le WaegUser restait indéfiniment à Synced=False — « passwordSecretRef is required to create a new console user », tandis que l'Identity s'affichait au vert et que le compte de console n'existait pas. Une Identity au vert signifie désormais que la passerelle a accepté le compte.

Membres d'équipe. Wäg désigne un membre d'équipe par un WaegUser, jamais par son email. Pour un membre qui possède aussi une Identity sur le même Gateway, l'équipe pointe vers le WaegUser de cette Identity — un seul utilisateur de console par personne. Seule une adresse sans Identity reçoit un WaegUser d'appartenance distinct (nommé <team>-<email-slug>), supprimé dès que l'adresse quitte l'équipe. Cette suppression n'efface jamais le compte Wäg de la personne : Wäg ne supprime un utilisateur de l'annuaire que si la CR supprimée l'a créé, ce qu'un WaegUser d'appartenance (sans mot de passe) ne fait jamais.

Non appliqué sur Wäg — chaque cas est signalé par un Event (UnsupportedByBackend), jamais abandonné en silence :

ChampPourquoi
Identity.spec.teamRefsWäg garde l'appartenance sur l'équipe, pas sur l'utilisateur. Indiquez plutôt l'adresse de la personne dans le spec.members de la Team
Identity.spec.budgetUne limite Wäg par utilisateur est un WaegBudget de scope: user, que cet opérateur n'émet pas
Organization.spec.membersWaegOrganization ne modélise aucun membre — l'appartenance à une organisation est un endpoint de l'Admin API sans CR. Les members d'une Team, eux, sont appliqués
spec.budget.budgetDuration (Organization / Team)Les politiques de budget Wäg n'ont pas de champ de période
spec.budget.models (Organization / Team)Les listes de modèles autorisés relèvent de l'ACL WaegModelAccess distincte, pas d'un champ de budget

Organization et Team ​

ResourceGère
OrganizationUne frontière de tenant / facturation de premier niveau
TeamUn groupe au sein d'une organisation, avec des budgets et un accès aux modèles

Chacune porte un type qui sélectionne l'identité de quel composant elle pilote :

typeÉmet
gatewayRecommandé. Suit le spec.type du Gateway référencé
litellmLiteLLMOrganization / LiteLLMTeam
waegWaegOrganization / WaegTeam, plus la politique WaegBudget correspondante
observabilityResources d'org / projet / appartenance Langfuse (les équipes sont à l'état d'ébauche)

Les deux acceptent un gatewayRef — requis pour gateway / litellm / waeg, et uniquement dans le même namespace (Règles d'admission). Organization expose également un observabilityRef pour pointer vers la charge de travail Observability lorsque type: observability.

Une Team référence son organisation parente via spec.organizationRef ({ name }, même namespace). Sur LiteLLM le parent est optionnel ; sur Wäg il est requis — les équipes Wäg sont toujours rattachées à une organisation. Une Team de type: waeg qui en manque est rejetée à l'admission (spec.organizationRef: Required value) ; une Team de type: gateway sur un gateway Wäg est refusée lors de la réconciliation, car l'admission ne voit pas le type du Gateway. Le type de l'organisation parente est résolu de la même façon : une Organization de type: gateway sur un gateway Wäg est un parent valide pour une équipe Wäg ; une Organization de l'autre produit est signalée comme incompatible.

Exemple ​

Un Gateway, une organisation, une équipe, une personne — et aucune des resources d'identité ne nomme le produit de passerelle. Basculer le Gateway entre litellm et waeg laisse les quatre inchangées.

yaml
apiVersion: core.navique.com/v1alpha1
kind: Organization
metadata:
  name: acme
  namespace: forge
spec:
  type: gateway                        # résolu depuis le Gateway
  gatewayRef: { name: forge-gateway }  # même namespace — pas de champ `namespace:`
  displayName: ACME Corp
  budget:
    maxBudget: 500
---
apiVersion: core.navique.com/v1alpha1
kind: Team
metadata:
  name: platform
  namespace: forge
spec:
  type: gateway
  gatewayRef: { name: forge-gateway }
  organizationRef: { name: acme }      # requis sur Wäg, optionnel sur LiteLLM
  displayName: Platform Team
  members:
    - email: alice@example.com         # sur Wäg, l'appartenance se déclare ici
      role: admin
---
apiVersion: core.navique.com/v1alpha1
kind: User
metadata:
  name: alice
  namespace: forge
spec:
  email: alice@example.com
  displayName: Alice Example
---
apiVersion: core.navique.com/v1alpha1
kind: Identity
metadata:
  name: alice-gateway
  namespace: forge
spec:
  type: gateway
  userRef: { name: alice }             # le siège sous licence, même namespace
  gatewayRef: { name: forge-gateway }
  role: admin
  # email omis → hérite de alice@example.com depuis le User

Sur une passerelle de type: waeg, cela produit également le mot de passe de console généré dans alice-gateway-waeg-password — voir Comptes Wäg.

Relation avec le Gateway ​

Un Gateway peut déclarer une organization et des teams[] inline. Les resources d'identité sont le mécanisme plus large, transversal aux composants : elles vous permettent de gérer les organisations, les équipes, les personnes (User) et leurs comptes backend (Identity) une seule fois et de les voir reflétés de manière cohérente à travers la passerelle, Langfuse et LibreChat, y compris à travers plusieurs gateways.

Licences ​

La gestion des identités fait partie de la valeur multi-tenancy et requiert la fonctionnalité identity-management ainsi que les quotas d'instances organizations / teams pertinents dans la License. Le quota users compte les sièges User — et non les comptes Identity, qui sont illimités. Dans l'édition Community, utilisez les organization / teams[] inline sur un seul Gateway.

Voir Éditions et licences.

Cœur open source sous AGPL-3.0. Les composants Enterprise sont propriétaires et soumis à licence.