Tornar al BlogTècnic

Anonimització de registres JSON compliant a GDPR...

Els registres del servidor (Kubernetes, Docker, syslog, Elasticsearch) contenen adreça IP, ID de sessió, PII de demanda HTTP.

April 21, 20267 min llegit
JSON logsGDPR complianceDevOps privacylog anonymizationdata minimization

Problema: registres del servidor contenen PII

Logs del servidor típics contenen:

  • Direccions IP: 192.168.1.100, 2001:db8::1
  • ID de sessió: UUID, JWT tokens, cookies
  • Paràmetres de demanda: email, números de compte, noms
  • Capçaleres HTTP: User-Agent, Authorization, X-Forwarded-For
  • Respostes d'API: JSON amb dades de usuari

Problema GDPR: Si un operador de servidors pot accedir als logs, pot veure les adreços IP, IDs de sessió, emails dels usuaris — violació d'Article 32 (mesures de seguretat).

Arquitectura de 3 capes de anonimització de logs

Capa 1: Anonimització en el origen (aplicació)

  • Aplicació anonimitza dades sensibles als logs antes d'escriure
  • Exemple: user_id = hash(user_id), ip = hash(ip), email = <redacted>

Capa 2: Anonimització en transit (recopilador de logs)

  • Recopilador de logs (Filebeat, Logstash, Fluentd) anonimitza logs entre servidor i sistema central
  • Exemple: regex per redactar adreces emails, números de compte

Capa 3: Anonimització en repòs (central de logs)

  • Sistema central (Elasticsearch, Splunk, CloudWatch) anonimitza logs al emmagatzemament
  • Exemple: eliminar logs més vells de 30 dies (retenció)

Implementació pràctica: Anonimització de logs JSON

Exemple de log original en JSON:

{
  "timestamp": "2025-01-15T10:30:45Z",
  "level": "INFO",
  "service": "api-gateway",
  "user_id": "12345",
  "user_email": "john.smith@company.com",
  "ip_address": "192.168.1.100",
  "http_method": "POST",
  "http_path": "/api/users/12345",
  "http_status": 200,
  "request_body": {"email": "john.smith@company.com", "account_number": "ACC-98765"},
  "response_time_ms": 250
}

Capa 1: Anonimització en origen (Node.js):

const crypto = require('crypto');

function hashPII(value) {
  return crypto.createHash('sha256').update(value).digest('hex').substring(0, 12);
}

function anonymizeLog(logEntry) {
  return {
    timestamp: logEntry.timestamp,
    level: logEntry.level,
    service: logEntry.service,
    user_id: hashPII(logEntry.user_id),
    user_email: '<REDACTED>',
    ip_address: '<IP>',
    http_method: logEntry.http_method,
    http_path: logEntry.http_path.replace(/\/\d+/, '/:id'), // /api/users/12345 -> /api/users/:id
    http_status: logEntry.http_status,
    request_body: '<REDACTED>', // no loguejis request body que conté PII
    response_time_ms: logEntry.response_time_ms
  };
}

const anonLog = anonymizeLog(logEntry);
console.log(JSON.stringify(anonLog));

Resultat anonimitzat:

{
  "timestamp": "2025-01-15T10:30:45Z",
  "level": "INFO",
  "service": "api-gateway",
  "user_id": "a3b2c1d4e5f6",
  "user_email": "<REDACTED>",
  "ip_address": "<IP>",
  "http_method": "POST",
  "http_path": "/api/users/:id",
  "http_status": 200,
  "request_body": "<REDACTED>",
  "response_time_ms": 250
}

Capa 2: Anonimització en transit (Logstash)

filter {
  # Redactar adreces email
  mutate {
    gsub => [ "message", "([\w\.-]+@[\w\.-]+\.\w+)", "<EMAIL>" ]
  }
  
  # Redactar adreces IP (except loopback)
  mutate {
    gsub => [ "message", "(?<!127\.)\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", "<IP>" ]
  }
  
  # Redactar números de compte (format ACC-XXXXX)
  mutate {
    gsub => [ "message", "ACC-\d{5}", "<ACCOUNT>" ]
  }
  
  # Eliminar query parameters que podrien contenir PII
  if [http_query] {
    mutate {
      replace => { "http_query" => "<REDACTED>" }
    }
  }
}

Capa 3: Anonimització en repòs (Elasticsearch + Retenció)

// Política de retenció Elasticsearch
{
  "policy": "gdpr-log-retention",
  "phases": {
    "hot": {
      "min_age": "0d",
      "actions": {
        "set_priority": {
          "priority": 100
        }
      }
    },
    "warm": {
      "min_age": "7d",
      "actions": {
        "set_priority": {
          "priority": 50
        }
      }
    },
    "delete": {
      "min_age": "30d",
      "actions": {
        "delete": {}
      }
    }
  }
}

Validació de conformitat GDPR

Checklist per a logs anonimitzatos:

  • Sense adreces IP: Cercar pattern \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} — s'espera 0 coincidències (excepte 127.0.0.1)
  • Sense emails: Cercar pattern [\w\.-]+@[\w\.-]+\.\w+ — s'espera 0 coincidències
  • Sense números de compte: Cercar pattern ACC-\d{5} — s'espera 0 coincidències
  • Sense user IDs de text pla: Cercar paterns de user ID originals (p. ex. noms, emails) — s'espera 0 coincidències
  • Sense paràmetres de consulta: Cercar URLs amb query strings que continguin paràmetres — s'espera 0 coincidències
  • Retenció limitada: Verificar que els logs més vells de 30 dies es eliminen automàticament
  • Accés restringit: Verificar que els operadors requereixen autenticació MFA per accedir a logs, i els accessos estan auditados

Fonts:

Preparat per protegir les vostres dades?

Comenceu a anonimitzar PII amb més de 285 tipus d'entitats en 48 idiomes.