Conformité et audit

Conformité réglementaire et audit dans les systèmes distribués : journaux d'audit, RGPD, chiffrement des données, rétention et traçabilité des actions.

Pourquoi la conformité compte en architecture

La conformité réglementaire n’est pas seulement une question juridique — elle a des implications directes sur la conception et le fonctionnement d’un système. Des réglementations comme le RGPD, PCI-DSS ou SOC 2 imposent des exigences techniques concrètes sur la manière dont les données sont stockées, traitées et protégées.

Ignorer la conformité lors de la conception de l’architecture signifie devoir effectuer des changements coûteux par la suite, ou pire, faire face à des sanctions légales et à une perte de confiance des utilisateurs.

Journaux d’audit

Les journaux d’audit enregistrent qui a fait quoi, quand et sur quelle ressource. Ils constituent la base de toute stratégie de conformité.

Que faut-il enregistrer

Tout ne nécessite pas un journal d’audit. Concentrez-vous sur :

  • Authentification : connexion réussie, connexion échouée, déconnexion, changement de mot de passe
  • Autorisation : accès refusé, changement de rôles ou de permissions
  • Données sensibles : lecture, création, modification ou suppression de données personnelles
  • Configuration : changements de configuration du système, déploiements
  • Opérations critiques : transactions financières, suppression de comptes, export de données

Structure d’un journal d’audit

{
  "timestamp": "2024-01-15T14:30:00.000Z",
  "eventType": "DATA_ACCESS",
  "action": "READ",
  "actor": {
    "userId": "user-456",
    "role": "admin",
    "ip": "192.168.1.100",
    "userAgent": "Mozilla/5.0..."
  },
  "resource": {
    "type": "user_profile",
    "id": "user-789",
    "fields": ["email", "phone", "address"]
  },
  "result": "SUCCESS",
  "metadata": {
    "service": "users-service",
    "requestId": "req-abc-123",
    "traceId": "trace-xyz-789"
  }
}

Propriétés d’un bon journal d’audit

PropriétéDescription
ImmuableUne fois écrit, il ne peut être ni modifié ni supprimé
CompletContient toutes les informations nécessaires pour reconstituer l’événement
TraçablePeut être corrélé avec d’autres journaux via un requestId ou un traceId
SécuriséProtégé contre les accès non autorisés et les manipulations
ConservéStocké pendant la durée requise par la réglementation

Implémentation pratique

class AuditLogger {
  async log(event) {
    const auditEntry = {
      timestamp: new Date().toISOString(),
      eventType: event.type,
      action: event.action,
      actor: {
        userId: event.userId,
        role: event.userRole,
        ip: event.clientIp,
      },
      resource: {
        type: event.resourceType,
        id: event.resourceId,
      },
      result: event.result,
      metadata: {
        service: process.env.SERVICE_NAME,
        requestId: event.requestId,
        traceId: event.traceId,
      }
    };

    // Écrire dans un stockage immuable
    await this.auditStore.append(auditEntry);
    
    // Ne jamais échouer silencieusement en audit
    // Si l'enregistrement échoue, l'opération doit échouer
  }
}

Stockage des journaux d’audit

Les journaux d’audit nécessitent un stockage particulier :

  • Append-only : on ne peut qu’ajouter des enregistrements, jamais les modifier ni les supprimer
  • Séparé : dans une base de données ou un service différent de celui de l’application
  • Chiffré : les journaux peuvent contenir des données sensibles
  • Répliqué : copies dans plusieurs emplacements pour éviter toute perte

Options courantes :

  • Amazon S3 avec Object Lock (immutabilité)
  • Elasticsearch avec des index en lecture seule
  • Base de données dédiée avec permissions d’insertion uniquement
  • Services spécialisés comme Splunk ou Datadog

RGPD et protection des données personnelles

Le Règlement Général sur la Protection des Données (RGPD) de l’Union Européenne établit des exigences strictes sur la manière dont les données personnelles sont traitées. Bien qu’il s’agisse d’une réglementation européenne, elle concerne tout système traitant des données de résidents de l’UE.

Principes clés du RGPD

  1. Minimisation des données : ne collecter que les données strictement nécessaires
  2. Limitation de la finalité : utiliser les données uniquement pour l’objectif déclaré
  3. Limitation de la conservation : ne pas conserver les données plus longtemps que nécessaire
  4. Intégrité et confidentialité : protéger les données contre tout accès non autorisé
  5. Responsabilité proactive : démontrer la conformité, pas seulement la respecter

Droits de l’utilisateur ayant un impact sur l’architecture

Droit d’accès (Art. 15)

L’utilisateur peut demander toutes les données que le système possède à son sujet :

// Le système doit pouvoir collecter les données de TOUS les services
async function getUserData(userId) {
  const [profile, orders, payments, logs] = await Promise.all([
    usersService.getData(userId),
    ordersService.getData(userId),
    paymentsService.getData(userId),
    auditService.getData(userId),
  ]);
  
  return {
    personalData: profile,
    orderHistory: orders,
    paymentHistory: payments,
    activityLog: logs,
    exportedAt: new Date().toISOString()
  };
}

Cela implique que chaque microservice doit pouvoir exporter les données d’un utilisateur spécifique.

Droit à l’oubli (Art. 17)

L’utilisateur peut demander la suppression de toutes ses données :

async function deleteUserData(userId) {
  // Supprimer de tous les services
  await usersService.deleteUser(userId);
  await ordersService.anonymizeOrders(userId);
  await paymentsService.anonymizePayments(userId);
  
  // Certaines données ne peuvent pas être supprimées (obligations légales)
  // mais peuvent être anonymisées
  await auditService.anonymizeEntries(userId);
  
  // Enregistrer la suppression (paradoxalement, celle-ci est bien conservée)
  await auditLogger.log({
    type: 'DATA_DELETION',
    action: 'DELETE',
    userId: 'ANONYMIZED',
    resourceId: userId
  });
}

Droit à la portabilité (Art. 20)

L’utilisateur peut demander ses données dans un format lisible par machine :

{
  "format": "JSON",
  "exportDate": "2024-01-15",
  "userData": {
    "profile": { "name": "María García", "email": "maria@ejemplo.com" },
    "orders": [
      { "id": "ord-001", "date": "2024-01-10", "total": 150.00 }
    ]
  }
}

Implications architecturales du RGPD

  • Chaque service doit savoir quelles données personnelles il stocke
  • Un mécanisme centralisé doit exister pour exécuter les droits de l’utilisateur
  • Les données doivent pouvoir être anonymisées sans compromettre l’intégrité du système
  • Les journaux d’audit doivent équilibrer rétention et droit à l’oubli

Chiffrement des données

Chiffrement en transit

Toute donnée circulant sur le réseau doit être chiffrée :

  • TLS 1.2+ pour la communication externe
  • mTLS pour la communication entre services
  • Chiffrement des messages dans les files d’attente et les bus d’événements

Chiffrement au repos

Les données stockées doivent être chiffrées :

Niveaux de chiffrement au repos :

1. Chiffrement de disque (transparent)
   - AWS EBS encryption, Azure Disk Encryption
   - Protège contre le vol physique du disque

2. Chiffrement de base de données (TDE)
   - Transparent Data Encryption dans PostgreSQL, MySQL
   - Protège contre l'accès direct aux fichiers de la BD

3. Chiffrement au niveau des champs (application-level)
   - Champs spécifiques chiffrés par l'application
   - Protège même si la BD est compromise

Chiffrement au niveau des champs

Pour les données particulièrement sensibles, chiffrez les champs individuellement :

const crypto = require('crypto');

class FieldEncryption {
  constructor(key) {
    this.key = Buffer.from(key, 'hex');
  }

  encrypt(plaintext) {
    const iv = crypto.randomBytes(16);
    const cipher = crypto.createCipheriv('aes-256-gcm', this.key, iv);
    let encrypted = cipher.update(plaintext, 'utf8', 'hex');
    encrypted += cipher.final('hex');
    const tag = cipher.getAuthTag().toString('hex');
    return `${iv.toString('hex')}:${tag}:${encrypted}`;
  }

  decrypt(ciphertext) {
    const [ivHex, tagHex, encrypted] = ciphertext.split(':');
    const iv = Buffer.from(ivHex, 'hex');
    const tag = Buffer.from(tagHex, 'hex');
    const decipher = crypto.createDecipheriv('aes-256-gcm', this.key, iv);
    decipher.setAuthTag(tag);
    let decrypted = decipher.update(encrypted, 'hex', 'utf8');
    decrypted += decipher.final('utf8');
    return decrypted;
  }
}

// Utilisation
const encryption = new FieldEncryption(process.env.ENCRYPTION_KEY);
const encryptedSSN = encryption.encrypt('123-45-6789');

Gestion des clés

Les clés de chiffrement sont aussi sensibles que les données qu’elles protègent :

  • Ne jamais stocker les clés dans le code source
  • Utiliser un service de gestion des clés (KMS) : AWS KMS, Azure Key Vault, HashiCorp Vault
  • Faire tourner les clés périodiquement
  • Conserver des clés distinctes par environnement (développement, staging, production)
  • Implémenter l’envelope encryption pour les données à grande échelle

Rétention des données

Chaque type de donnée a une période de rétention différente selon la réglementation et la finalité :

Type de donnéeRétention typiqueRaison
Journaux d’audit1 à 7 ansConformité réglementaire
Données de transactions5 à 10 ansObligations fiscales
Données personnellesTant que nécessaireRGPD : minimisation
Journaux d’application30 à 90 joursDébogage et opérations
Sauvegardes30 à 365 joursReprise après sinistre

Implémentation des politiques de rétention

# Politique de rétention par type de donnée
retention_policies:
  audit_logs:
    retention_days: 2555  # 7 ans
    storage: s3-archive
    encryption: aes-256
    immutable: true
    
  application_logs:
    retention_days: 90
    storage: elasticsearch
    auto_delete: true
    
  user_data:
    retention: until_deletion_request
    anonymization: on_request
    backup_retention_days: 30
    
  transaction_data:
    retention_days: 3650  # 10 ans
    storage: database
    anonymization: after_retention

Traçabilité des actions

Dans un système distribué, une action de l’utilisateur peut impliquer plusieurs services. La traçabilité permet de reconstituer le chemin complet :

L'utilisateur demande la suppression de son compte
  → API Gateway (requête reçue)
    → BFF (orchestre la suppression)
      → Users Service (supprime le profil)
      → Orders Service (anonymise les commandes)
      → Payments Service (anonymise les paiements)
      → Notifications Service (envoie la confirmation)
    → Audit Service (enregistre l'opération complète)

Correlation ID

Chaque requête génère un identifiant unique qui se propage à tous les services :

// Middleware qui génère ou propage le correlation ID
function correlationMiddleware(req, res, next) {
  const correlationId = req.headers['x-correlation-id'] || uuid();
  req.correlationId = correlationId;
  res.setHeader('x-correlation-id', correlationId);
  
  // Inclure dans tous les journaux
  req.logger = logger.child({ correlationId });
  
  next();
}

Grâce au correlation ID, vous pouvez chercher dans les journaux de tous les services et reconstituer exactement ce qui s’est passé à chaque étape.

Checklist de conformité

Pour vérifier que votre architecture répond aux exigences de base :

  • Les journaux d’audit sont immuables et chiffrés
  • Chaque service peut exporter les données d’un utilisateur spécifique
  • Il existe un mécanisme pour supprimer ou anonymiser les données d’un utilisateur
  • Les données en transit sont chiffrées (TLS/mTLS)
  • Les données au repos sont chiffrées
  • Les clés de chiffrement sont gérées dans un KMS, pas dans le code
  • Des politiques de rétention sont définies par type de donnée
  • Chaque requête possède un correlation ID pour la traçabilité
  • Les accès aux données sensibles sont enregistrés dans le journal d’audit
  • Les données personnelles sont collectées avec un consentement explicite

Résumé

La conformité réglementaire et l’audit sont des responsabilités architecturales, pas seulement juridiques. Les journaux d’audit immuables constituent la base pour démontrer la conformité. Le RGPD impose des exigences concrètes sur la manière dont les données personnelles sont stockées, exportées et supprimées — et ces exigences influencent directement la conception de chaque microservice. Le chiffrement protège les données en transit et au repos, et la gestion des clés est aussi critique que le chiffrement lui-même. La traçabilité via des correlation IDs permet de reconstituer n’importe quelle action à travers plusieurs services. Concevoir en pensant à la conformité dès le départ est bien plus économique que de s’adapter par la suite.