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:
- Si
ves vacío,None, o no es string → devuelve sin cambios - Si no es un token Fernet (detectado por
not CredentialManager.is_encrypted(v)) → devuelve sin cambios (plaintext o valor no-secreto) - Si es token Fernet → llama a
CredentialManager.safe_decrypt(v, "channel_config")- En caso de fallo (clave perdida, token corrupto) → devuelve
""(empty fallback)
- En caso de fallo (clave perdida, token corrupto) → devuelve
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 accedecfg.get("url")_send_slack(channel, insight, event)→ mismo patrón_send_teams(channel, insight, event)→ mismo patrónsend_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_decryptdevuelve""(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:
- En la BD: token Fernet (no plaintext)
- En memoria: desencriptado solo cuando se necesita
- En logs de la llamada HTTP al webhook: la URL está en plaintext momentáneamente, pero esto es necesario (el webhook debe recibirla)
- Rotation: la operación inversa de
reencrypt_credentialspuede 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]]