Infra de base — DNS, secrets et config NestJS
Phases 9 à 11 du déploiement infrastructure : DNS Cloudflare + certificats, Doppler / External Secrets, configuration NestJS des services. Pour la vue d'ensemble, voir Infra de base — overview.
PHASE 9 — DNS CLOUDFLARE & CERTIFICATS
Objectif
Rendre les services accessibles via les domaines paywithnex.com avec TLS.
Instructions pour l'agent
9.1 Configuration DNS
Dans Cloudflare (via Terraform provider Cloudflare ou manuellement) :
| Type | Nom | Valeur | Proxy Cloudflare | Note |
|---|---|---|---|---|
| CNAME | api.staging | Hostname du NLB (phase 8.3) | Oui (orange) | API staging |
| CNAME | admin | Site Firebase Hosting | Non (gris) | CMMS Dashboard |
| CNAME | bo | Site Firebase Hosting | Non (gris) | Backoffice |
| TXT | @ | SPF record pour Resend | — | Délivrabilité email |
| TXT | resend._domainkey | DKIM record Resend | — | Signature email |
| TXT | _dmarc | DMARC policy | — | Anti-spoofing |
| CNAME | *.review | Hostname du NLB (phase 8.3) | Oui (orange) | Review envs éphémères |
Les enregistrements pour la production (prod.paywithnex.com) seront ajoutés en semaine 2.
Note review : Le wildcard *.review.paywithnex.com pointe vers le même NLB que staging. L'Ingress Controller route vers le bon namespace nex-review-{branch} grâce au host header.
9.2 Configuration Cloudflare
- SSL/TLS mode : Full (strict) — Cloudflare ↔ origin avec certificat valide (cert-manager)
- Always Use HTTPS : activé
- Minimum TLS Version : 1.2
- HSTS : activé, max-age 6 mois
- Brotli : activé
- HTTP/2 : activé
9.3 Firebase Hosting
L'agent doit configurer le fichier infrastructure/firebase/firebase.json pour le hosting des 2 dashboards Nuxt.js :
- Target
admin→ CMMS Dashboard (admin.paywithnex.com) - Target
backoffice→ Backoffice (bo.paywithnex.com)
Connecter les custom domains dans la console Firebase Hosting et ajouter les enregistrements DNS de vérification dans Cloudflare.
Recommandation : le proxy Cloudflare (orange) doit être désactivé pour les domaines Firebase Hosting. Firebase gère son propre SSL et CDN. Mettre Cloudflare en proxy devant Firebase crée des conflits de certificats.
Validation
# DNS résout
dig dev.paywithnex.com +short
# Attendu : IP Cloudflare (le proxy est actif)
dig admin.paywithnex.com +short
# Attendu : IP Firebase Hosting
# TLS fonctionne
curl -I https://dev.paywithnex.com
# Attendu : HTTP/2 200 ou 404 (pas encore de routes) avec headers Cloudflare
# Firebase Hosting répond
curl -I https://admin.paywithnex.com
# Attendu : HTTP/2 200 avec headers FirebasePHASE 10 — DOPPLER : INJECTION DES SECRETS
Objectif
Remplir Doppler avec toutes les valeurs réelles issues des outputs Terraform (endpoints RDS, Redis, etc.) et des services externes (Firebase, Sentry, Resend).
Instructions pour l'agent
Après les phases 4 à 9, tous les endpoints sont connus. L'agent doit générer un script qui récupère les outputs Terraform et met à jour Doppler.
Secrets à configurer dans le projet Doppler paywithnex, config stg :
# --- Base de données ---
POSTGRES_HOST=<output terraform: rds_endpoint (sans le port)>
POSTGRES_PORT=5432
POSTGRES_DB=nex_staging
POSTGRES_USER=nex_admin
POSTGRES_PASSWORD=<output terraform: rds_password>
POSTGRES_SSL=true
# --- Schemas par service ---
AUTH_SCHEMA=auth
ORCHESTRATOR_SCHEMA=orchestrator
NOTIFICATIONS_SCHEMA=notification
LEDGER_WALLETS_SCHEMA=ledger_wallets
# (chaque service a sa variable <SERVICE>_SCHEMA)
# --- Redis ---
REDIS_HOST=<output terraform: redis_endpoint>
REDIS_PORT=6379
REDIS_PASSWORD=<output terraform: redis_auth_token>
REDIS_TLS=true
# --- JWT ---
JWT_SECRET=<généré, 64 chars aléatoires>
JWT_EXPIRATION=3600
# --- Firebase ---
FIREBASE_PROJECT_ID=nex-app
FIREBASE_SERVER_KEY=<depuis Firebase console>
FIREBASE_STORAGE_BUCKET=nex-app.appspot.com
# --- Sentry ---
SENTRY_DSN=<depuis Sentry dashboard, un DSN par service ou un global>
# --- Resend ---
RESEND_API_KEY=<depuis Resend dashboard>
# --- App ---
NODE_ENV=staging
LOG_LEVEL=debug
API_BASE_URL=https://dev.paywithnex.comIMPORTANT — Variables de connexion :
Les services NestJS utilisent les noms
POSTGRES_*(pasDATABASE_*) etREDIS_PASSWORD(pasREDIS_AUTH_TOKEN). Deux variables cruciales à ne pas oublier :
POSTGRES_SSL=true— RDS exige SSL. Sans ça, erreurno pg_hba.conf entry... no encryption.REDIS_TLS=true— ElastiCache atransit_encryption_enabled. Sans ça, erreurETIMEDOUTcar ioredis essaie une connexion non-TLS.
URLs de communication inter-services (utilisées par l'orchestrator) :
RISK_ENGINE_SERVICE_URL=http://risk-engine:3009
LEDGER_WALLET_SERVICE_URL=http://ledger-wallets:3002
AUTH_SERVICE_URL=http://auth:3001
CUSTOMER_SERVICE_URL=http://customer-profiles-kyc:3003
CONFIGURATION_SERVICE_URL=http://configuration:3006
NOTIFICATIONS_SERVICE_URL=http://notifications:3005
SERVICE_CATALOG_URL=http://service-catalog:3010Note : Les services communiquent via le DNS interne Kubernetes (
<service-name>.<namespace>.svc.cluster.local). Les noms courts (http://auth:3001) fonctionnent car tous les services sont dans le même namespacenex-staging.
Recommandations :
- Le script doit être idempotent : relancer le script ne crée pas de doublons.
- Les mots de passe générés (POSTGRES_PASSWORD, JWT_SECRET, REDIS_PASSWORD) ne doivent être générés qu'une fois. Si ils existent déjà dans Doppler, ne pas les écraser.
- Après la mise à jour de Doppler, forcer un refresh de l'ExternalSecret K8s pour que les pods récupèrent les nouvelles valeurs.
Validation
# Vérifier le nombre de secrets
doppler secrets --project paywithnex --config stg --only-names | wc -l
# Attendu : >= 25
# Vérifier que les endpoints sont corrects
doppler secrets get POSTGRES_HOST --project paywithnex --config stg --plain
# Attendu : nex-staging-postgres.xxxxx.eu-west-3.rds.amazonaws.com
# Vérifier les variables critiques
doppler secrets get POSTGRES_SSL --project paywithnex --config stg --plain
# Attendu : true
doppler secrets get REDIS_TLS --project paywithnex --config stg --plain
# Attendu : true
# Vérifier la synchro K8s
kubectl get secret nex-secrets -n nex-staging -o jsonpath='{.data.POSTGRES_HOST}' | base64 -d
# Attendu : même valeur que DopplerPHASE 11 — CONFIGURATION NESTJS DES SERVICES
Objectif
S'assurer que chaque service NestJS est correctement configuré pour fonctionner sur EKS avec les managed services AWS (RDS + SSL, ElastiCache + TLS, health checks K8s).
Pré-requis par service
Chaque service NestJS doit avoir les 3 éléments suivants :
11.1 Health endpoint
Chaque service doit exposer un endpoint GET /health exclu du prefix global pour que les probes K8s fonctionnent.
Dans main.ts :
app.setGlobalPrefix('v1', { exclude: ['health'] });Dans app.controller.ts :
@Get('health')
health() {
return { status: 'ok' };
}Sans l'exclusion
{ exclude: ['health'] }, le endpoint devient/v1/healthau lieu de/health, et les readiness/liveness probes K8s renvoient 404.
11.2 SSL PostgreSQL
Chaque service utilisant TypeORM doit configurer SSL dans tous les endroits où une connexion est créée :
Dans app.module.ts (TypeORM.forRoot) :
ssl: process.env.POSTGRES_SSL === 'true' ? { rejectUnauthorized: false } : false,Dans data-source.ts (si le service en a un — utilisé par les migrations) :
ssl: process.env.POSTGRES_SSL === 'true' ? { rejectUnauthorized: false } : false,Piège : certains services (auth, orchestrator, notifications...) ont deux connexions TypeORM — une dans
app.module.tset une dansdata-source.ts. Si on oublie l'une des deux, le service crash avecno pg_hba.conf entry... no encryption.
11.3 TLS Redis
Les services utilisant Redis (auth, notifications via BullMQ) doivent activer TLS :
ioredis (auth) :
...(process.env.REDIS_TLS === 'true' && { tls: {} }),BullMQ (notifications) :
connection: {
host: process.env.REDIS_HOST,
port: parseInt(process.env.REDIS_PORT || '6379'),
password: process.env.REDIS_PASSWORD,
...(process.env.REDIS_TLS === 'true' && { tls: {} }),
},Récapitulatif par service
| Service | Port | TypeORM SSL | data-source.ts | Redis TLS | Health endpoint |
|---|---|---|---|---|---|
| auth | 3001 | app.module.ts | oui | oui (ioredis) | oui |
| ledger-wallets | 3002 | app.module.ts | oui | non | oui |
| customer-profiles-kyc | 3003 | app.module.ts | oui | non | oui |
| orchestrator | 3004 | app.module.ts | oui | non | oui |
| notifications | 3005 | app.module.ts | oui | oui (BullMQ) | oui |
| configuration | 3006 | app.module.ts | oui | non | oui |
| file-service | 3007 | app.module.ts | oui | non | oui |
| providers-gateway | 3008 | app.module.ts | oui | non | oui |
| risk-engine | 3009 | app.module.ts | oui | non | oui |
| service-catalog | 3010 | database.providers.ts | non | non | oui |
| logs-reporting | 3011 | non (pas de DB) | non | non | oui |