Skip to content

fix(security): ceo-web resuelve sus secretos desde 1Password al arrancar

isidro requested to merge fix/ceo-web-secrets-from-1password into main

El problema

launchd cargaba ~/.config/cmoagent/web.env: 31 variables, 12 de ellas secretos en claro — Slack (signing secret + bot token), Resend, GitLab, Postiz, YouTube, Freepik, la contraseña del portal, el cookie secret y la URL de Postgres. En un fichero fuera de todo repo.

Ese fichero fue el cuarto vector de la auditoría de gasto del 2026-08-04: llevaba la master key de LiteLLM y, al no estar versionado ni escaneado, no aparecía en ningún barrido. Se descubrió solo cuando el proxy volvió a registrar 58 llamadas sin atribuir con los repos ya limpios.

La migración

Los 12 secretos ya existían en 1Password con refs en .env.tpl, y sus valores coincidían exactamente. La plantilla reusa esos mismos items: una sola fuente por secreto, sin duplicar nada.

  • deploy/web.env.tpl — plantilla versionada: secretos por referencia, config no sensible literal.
  • scripts/start-ceo-web.sh — resuelve con el service account (desatendido, sin Touch ID) y arranca. Si 1Password no responde, reutiliza el último .resolved: un fallo del gestor de secretos no debe tirar el portal.
  • El plist llama al script. web.env retirado.

Dos trampas, un arranque fallido cada una

  • op inject resuelve referencias incluso dentro de comentarios. La cabecera de la plantilla las llevaba en prosa y abortaba la resolución entera. El .env.tpl de este repo ya lo documentaba — no lo leí a tiempo.
  • op inject -o sobre un fichero que ya existe pide confirmación interactiva. Bajo launchd no hay TTY, así que fallaba en silencio. Ahora escribe a stdout.

Test plan

  • La plantilla resuelve a las mismas 31 claves con los mismos valores que el fichero que sustituye (comparación programática, cero diferencias)
  • launchctl kickstartentorno resuelto desde 1Password, proceso vivo
  • Portal en :8788 → HTTP 401 (auth activa, comportamiento correcto)
  • Arranque repetido tras retirar web.env → sigue funcionando
  • ps eww del proceso: sin la master key, con la VK de CMOAgent

Merge request reports