Gestion des secrets
La règle : aucun secret fourni par un humain n'est jamais en clair dans une custom resource, une valeur de chart ou un template. Les identifiants atteignent la plateforme par l'un des trois chemins suivants, sélectionné et configuré par la ressource SecretsManagement.
Les trois sources de secrets
- External Secrets (ESO) — récupère les secrets depuis un magasin de secrets externe (Azure Key Vault par défaut, mais n'importe quel fournisseur ESO) vers des Kubernetes Secrets dans le namespace.
- Sealed Secrets — manifestes chiffrés au repos, déchiffrés dans le cluster.
- Générés par l'opérateur — identifiants que l'opérateur lui-même crée (clés virtuelles LiteLLM, clés de callback Langfuse, mots de passe des datastores). Stockés comme Kubernetes Secrets possédés (owned) avec des références de propriétaire pour le ramasse-miettes ; vous pouvez les convertir manuellement en ESO/Sealed.
SecretsManagement est requis et sélectionne le backend (1) ou (2). Les workloads se lient à un SecretsManagement du même namespace via secretsRef et référencent les noms des Secrets matérialisés.
Fournisseurs ESO
L'opérateur provisionne un SecretStore namespacé (et non un ClusterSecretStore), gardant les identifiants de chaque namespace isolés.
Azure Key Vault (le défaut en production)
- Workload Identity (
authType: WorkloadIdentity) — production sur AKS. Le ServiceAccount de chaque workload consommateur a besoin du labelazure.workload.identity/use: "true"et d'un federated identity credential dans Azure. L'opérateur applique les labels du pod/SA via les valeurs de chart qu'il rend. - Service Principal (
authType: ServicePrincipal) — fonctionne partout, y compris sur des clusters non-AKS et Kind (qui n'a pas de fédération OIDC pour Workload Identity). FournisseztenantID+authSecretRef.{clientID, clientSecret}.
apiVersion: external-secrets.io/v1
kind: SecretStore
metadata: { name: azure-keyvault, namespace: forge-gateway }
spec:
provider:
azurekv:
authType: WorkloadIdentity
vaultUrl: https://kvforgepltprod.vault.azure.net/
serviceAccountRef: { name: forge-sa }La federated credential est une étape manuelle obligatoire
L'opérateur met en place le côté Kubernetes (le ServiceAccount étiqueté, le SecretStore, les ExternalSecrets). Il n'appelle aucune API Azure et ne peut donc pas créer la federated identity credential qui permet à ce ServiceAccount d'échanger son jeton contre la managed identity de la plateforme. Vous devez en créer une par (namespace, serviceAccount) — l'émetteur OIDC d'AKS exige un subject correspondant exactement et ne prend pas en charge les jokers :
az identity federated-credential create \
--name "eso-<namespace>-<serviceAccount>" \
--identity-name "<managed-identity>" \
--resource-group "<resource-group>" \
--issuer "$(az aks show -g <resource-group> -n <cluster> --query oidcIssuerProfile.issuerUrl -o tsv)" \
--subject "system:serviceaccount:<namespace>:<serviceAccount>" \
--audiences "api://AzureADTokenExchange"Tant qu'elle n'existe pas, l'échange de jeton d'ESO échoue avec l'erreur Entra AADSTS70021: No matching federated identity record found …. L'opérateur surveille le statut du SecretStore d'ESO et le reflète dans la condition FederatedCredentialReady de la SecretsManagement :
Waiting— ESO n'a pas encore validé le store.False/MissingFederatedCredential— l'erreurAADSTS70021a été observée ; le message indique le subject exact pour lequel créer une credential.True— ESO s'est authentifié ; la credential est en place.
Ready continue d'indiquer que le backend a été câblé ; FederatedCredentialReady est le signal spécifique de la confiance côté Azure. (Avec authType: ServicePrincipal, aucune federated credential n'est nécessaire et cette condition n'est pas définie.)
HashiCorp Vault
Permet à l'ensemble du chemin des secrets de s'exécuter dans le cluster (sans Key Vault cloud, Service Principal ni federated identity). Pour KV-v2, chaque valeur keys est le chemin du secret et le nom de la clé Kubernetes est la propriété qui s'y trouve.
N'importe quel fournisseur (passthrough brut)
provider: raw injecte le bloc ESO spec.provider tel quel, de sorte que chaque fournisseur ESO est pris en charge — AWS, GCP, IBM, Akeyless, 1Password, Kubernetes, et tout fournisseur que ESO ajoutera à l'avenir — sans modification de l'opérateur. La forme externalSecrets[].data expose la totalité du remoteRef ESO (remoteKey / property / version).
Consultez la référence SecretsManagement pour les formes de champs exactes et des exemples de chaque fournisseur.
Matrice des clés Azure Key Vault
Lorsque vous utilisez Azure Key Vault, voici les noms de secrets que l'opérateur attend (repris des valeurs de chart antérieures de la plateforme). SecretsManagement.eso.externalSecrets[].keys mappe les clés des Kubernetes Secrets → les noms de secrets Key Vault.
Gateway (forge-gateway)
| Kubernetes Secret / clé | Secret Key Vault | Utilisé pour |
|---|---|---|
model-credentials / OPENAI_API_KEY | gateway-foundry-api-key | Auth modèle amont |
model-credentials / ANTHROPIC_API_KEY | gateway-foundry-api-key | Auth modèle amont |
litellm-db-credentials / DATABASE_URL | (assemblé à partir de PostgresCluster) | BDD LiteLLM |
entra-sso-credentials / client-id,client-secret | gateway-entra-sso-client-id / -secret | SSO de l'UI (quand enableEntraSSO) |
litellm-license / license-key | gateway-litellm-license-key | LiteLLM enterprise |
ChatUI (forge-ui)
| Kubernetes Secret / clé | Secret Key Vault |
|---|---|
librechat-credentials-env / CREDS_KEY | chatui-creds-key |
librechat-credentials-env / CREDS_IV | chatui-creds-iv |
librechat-credentials-env / JWT_SECRET | chatui-jwt-secret |
librechat-credentials-env / JWT_REFRESH_SECRET | chatui-jwt-refresh-secret |
librechat-credentials-env / LITELLM_API_KEY | chatui-litellm-api-key (ou une clé virtuelle créée automatiquement si la licence le permet) |
forge-ui-basic-auth / htpasswd | chatui-basic-auth-htpasswd |
Les identifiants MongoDB et Meilisearch ne sont pas issus de Key Vault pour ChatUI. Ils sont possédés par les ressources datastore : la master key Meilisearch par la MeilisearchInstance, et le mot de passe SCRAM Mongo + le MONGO_URI par base de données par le MongoCluster.
Langfuse (forge-langfuse)
nextauth-secret + salt sont générés et tournés automatiquement par le langfuse-operator dans un Secret <instance>-generated-secrets — ne les sourcez pas depuis Key Vault sauf en cas de surcharge. Les identifiants de datastore proviennent des Secrets matérialisés des ressources datastore référencées (plus Key Vault pour les datastores externes).
Secrets générés par l'opérateur
- Les clés virtuelles LiteLLM (auto-wiring de ChatUI) et les clés master/salt (
autoGenerate: true). - Les mots de passe de rôle CloudNativePG (exposés sous forme d'un Secret d'identifiants par base de données).
- Le mot de passe SCRAM
MongoClusteret les SecretsMONGO_URIpar base de données. - Le Secret de master key
MeilisearchInstance.
Tous les Secrets possédés par l'opérateur reçoivent des références de propriétaire pour le ramasse-miettes et un label managed-by=navique-ai-core-operator.
Rotation
Avec la fonctionnalité credential-rotation et un bloc rotation par ressource (intervalle par défaut de 90 jours), l'opérateur fait tourner les identifiants qu'il possède — clés virtuelles LiteLLM, et mots de passe générés ClickHouse / Redis / Mongo / Meilisearch — en réappliquant une annotation core.navique.com/rotated-at.
Hors périmètre (tournés par leurs propres systèmes) : les secrets Key Vault (tournez-les dans KV ; ESO resynchronise) et les mots de passe de rôle gérés par CNPG (tournez-les via CNPG). L'opérateur ne fait jamais tourner les identifiants qu'il ne possède pas. Sans la fonctionnalité, le bloc rotation est ignoré.
Migration hors du clair
Faites tourner les secrets précédemment commités
Les anciens Helm charts de la plateforme commitaient des secrets actifs dans git (clés d'API de modèles, secret client Entra SSO, licence LiteLLM, URL de bases de données, secrets Langfuse). Ceux-ci sont compromis par définition et doivent être tournés dans le cadre de la migration — ne copiez aucun d'entre eux dans l'opérateur. Faites tourner chacun d'eux dans Key Vault, sourcez-les via ESO, et nettoyez l'historique git si possible.
À ne pas faire
- Pas de valeurs de secret dans les samples — utilisez des placeholders et une note pour renseigner le vault.
- Pas de journalisation de secrets. Masquez les chaînes de connexion dans les Events et les conditions.
- Pas de secrets embarqués dans l'image de l'opérateur (la clé publique de licence est acceptable ; jamais la clé privée).