Se acabó el incordio del keychain: cifrado opt-in con el keychain del sistema operativo para secretos almacenados


Lunes por la mañana, abres la app de escritorio de Hermes y, en lugar de tu lista de chats, te aparece un diálogo de macOS: «Hermes quiere acceder a tu keychain. Introduce tu contraseña para permitirlo.» La tecleas, la app carga. El martes: el mismo diálogo. Cada arranque, para siempre — porque los secretos de la app estaban cifrados con una clave depositada en el keychain de inicio de sesión, y tu keychain estaba bloqueado, ausente o corrupto. Es el tipo de incordio que te dan ganas de tirar la máquina por la ventana. Hermes v0.20.6 (commit 6a6e16fa5d) lo arregla de raíz: el cifrado de secretos almacenados respaldado por keychain ahora es una opción explícita (opt-in), y la ruta por defecto no llama al keychain en absoluto.

El cambio apunta a los secretos almacenados en el escritorio: tokens de gateways remotos, cabeceras de Cloudflare Access y conjuntos de tokens OAuth nativos. Antes, el safeStorage de Electron depositaba una clave por app («Hermes Key») en el keychain de inicio de sesión de macOS, y cualquier contacto con safeStorage — incluso la comprobación de «¿está disponible el cifrado?» — podía lanzar un diálogo bloqueante de keychain en máquinas con el keychain por defecto bloqueado o corrupto. Ese era un comportamiento predeterminado inaceptable para una app de chat, así que la conducta se invirtió: el cifrado ahora es opt-in, el almacenamiento plano es la opción por defecto, y una migración de un solo paso limpia los restos del comportamiento antiguo.

Qué cambió

La política se define en un módulo independiente (electron/secret-storage-policy.ts) — deliberadamente libre de import 'electron' para que los unit tests pasen limpios — con tres propiedades:

  • Ajuste OFF (por defecto): los secretos se escriben con codificación 'plain' y nunca se llama a ninguna API de safeStorage — incluida isEncryptionAvailable(), que en sí misma toca el keychain. Sin keychain, sin diálogo, sin prompt.
  • Ajuste ON: el comportamiento anterior — cifrado estricto de safeStorage, fallo ruidoso cuando el keychain no está disponible, y un diálogo de confirmación de texto plano por guardado como vía de escape.
  • Migración de un solo paso: los blobs heredados escritos antes de que existiera el flag están codificados con safeStorage en disco. Con el ajuste desactivado, Hermes intenta una pasada de migración (descifrar → reescribir como plano). La pasada se registra en el mismo archivo de ajustes tenga éxito o no, de modo que un keychain roto cuesta como mucho un prompt en el primer arranque posterior a la actualización — nunca uno por arranque.

El flag on usa una coerción estricta de === true: un valor truthy pero no estrictamente true no debe activar en silencio los prompts de keychain (replicando la regla de coerción allowPlainText en hardening.ts). El archivo de política vive en secure-token-storage.json.

Cómo usarlo

Escritorio (recomendado): abre Settings → Gateway, encuentra el toggle de keychain/almacenamiento seguro y actívalo. Al activar el toggle, cada almacén de secretos se recodifica en su sitio — v1 connection.json, v2 connections.json y native-oauth-tokens.json — y la especificación at-rest cubre ambas posturas: contrato intacto si has hecho opt-in, guardado por defecto sin almacenamiento seguro, permisos de solo el propietario y viaje de ida y vuelta al reiniciar.

El detalle de la migración que merece la pena conocer: si vienes de una versión anterior, el primer arranque posterior a la actualización con el ajuste por defecto (off) intenta la migración de un solo paso — descifrando los blobs existentes de safeStorage a archivos planos 0600. Los blobs indescifrables (por ejemplo, un keychain muerto) se conservan en disco pero después se leen como ausentes, clasificados como ‘drop’, de modo que un keychain muerto genera como mucho un prompt. En Linux, el backend de keychain subyacente es configurable: desktop.password_store acepta auto (detectar el keychain de la sesión — KWallet a través de las variables de entorno de la sesión KDE, GNOME Keyring / cualquier proveedor de org.freedesktop.secrets como KeePassXC vía D-Bus) o un backend forzado (gnome-libsecret, kwallet, kwallet5, kwallet6); basic significa un almacén sin cifrar. Una variable de entorno explícita HERMES_DESKTOP_PASSWORD_STORE sigue teniendo prioridad sobre la configuración.

Qué sigue igual

  • Las máquinas con opt-in mantienen el contrato completo: cifrado estricto de safeStorage, fallo ruidoso cuando el keychain no está disponible.
  • Los permisos de archivo de solo el propietario en los archivos planos de respaldo (0600) mantienen razonable la postura de «sin cifrar en reposo»: solo los puede leer tu usuario.
  • Los secretos siguen siendo secretos. El cambio trata de dónde vive la clave de cifrado (keychain del sistema operativo frente a archivos planos de solo el propietario), no de exponer tokens en logs o en contenido visible para el modelo — la maquinaria de redacción existente (security.redact_secrets) queda intacta.

Cuándo hacer opt-in

  • Haz opt-in si quieres cifrado en reposo a nivel de sistema operativo y tu keychain está sano — la postura estándar para portátiles, máquinas compartidas o entornos orientados al cumplimiento.
  • Déjalo desactivado si tu keychain está bloqueado/ausente/corrupto (la población de los diálogos), si prefieres no tener una clave por app sentada en el keychain de inicio de sesión, o si el prompt de cada arranque te estaba volviendo loco. La ruta por defecto ahora está libre de prompts por diseño.

El panorama general

Esto forma parte del tema de fiabilidad de v0.20.6: la misma ventana que convirtió en predeterminados la caché de búsqueda web y la compresión lean-tail también evitó que el actualizador matara gateways por tree-kill (consulta nuestra guía de actualización elegante). El almacenamiento de secretos era la última cosa del escritorio que podía bloquear tu mañana con un diálogo de contraseña — ahora es opt-in, silencioso y reversible. Para el resumen completo de la release, consulta las notas de la release v0.20.6.

Un solo toggle. Se acabó el «Hermes quiere acceder a tu keychain» diario — a menos que quieras el cifrado, en cuyo caso sigue ahí, a un interruptor de distancia.