Skip to content

03 — GATEWAY, CDN & SÉCURISATION

Objectif

À la fin de ce fichier :

  • Cloudflare protège toute l'API (WAF, DDoS, rate limiting, bot protection)
  • Les network policies Kubernetes isolent les services entre eux
  • Les Security Groups sont restreints au strict minimum
  • Le chiffrement est activé partout (transit + repos)
  • Les secrets ont une politique de rotation
  • L'accès au cluster et à l'infra est verrouillé

Pré-requis : fichier 02_cicd_et_services.md complété, les 11 services tournent en staging.


PHASE 1 — CLOUDFLARE WAF & PROTECTION

Objectif

Cloudflare est le bouclier devant ton API. Tout le trafic passe par Cloudflare avant d'atteindre tes services. C'est ici qu'on bloque les attaques avant qu'elles ne touchent ton infrastructure.

Instructions pour l'agent

1.1 Plan Cloudflare Pro

Vérifier que le domaine paywithnex.com est sur le plan Pro (minimum requis pour les WAF rules personnalisées). Le plan Free a un WAF basique mais insuffisant pour une fintech.

1.2 WAF Managed Rules

Activer les rulesets managés par Cloudflare :

  • Cloudflare Managed Ruleset : activé. Protège contre les attaques connues (injections SQL, XSS, path traversal, etc.). Ce sont des règles maintenues par l'équipe sécurité de Cloudflare, mises à jour automatiquement.
  • OWASP Core Ruleset : activé en mode simulation d'abord. Ce ruleset est plus agressif — il peut générer des faux positifs. L'activer en simulation pendant 1 semaine pour observer les déclenchements, puis passer en mode bloquant en excluant les règles qui génèrent des faux positifs.

1.3 WAF Custom Rules

Créer les règles personnalisées suivantes (Cloudflare → Security → WAF → Custom Rules) :

Règle 1 — Rate limiting global :

  • Condition : tout le trafic vers staging.paywithnex.com
  • Limite : 100 requêtes par minute par IP
  • Action : Block (429 Too Many Requests)
  • Pourquoi : empêche le brute force et le scraping. 100 req/min est généreux pour un usage normal.

Règle 2 — Rate limiting auth (plus strict) :

  • Condition : URI contient /auth/login ou /auth/register ou /auth/otp
  • Limite : 10 requêtes par minute par IP
  • Action : Block
  • Pourquoi : les endpoints d'authentification sont les cibles principales de brute force. 10/min suffit largement pour un usage légitime.

Règle 3 — Bloquer les pays non ciblés (optionnel en staging) :

  • Condition : pays NOT IN (CM, GA, CG, TD, GQ, CF, FR, US) — adapter selon ta zone CEMAC + les pays où l'équipe travaille
  • Action : Challenge (Managed Challenge, pas Block — pour ne pas bloquer des utilisateurs légitimes en voyage)
  • Pourquoi : ton service cible la zone CEMAC. Le trafic depuis d'autres pays est suspect par défaut.

Règle 4 — Bloquer les bots connus :

  • Condition : Bot Score < 30 (Cloudflare calcule un score de 1 à 99, 1 = bot certain)
  • Action : Challenge
  • Pourquoi : les bots malveillants testent les API fintech pour trouver des failles.

Règle 5 — Protection des endpoints sensibles :

  • Condition : URI contient /api/transfer ou /api/withdraw ou /api/wallets (adapter selon les routes réelles)
  • Limite : 5 requêtes par minute par IP
  • Action : Block
  • Pourquoi : les opérations financières doivent avoir un rate limiting très strict. Un utilisateur légitime ne fait pas 5 transferts par minute.

1.4 DDoS Protection

Déjà incluse dans le plan Pro. Vérifier que :

  • DDoS protection level : High
  • Sensitivity : Medium (ajuster si trop de faux positifs)

1.5 Page Rules / Configuration Rules

  • Force HTTPS : toutes les requêtes HTTP redirigées vers HTTPS
  • Security Level : Medium pour tout le domaine, High pour les chemins /auth/* et /api/transfer*
  • Browser Integrity Check : activé
  • Hotlink Protection : activé (empêche l'utilisation de tes ressources depuis d'autres sites)

Recommandations

  • Commencer en mode simulation (Log) pour les WAF rules pendant quelques jours avant de passer en mode Block. Observer les logs dans Cloudflare → Security → Events pour repérer les faux positifs.
  • En production, envisager le plan Business (~200 $/mois) pour les WAF rules plus avancées et le support prioritaire. Pour le staging, Pro suffit.
  • Documenter chaque règle WAF avec son justificatif pour le régulateur. Le dossier de conformité doit montrer les mesures anti-fraude.

Validation

bash
# Vérifier que Cloudflare proxy est actif
curl -I https://staging.paywithnex.com
# Attendu : headers cf-ray, server: cloudflare

# Tester le rate limiting (envoyer 15 requêtes rapides sur /auth/login)
for i in $(seq 1 15); do
  curl -s -o /dev/null -w "%{http_code}\n" https://staging.paywithnex.com/auth/login
done
# Attendu : les premières retournent 200/401, les dernières retournent 429

# Vérifier TLS
curl -vI https://staging.paywithnex.com 2>&1 | grep "TLS"
# Attendu : TLS 1.2 ou 1.3

PHASE 2 — NETWORK POLICIES KUBERNETES

Objectif

Isoler les services à l'intérieur du cluster. Même si un pod est compromis, il ne peut pas parler aux services auxquels il n'a pas le droit d'accéder.

Instructions pour l'agent

Créer kubernetes/base/network-policies.yaml avec les règles suivantes :

2.1 Default Deny

Première règle : tout est interdit par défaut dans le namespace nex-staging. Aucun pod ne peut recevoir de trafic entrant sauf si une NetworkPolicy l'autorise explicitement.

Politique : deny-all-ingress
Namespace : nex-staging
PodSelector : tous les pods
Ingress : aucun (vide = deny all)

C'est le principe du moindre privilège appliqué au réseau.

2.2 Services publics — accès depuis l'Ingress

Les 3 services publics (auth, configuration, orchestrator) doivent recevoir le trafic depuis le namespace ingress-nginx (le Ingress Controller) :

Politique : allow-ingress-to-public
Namespace : nex-staging
PodSelector : app in (auth, configuration, orchestrator)
Ingress autorisé : depuis le namespace ingress-nginx

2.3 Services internes — accès depuis l'orchestrator

Les 8 services internes ne sont joignables que par l'orchestrator (et éventuellement par d'autres services internes qui s'appellent entre eux) :

Politique : allow-internal-mesh
Namespace : nex-staging
PodSelector : app in (customer-profiles-kyc, ledger-wallets, notifications, file-service, providers-gateway, risk-engine, service-catalog, logs-reporting)
Ingress autorisé : depuis les pods du namespace nex-staging (communication inter-services)

Recommandation : pour une isolation plus fine en production, créer une policy par service qui liste exactement quels services peuvent l'appeler. Par exemple, notifications ne devrait être appelé que par orchestrator, pas par risk-engine. En staging, autoriser tout le namespace est acceptable.

2.4 Accès aux données (egress)

Autoriser les pods à sortir vers RDS et Redis :

Politique : allow-data-egress
Namespace : nex-staging
PodSelector : tous les pods
Egress autorisé :
  - Port 5432 vers le CIDR des subnets data (10.0.100.0/24, 10.0.200.0/24)
  - Port 6379 vers le CIDR des subnets data
  - Port 443 vers 0.0.0.0/0 (appels API externes : Auth0, Firebase, Resend, Sentry)
  - Port 53 UDP/TCP vers kube-dns (résolution DNS interne obligatoire)

Attention : ne pas oublier le port 53 (DNS). Sans ça, les pods ne peuvent plus résoudre les noms de service Kubernetes ni les noms de domaine externes. C'est une erreur classique qui rend tout silencieusement cassé.

2.5 logs-reporting — cas particulier

Le service logs-reporting n'a pas de base de données. Sa policy egress ne doit pas inclure le port 5432.

Recommandations

  • Les Network Policies nécessitent un CNI (Container Network Interface) qui les supporte. EKS utilise le VPC CNI par défaut qui supporte les NetworkPolicies depuis EKS 1.25 avec le network policy agent. L'agent doit vérifier que le network policy agent est activé sur le cluster.
  • Tester les policies en les appliquant une par une et en vérifiant que les services fonctionnent toujours après chaque ajout. Si un service casse, la policy est trop restrictive.
  • Les Network Policies sont namespace-scoped. Elles ne s'appliquent qu'au namespace nex-staging. Les pods dans d'autres namespaces (monitoring, ingress) ne sont pas affectés.

Validation

bash
# Vérifier les policies appliquées
kubectl get networkpolicies -n nex-staging
# Attendu : 4 policies (deny-all, allow-ingress-to-public, allow-internal-mesh, allow-data-egress)

# Test positif — l'orchestrator peut joindre un service interne
kubectl exec -it deploy/orchestrator -n nex-staging -- wget -qO- --timeout=5 http://ledger-wallets:3005/health
# Attendu : OK

# Test négatif — un service interne ne peut PAS être joint depuis l'extérieur du namespace
kubectl run test-external --rm -it --image=curlimages/curl -n default -- \
  curl --max-time 5 http://ledger-wallets.nex-staging:3005/health
# Attendu : timeout (bloqué par la NetworkPolicy)

# Les services fonctionnent toujours
curl https://staging.paywithnex.com/api/health
# Attendu : OK (le trafic passe toujours via Ingress → orchestrator → services)

PHASE 3 — SECURITY GROUPS HARDENING

Objectif

Restreindre les Security Groups créés au fichier 01. En staging on les avait laissés un peu ouverts pour faciliter le setup. Maintenant que tout fonctionne, on verrouille.

Instructions pour l'agent

3.1 Restreindre sg-alb aux IPs Cloudflare

En phase 01, le sg-alb acceptait le 443 depuis 0.0.0.0/0 (tout internet). Maintenant que Cloudflare est devant, seules les IPs Cloudflare doivent pouvoir atteindre le load balancer.

L'agent doit :

Résultat : si quelqu'un essaie d'accéder directement au NLB AWS (en contournant Cloudflare), il est bloqué.

Recommandation : les IPs Cloudflare changent rarement mais changent. Créer un script ou un job Terraform qui met à jour ces plages périodiquement (mensuel suffit). Ou utiliser un Terraform data source qui fetch les IPs à chaque apply.

3.2 Vérifier que RDS et Redis sont verrouillés

Confirmer que :

  • sg-rds n'accepte QUE le port 5432 depuis sg-eks-nodes
  • sg-redis n'accepte QUE le port 6379 depuis sg-eks-nodes
  • Aucun outbound sur les deux
  • Aucune règle avec 0.0.0.0/0

3.3 Restreindre l'accès kubectl au cluster EKS

En phase 01, l'endpoint public du cluster EKS est ouvert (pour configurer kubectl). Maintenant on restreint :

  • L'agent doit configurer public_access_cidrs dans le module EKS Terraform pour n'autoriser que les IPs de l'équipe (IP du bureau, IPs des devs en remote). Le format est une liste de CIDR.
  • En production (semaine 2), envisager de désactiver complètement l'endpoint public et d'accéder au cluster uniquement via un VPN ou AWS SSM.

Validation

bash
# Vérifier que l'accès direct au NLB est bloqué (depuis une IP non-Cloudflare)
# Récupérer le hostname du NLB
NLB=$(kubectl get svc -n ingress-nginx ingress-nginx-controller -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
curl --max-time 5 https://$NLB
# Attendu : timeout ou connection refused (si ton IP n'est pas une IP Cloudflare)

# Mais via Cloudflare ça marche toujours
curl https://staging.paywithnex.com/api/health
# Attendu : OK

# Vérifier les SG
aws ec2 describe-security-groups --group-ids <sg-rds-id> \
  --query "SecurityGroups[0].IpPermissions[].{Port:FromPort,Source:UserIdGroupPairs[0].GroupId}"
# Attendu : Port 5432 source sg-eks-nodes uniquement

PHASE 4 — CHIFFREMENT

Objectif

Vérifier que toutes les données sont chiffrées en transit et au repos. C'est une exigence réglementaire absolue pour une fintech.

Instructions pour l'agent

4.1 Chiffrement en transit (TLS partout)

Vérifier que chaque connexion est chiffrée :

LiaisonProtocoleDéjà configuré
Utilisateur → CloudflareTLS 1.2+Oui (Cloudflare force HTTPS)
Cloudflare → NLB AWSTLS 1.2+Oui (Full Strict mode)
NLB → Ingress NGINXTLSOui (cert-manager)
Ingress → PodsHTTP (dans le cluster)Acceptable en staging
Pods → RDSTLSÀ vérifier
Pods → RedisTLSOui (activé au fichier 01)
Pods → Auth0HTTPSOui (Auth0 force TLS)
Pods → FirebaseHTTPSOui (Firebase force TLS)
Pods → ResendHTTPSOui (Resend force TLS)

Action requise : vérifier que la connexion PostgreSQL utilise TLS. Dans TypeORM, la config de connexion doit inclure ssl: { rejectUnauthorized: true } ou le paramètre de connexion ?sslmode=require. L'agent doit s'assurer que cette config est dans le code ou dans les variables d'environnement.

Recommandation : en production, activer le TLS entre l'Ingress et les pods (mTLS) avec un service mesh comme Linkerd (léger) ou via les certificats cert-manager. En staging, le HTTP intra-cluster est acceptable car le réseau est privé.

4.2 Chiffrement au repos

Vérifier que tout est chiffré au repos :

RessourceChiffrementConfiguré au fichier 01
RDS PostgreSQLAES-256 (KMS)Oui
ElastiCache RedisAES-256Oui
S3 BackupsAES-256Oui
EBS (disques EKS nodes)AES-256À vérifier
Secrets K8s (etcd)KMS envelope encryptionOui (config EKS)

Action requise : vérifier que les volumes EBS des nœuds EKS sont chiffrés. L'agent doit ajouter encrypted = true dans le launch template du node group si ce n'est pas le cas.

Validation

bash
# Vérifier TLS PostgreSQL
kubectl exec -it deploy/auth -n nex-staging -- sh -c \
  'echo | openssl s_client -connect $DATABASE_HOST:5432 -starttls postgres 2>/dev/null | head -5'
# Attendu : certificat SSL visible

# Vérifier encryption RDS
aws rds describe-db-instances --db-instance-identifier nex-staging-postgres \
  --query "DBInstances[0].StorageEncrypted"
# Attendu : true

# Vérifier encryption EBS
aws ec2 describe-volumes --filters "Name=tag:kubernetes.io/cluster/nex-staging,Values=owned" \
  --query "Volumes[].Encrypted"
# Attendu : tous à true

PHASE 5 — GESTION DES SECRETS

Objectif

S'assurer que les secrets sont gérés proprement avec une politique de rotation.

Instructions pour l'agent

5.1 Audit des secrets

L'agent doit vérifier qu'aucun secret n'est :

  • Hardcodé dans le code source (chercher dans les repos GitLab des patterns comme password=, secret=, api_key=, token=)
  • Présent dans les fichiers .env committés
  • Dans les logs applicatifs (les frameworks comme NestJS peuvent logger les variables d'environnement au démarrage — désactiver ça)

Recommandation : ajouter un hook pre-commit (ou un stage dans le pipeline) qui scanne les commits pour des secrets accidentels. Des outils comme gitleaks ou detect-secrets font ça automatiquement.

5.2 Politique de rotation

Définir la fréquence de rotation de chaque type de secret :

SecretRotationMéthode
DATABASE_PASSWORDTous les 90 joursChanger dans RDS + mettre à jour Doppler + restart pods
REDIS_AUTH_TOKENTous les 90 joursChanger dans ElastiCache + Doppler + restart pods
JWT_SECRETTous les 6 moisMettre à jour dans Doppler + restart pods (invalide les tokens en cours)
AUTH0_CLIENT_SECRETJamais (géré par Auth0)Rotation manuelle si compromis
FIREBASE_SERVER_KEYJamais (géré par Firebase)Rotation manuelle si compromis
RESEND_API_KEYJamaisRotation manuelle si compromis
SENTRY_DSNJamaisPas un secret sensible

L'agent doit générer un script scripts/rotate-db-password.sh qui :

  1. Génère un nouveau mot de passe
  2. Le met à jour dans RDS (via AWS CLI)
  3. Le met à jour dans Doppler
  4. Force un refresh de l'ExternalSecret K8s
  5. Fait un rolling restart des pods pour qu'ils prennent le nouveau mot de passe

Recommandation : ne pas automatiser la rotation complètement en staging. Un script manuel suffit. En production, planifier un rappel trimestriel (calendrier ou ticket Jira récurrent).

5.3 Accès aux secrets — qui a accès à quoi

PersonneAccès DopplerAccès console AWSAccès kubectl
DevOps leadTous les envsAdminCluster admin
Développeursdev + staging (lecture)Aucunnamespace nex-staging uniquement
CDPAucunAucunAucun
CI/CD (GitLab)staging (service token)AucunDeploy uniquement

L'agent doit configurer les permissions Doppler en conséquence. Les développeurs ne doivent pas pouvoir voir les secrets de production.

Validation

bash
# Scanner le repo pour des secrets exposés
# L'agent installe et exécute gitleaks sur le repo
gitleaks detect --source=. --verbose
# Attendu : 0 leaks found

# Vérifier que les logs ne contiennent pas de secrets
kubectl logs deploy/auth -n nex-staging | grep -iE "password|secret|token|api.key" | head -5
# Attendu : rien (ou des valeurs masquées)

PHASE 6 — IAM & MOINDRE PRIVILÈGE

Objectif

Chaque composant ne doit avoir que les permissions strictement nécessaires.

Instructions pour l'agent

6.1 IRSA (IAM Roles for Service Accounts)

Au lieu de donner un rôle IAM large aux nœuds EKS (qui serait partagé par tous les pods), utiliser IRSA pour attribuer un rôle spécifique à chaque service qui en a besoin.

Seuls les services qui accèdent à des ressources AWS directement ont besoin d'un rôle IRSA :

ServiceAccès AWS nécessaireRôle IRSA
Tous les services (backups)S3 PutObject sur le bucket backupsnex-s3-backup-role
CronJob réconciliationRDS lecture (via IAM auth optionnel)Non requis si auth par password

La plupart des services n'ont pas besoin d'IRSA — ils accèdent à RDS et Redis via mot de passe (dans les secrets), et aux services tiers (Auth0, Firebase, Resend) via des API keys.

Recommandation : ne pas créer d'IRSA pour chaque service en staging. C'est de l'optimisation de production. En staging, si un service a besoin d'écrire dans S3, créer un seul rôle IRSA partagé avec les permissions minimales.

6.2 Compte IAM CI/CD

Le pipeline GitLab CI a besoin d'un kubeconfig pour déployer. Ce kubeconfig doit être lié à un user ou rôle IAM avec des permissions minimales :

  • eks:DescribeCluster (pour se connecter)
  • Accès K8s limité au namespace nex-staging (via RBAC Kubernetes, pas via IAM)

L'agent doit créer un ClusterRole K8s nex-deployer avec les permissions : get/list/watch/update/patch sur les Deployments, Services, ConfigMaps du namespace nex-staging uniquement. Pas de delete, pas d'accès aux Secrets, pas d'accès aux autres namespaces.

Validation

bash
# Vérifier les permissions du rôle CI/CD
kubectl auth can-i update deployments -n nex-staging --as=system:serviceaccount:nex-staging:gitlab-deployer
# Attendu : yes

kubectl auth can-i delete pods -n nex-staging --as=system:serviceaccount:nex-staging:gitlab-deployer
# Attendu : no

kubectl auth can-i get secrets -n nex-staging --as=system:serviceaccount:nex-staging:gitlab-deployer
# Attendu : no

PHASE 7 — PROTECTION SUPPLÉMENTAIRE

Objectif

Couches de sécurité additionnelles spécifiques à une fintech.

Instructions pour l'agent

7.1 Pod Security Standards

Appliquer les Pod Security Standards de Kubernetes sur le namespace nex-staging :

  • Level : restricted (le plus strict)
  • Cela force : pas de conteneur root, pas de privilege escalation, pas d'accès au host network, filesystem read-only (si possible)

Si restricted bloque certains services (certains frameworks ont besoin d'écrire dans /tmp), passer à baseline et documenter pourquoi.

7.2 VPC Flow Logs

Activer les VPC Flow Logs sur le VPC. Ils enregistrent tout le trafic réseau (source, destination, port, accept/reject). C'est une exigence courante des régulateurs pour la traçabilité réseau.

  • Destination : CloudWatch Logs (group /vpc/nex-staging/flow-logs)
  • Filtre : ALL (accept + reject)
  • Rétention : 90 jours

Coût : les flow logs génèrent du volume. En staging c'est négligeable. En production, surveiller le coût CloudWatch Logs.

7.3 AWS GuardDuty

Activer GuardDuty dans la région eu-west-1. C'est le service de détection de menaces d'AWS — il analyse les CloudTrail logs, VPC Flow Logs et DNS logs pour détecter des comportements suspects (accès depuis une IP malveillante, appels API inhabituels, communication avec des serveurs C&C).

  • Coût : pay-per-use, généralement < 5 $/mois pour une petite infra
  • L'agent l'active via Terraform (resource aws_guardduty_detector)

7.4 Scan de sécurité Git

Ajouter dans le pipeline GitLab CI un job qui exécute gitleaks sur chaque push. Si un secret est détecté dans le code, le pipeline échoue.

Recommandations

  • La plupart de ces mesures sont peu coûteuses et demandent peu d'effort mais impressionnent le régulateur. Elles montrent une posture de sécurité proactive.
  • GuardDuty en particulier est souvent demandé par les auditeurs de sécurité. L'activer maintenant évite de devoir le faire dans l'urgence.
  • Les Pod Security Standards peuvent casser des applications qui n'ont pas été conçues pour tourner en mode restricted. Les appliquer progressivement et tester chaque service.

Validation

bash
# Pod Security Standards appliqués
kubectl get ns nex-staging -o jsonpath='{.metadata.labels}'
# Attendu : pod-security.kubernetes.io/enforce=baseline (ou restricted)

# VPC Flow Logs actifs
aws ec2 describe-flow-logs --filter "Name=resource-id,Values=<vpc-id>"
# Attendu : 1 flow log en status ACTIVE

# GuardDuty actif
aws guardduty list-detectors
# Attendu : 1 detector ID

CHECKLIST GLOBALE — FIN DU FICHIER 03

Cloudflare

  • [ ] Plan Pro actif sur paywithnex.com
  • [ ] WAF Managed Ruleset activé
  • [ ] OWASP Ruleset activé (simulation ou block)
  • [ ] Rate limiting global : 100 req/min/IP
  • [ ] Rate limiting auth : 10 req/min/IP
  • [ ] Rate limiting transactions : 5 req/min/IP
  • [ ] DDoS protection level High
  • [ ] SSL/TLS Full Strict
  • [ ] HSTS activé

Network Policies Kubernetes

  • [ ] Default deny appliqué sur nex-staging
  • [ ] Services publics accessibles depuis ingress-nginx uniquement
  • [ ] Services internes accessibles depuis nex-staging uniquement
  • [ ] Egress autorisé vers RDS, Redis, DNS, HTTPS externe
  • [ ] Les 11 services fonctionnent toujours après application des policies

Security Groups

  • [ ] sg-alb restreint aux IPs Cloudflare uniquement
  • [ ] sg-rds : port 5432 depuis sg-eks-nodes uniquement
  • [ ] sg-redis : port 6379 depuis sg-eks-nodes uniquement
  • [ ] Accès kubectl restreint aux IPs de l'équipe

Chiffrement

  • [ ] TLS sur toutes les connexions externes
  • [ ] TLS entre les pods et RDS PostgreSQL
  • [ ] TLS entre les pods et Redis
  • [ ] Encryption at rest sur RDS, Redis, S3, EBS
  • [ ] Secrets K8s chiffrés avec KMS

Secrets & IAM

  • [ ] Aucun secret hardcodé dans le code (scan gitleaks clean)
  • [ ] Aucun secret dans les logs applicatifs
  • [ ] Politique de rotation documentée
  • [ ] Script de rotation du mot de passe DB prêt
  • [ ] Permissions Doppler configurées (devs = staging lecture seule)
  • [ ] Rôle CI/CD avec permissions minimales (deploy only, pas de delete/secrets)

Protection

  • [ ] Pod Security Standards appliqués
  • [ ] VPC Flow Logs actifs
  • [ ] GuardDuty activé
  • [ ] gitleaks dans le pipeline CI

Si un point est rouge → corriger avant de passer au fichier 04.


Prochaine étape : 04_monitoring_alertes.md — Grafana Cloud, Sentry, UptimeRobot, alertes, dashboards, runbook.

NxPay — Plateforme fintech CEMAC