Aller au contenu principal

Durcissement des services de données

Version anglaise : en/data-services-hardening.md.

Les valeurs de connexion contenant un secret restent dans OpenBao (kv/eai/<env>/control-plane) et sont livrées par External Secrets ; values-prod.yaml en fixe le format attendu (controlPlane.secretFormats), vérifié par test_platform_security_manifests.py. Avant chaque bao kv put, l'opérateur contrôle ce format.

PostgreSQL (CloudNativePG)​

deploy/data/postgres/cluster.yaml :

  • enableSuperuserAccess: false : aucun secret superutilisateur n'est généré ; le propriétaire applicatif eai est un rôle simple, sans SUPERUSER ni REPLICATION ;
  • password_encryption: scram-sha-256, ssl_min_protocol_version: TLSv1.3, journalisation des connexions ;
  • pg_hba évalué avant les règles par défaut de l'opérateur : refus de toute connexion sans TLS, refus de postgres par le réseau, hostssl en scram-sha-256 pour eai sur ses bases depuis le réseau des pods (10.42.0.0/16, à adapter), puis refus de tout le reste. Les règles de l'opérateur pour streaming_replica (certificat) et le socket local passent en premier ;
  • côté client : EAI_DATABASE_URL se termine par ?sslmode=verify-full&sslrootcert=/run/secrets/postgres-ca/ca.crt, l'AC étant le secret eai-postgres-ca émis par CloudNativePG.

Redis​

deploy/data/redis/values.yaml : port en clair fermé (port 0), tls-port 6379, réplication TLS, certificats clients exigés, utilisateur default désactivé, un utilisateur ACL par service (eai-control-plane limité aux clés eai:rl:* et eai:cache:*, apisix limité aux compteurs limit-count, litellm limité aux clés litellm:*, livekit limité aux clés de LiveKit 1.9.0, qui n'a pas de préfixe, Opik, dont les clés n'ont pas de préfixe commun, n'utilise pas ce Redis : il a sa propre instance redis-opik, deploy/data/redis-opik/values.yaml, utilisateur ACL opik, TLS), commandes dangereuses renommées. EAI_REDIS_URL en production : rediss://eai-control-plane:<mot de passe>@redis-master.eai-data.svc.cluster.local:6379/2.

NATS​

deploy/data/nats/values.yaml : TLS sur les clients et les routes du cluster, un utilisateur par service (control-plane, worker, multimodal) avec des permissions de sujets minimales, mots de passe en bcrypt depuis le secret nats-users. EAI_NATS_URL en production : tls://control-plane:<mot de passe>@nats.eai-data.svc.cluster.local:4222.

OpenBao​

Les politiques de deploy/openbao/policies/ donnent à chaque composant ses seuls chemins : le control plane lit kv/data/eai/+/control-plane, gère kv/data/tenants/* et utilise les clés transit tenant-* et eai-audit sans export ni suppression ; LiteLLM lit ses clés de fournisseurs ; le portail et les workers lisent leur seul chemin. Aucune politique applicative n'accorde sys/*, transit/export/* ni auth/* ; seule security-officer.hcl (humains, révocation d'urgence) ouvre sys/leases/revoke-prefix/*. Tout le reste est refusé par défaut. Réseau : deploy/cilium/data-services.yaml n'ouvre 8200 qu'aux namespaces enterprise-ai, external-secrets et spire.

Qdrant​

deploy/data/qdrant/values.yaml : clé API lecture-écriture et clé lecture seule depuis le secret qdrant-api-key (EAI_QDRANT_API_KEY côté control plane), TLS sur REST, gRPC et le trafic pair à pair, télémétrie désactivée. EAI_QDRANT_URL passe en https:// en production.

ClickHouse​

deploy/data/clickhouse/users.yaml et config.yaml : utilisateur default supprimé, opik en écriture sur sa base opik, eai-writer limité à INSERT sur eai_finops.usage_events et eai_telemetry.spans (mot de passe CLICKHOUSE_EAI_WRITER_PASSWORD_SHA256, aucun droit SELECT, ALTER, CREATE ni DROP), eai-reader en lecture seule sur eai_finops.*, eai_telemetry.* et opik.* (readonly: 1, quotas et durée maximale) pour les tableaux de bord, access_management: 0, réseaux limités aux pods, ports en clair fermés (HTTPS 8443 et natif TLS 9440). L'exportateur du control plane (job analytics_export, voir analytics-export.md) utilise EAI_CLICKHOUSE_USER=eai-writer et EAI_CLICKHOUSE_URL=https://...:8443 ; les tableaux de bord utilisent eai-reader.

Politiques réseau​

deploy/cilium/data-services.yaml : refus total dans eai-data, openbao et eai-security, puis une politique par service (PostgreSQL, Redis, NATS, Qdrant, OpenBao, services de sécurité) qui n'accepte que les composants appelants, sélectionnés par app.kubernetes.io/component.