CreaRack-SL

Desencriptación de NotificationChannel.config (decrypt_channel_config)

Descripción

decrypt_channel_config(config: dict) → dict es el par simétrico de encrypt_channel_config. Se invoca justo antes de que el dispatcher envíe una notificación (webhook, Slack, Teams, email) para recuperar los secretos en plaintext necesarios para autenticación y comunicación.

Ubicación: monitoring/services/notification_service.py (línea ~158).

Qué desencripta

Espejo exacto de la encriptación:

  • Top-level: valores en _SECRET_CONFIG_KEYS (si son tokens Fernet)
  • Headers anidados: valores cuyo nombre aparece en _SECRET_HEADER_NAMES
  • Estructura: claves públicas quedan intactas

Componentes

_dec_value(v: str) → str

Función auxiliar que:

  1. Si v es vacío, None, o no es string → devuelve sin cambios
  2. Si no es un token Fernet (detectado por not CredentialManager.is_encrypted(v)) → devuelve sin cambios (plaintext o valor no-secreto)
  3. Si es token Fernet → llama a CredentialManager.safe_decrypt(v, "channel_config")
    • En caso de fallo (clave perdida, token corrupto) → devuelve "" (empty fallback)

Fuente: core.security.credential_manager.CredentialManager

Punto de invocación

Se llama en todos los dispatchers:

  • _send_webhook(channel, payload) → cfg = decrypt_channel_config(channel.config) → luego accede cfg.get("url")
  • _send_slack(channel, insight, event) → mismo patrón
  • _send_teams(channel, insight, event) → mismo patrón
  • send_test_notification(channel) → al validar con POST test

Tolerancia a fallos

  • Si la clave de desencriptación está perdida/rotada y no se puede recuperar → safe_decrypt devuelve "" (fallback vacío), el webhook falla con error de conexión (URL vacía) → el alert queda en el log, no hay crash ni exposure
  • Si el valor no es Fernet (plaintext viejo, migración a medio hacer) → se usa directamente (backward-compatible)
  • Si el config es None o no es dict → devuelve sin cambios

Seguridad

Este patrón reduce la ventana de exposición:

  1. En la BD: token Fernet (no plaintext)
  2. En memoria: desencriptado solo cuando se necesita
  3. En logs de la llamada HTTP al webhook: la URL está en plaintext momentáneamente, pero esto es necesario (el webhook debe recibirla)
  4. Rotation: la operación inversa de reencrypt_credentials puede cambiar la clave (Fernet KDF) sin romper los dispatches

Testing

Cubierto por test_dispatch_roundtrip_decrypts en TestChannelConfigEncryption:

  • encrypt → decrypt recupera los secretos originales
  • Non-secret fields (e.g., addresses) quedan intactos
  • Headers con Authorization se recuperan sin daño

Véase también

  • [[entity—monitoring—service—encrypt-channel-config]]
  • [[feature—monitoring—notification-channel-encryption]]
  • [[entity—core—service—credential-manager]]
  • [[concept—saas—security-at-rest]]
  • [[entity—monitoring—handler—webhook-dispatcher]]