Secretos y gestión de claves

En esta página

EmDash utiliza un pequeño conjunto de secretos para vistas previas, comentarios, autenticación, almacenamiento y plugins. Esta página es el inventario completo: de dónde viene cada secreto, dónde se almacena, cómo rotarlo y qué se rompe si se pierde.

Visión general

SecretoFuenteAlmacenado enImpacto de pérdida
EMDASH_ENCRYPTION_KEYOperador (emdash secrets generate)Solo entorno / secreto WorkerLos secretos de plugins cifrados se vuelven irrecuperables (cuando se lance el cifrado en reposo)
Secreto de vista previaAuto-generado (override de env)Tabla options (emdash:preview_secret)Los enlaces de vista previa existentes dejan de funcionar; los nuevos están bien
Salt de IPAuto-generado (override de env)Tabla options (emdash:ip_salt)La continuidad del rate-limit de comentarios se reinicia
Tokens de sesión y APIGenerados por sesión/tokenAlmacén de sesiones / BD (solo hashes)Nada — el texto plano nunca se almacena
Credenciales de proveedor OAuthTú (consola de Google/GitHub)EntornoEl inicio de sesión vía ese proveedor se detiene hasta reemplazarlo
Secreto de TurnstileTú (panel de Cloudflare)EntornoLa verificación CAPTCHA de comentarios falla
Credenciales S3Tú (proveedor de almacenamiento)Entorno o configuraciónLa carga/descarga de medios falla hasta reemplazarlo
Secretos de pluginsTú (UI de configuración de admin)Base de datos (configuración / almacenamiento de plugins)Re-ingresar en el admin
Credenciales CLIFlujos de dispositivo emdash login / emdash plugin publish~/.config/emdash/auth.json (modo 0600)Ejecutar el flujo de dispositivo de nuevo
Credenciales CLI del registroemdash-plugin atproto OAuth~/.emdash/oauth/, ~/.emdash/credentials.json (modo 0600)Iniciar sesión de nuevo; la identidad vive en tu PDS

La clave de cifrado

EMDASH_ENCRYPTION_KEY es la clave del sitio para cifrar secretos de plugins en reposo. Es proporcionada por el operador y nunca almacenada en la base de datos — la base de datos solo contiene texto cifrado, por lo que una fuga de backup no expone la clave.

Genera una y configúrala como variable de entorno (o secreto Worker):

npx emdash secrets generate
# emdash_enc_v1_<43 caracteres base64url>

# Cloudflare:
wrangler secret put EMDASH_ENCRYPTION_KEY

El formato es emdash_enc_v1_ seguido de 32 bytes aleatorios como base64url sin relleno. La clave se valida al iniciar el runtime; un valor malformado registra un error orientado al operador sin interrumpir las rutas de solicitud.

Rotación

La variable acepta una lista separada por comas de claves. La primera entrada es la primaria y se usa para nuevas escrituras; todas las entradas se intentan para descifrado. Cada valor cifrado está etiquetado con una huella digital de clave de 8 caracteres (el kid, imprimible vía emdash secrets fingerprint <key>), por lo que el runtime selecciona la clave correcta automáticamente.

Para rotar: genera una nueva clave, anteponla a la lista (EMDASH_ENCRYPTION_KEY="nueva,antigua"), redespliega y elimina la antigua una vez que los valores existentes hayan sido re-cifrados.

Secretos de sitio generados

Dos secretos se generan automáticamente en el primer uso y se persisten en la tabla options, por lo que son estables entre solicitudes, despliegues y aislamientos. La generación es atómica — arranques en frío concurrentes convergen en un valor.

Secreto de vista previa

Firma URLs de vista previa (HMAC). Almacenado como emdash:preview_secret; 32 bytes aleatorios, base64url.

  • Override: configura EMDASH_PREVIEW_SECRET (alias heredado: PREVIEW_SECRET) si necesitas el mismo secreto en múltiples procesos o quieres fijarlo por razones de auditoría. El entorno siempre gana sobre el valor almacenado.
  • Rotación: elimina la fila emdash:preview_secret (o cambia la variable de env) y redespliega. Impacto: los enlaces de vista previa emitidos previamente dejan de validar. Nada más se rompe — un secreto fresco se genera (o lee del env) en la siguiente solicitud de vista previa.
  • Si se pierde: nada es irrecuperable. Los enlaces de vista previa son efímeros por diseño.

Consulta la guía de vistas previas para cómo se construyen y verifican las URLs de vista previa.

Salt de IP

Sala el hash SHA-256 de las direcciones IP de los comentaristas (ip_hash en comentarios) usado para la limitación de tasa de comentarios. Almacenado como emdash:ip_salt. Específico del sitio, por lo que los hashes no son correlacionables entre instalaciones de EmDash.

  • Override: configura EMDASH_IP_SALT. Por compatibilidad retroactiva, también se consultan EMDASH_AUTH_SECRET / AUTH_SECRET — las instalaciones que históricamente derivaron el salt de estos mantienen hashes estables.
  • Rotación: cambia la variable de env o elimina la fila emdash:ip_salt. Impacto: los nuevos envíos de comentarios generan valores hash diferentes, así que el conteo de rate-limit se reinicia para todos. Los comentarios existentes y sus hashes almacenados no se tocan.
  • Si se pierde: sin pérdida de datos. Solo se reinicia la continuidad del rate-limit.

Tokens de sesión y API

  • Sesiones usan el almacén de sesiones de Astro (Workers KV en Cloudflare, sistema de archivos en Node). La cookie lleva un ID de sesión opaco; no hay secreto de firma que gestionar. Cierra sesión para terminar una sesión, o limpia el almacén de sesiones (ej. el namespace KV) para forzar a todos a iniciar sesión de nuevo.
  • Tokens API (prefijos ec_pat_, ec_oat_, ec_ort_) son valores aleatorios opacos de 256 bits; solo su hash SHA-256 se almacena. El texto plano se muestra una vez en la creación. Rotar revocando y recreando en el admin.
  • Tokens de invitación, magic-link y recuperación son de propósito único, almacenados como hashes SHA-256 en auth_tokens, y con tiempo limitado (invitaciones 7 días, magic links 15 minutos).

No hay nada que respaldar o rotar proactivamente: una fuga de base de datos expone solo hashes, y cada token puede ser revocado o reemitido desde el admin.

Credenciales de servicio proporcionadas por el usuario

Las credenciales para servicios externos se leen del entorno y nunca se escriben en la base de datos. Rótalas en el proveedor, actualiza la variable, redespliega.

ServicioVariables
Inicio de sesión GoogleEMDASH_OAUTH_GOOGLE_CLIENT_ID, EMDASH_OAUTH_GOOGLE_CLIENT_SECRET (o alias sin prefijo)
Inicio de sesión GitHubEMDASH_OAUTH_GITHUB_CLIENT_ID, EMDASH_OAUTH_GITHUB_CLIENT_SECRET (o alias sin prefijo)
Publicación Marketplace (CI)EMDASH_MARKETPLACE_TOKEN
Turnstile (comentarios)EMDASH_TURNSTILE_SECRET_KEY (o TURNSTILE_SECRET_KEY)
Almacenamiento compatible S3S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_ENDPOINT, S3_BUCKET, S3_REGION

En Cloudflare, configúralas con wrangler secret put; localmente, ponlas en .env. R2 vía binding no necesita credenciales — el acceso se otorga por el binding en wrangler.jsonc, que es la configuración recomendada en Workers. Consulta opciones de almacenamiento.

Secretos de plugins

Las configuraciones que un plugin declara con type: "secret" (claves API para proveedores de email, CAPTCHAs de formularios, etc.) se ingresan en la UI de admin y se almacenan en la base de datos — en la tabla options bajo plugin:<id>:settings:<key>, o en el almacenamiento key-value del plugin. Si un secreto almacenado se devuelve a la UI de admin depende del plugin; los plugins bien escritos devuelven solo un indicador “valor configurado” en lugar del secreto en sí (el plugin de formularios incluido hace esto).

  • Rotación: rota la clave en el proveedor y pega el nuevo valor en la página de configuración del plugin. Toma efecto inmediatamente.
  • Si se pierde: re-ingresa el valor en el admin. Nada más depende de él.

Credenciales CLI

La CLI emdash mantiene dos tipos de credenciales, ambas en ~/.config/emdash/auth.json (respetando XDG_CONFIG_HOME), creadas con permisos solo del propietario (0600):

  • Tokens de sitioemdash login se autentica contra tu instancia EmDash vía un flujo de dispositivo OAuth y almacena el token resultante indexado por URL de instancia. emdash logout lo elimina; por invocación, --token o EMDASH_TOKEN sobrescribe el token almacenado.
  • Tokens de Marketplaceemdash plugin publish se autentica en el EmDash Marketplace vía un flujo de dispositivo GitHub y almacena el JWT resultante indexado como marketplace:<origin>. Para publicación en CI, configura EMDASH_MARKETPLACE_TOKEN en su lugar — tiene prioridad sobre la credencial almacenada.

Perder el archivo es inofensivo: ejecuta emdash login (o emdash plugin publish, que re-ejecuta el flujo de dispositivo) de nuevo.

Credenciales CLI del registro de plugins

La CLI separada emdash-plugin (paquete @emdash-cms/plugin-cli) apunta al registro experimental del AT Protocol. La publicación allí está vinculada a tu identidad AT Protocol (tu DID de publicador) — el sitio en sí no contiene credenciales de publicación, y las instalaciones verifican artefactos contra checksums de registros de release atribuidos a ese DID.

  • Se autentica vía atproto OAuth. Los blobs de sesión/estado OAuth viven en ~/.emdash/oauth/, y la identidad del publicador (DID, handle, PDS) se cachea en ~/.emdash/credentials.json; ambos se escriben con permisos solo del propietario.
  • En CI, proporciona la identidad vía EMDASH_PUBLISHER_DID, EMDASH_PUBLISHER_HANDLE y EMDASH_PUBLISHER_PDS; EMDASH_REGISTRY_URL sobrescribe el host del registro. El publish automatizado desde CI aún necesita los archivos de sesión OAuth en ~/.emdash/oauth/ en el runner — las variables de env por sí solas no transportan la sesión OAuth.
  • Rotar o revocar el acceso de publicación ocurre en tu cuenta AT Protocol (ej. contraseñas de aplicación), no en EmDash. Consulta Atmosphere auth.

Referencia rápida de rotación

Quiero…Hacer esto
Rotar la clave de cifradoAnteponer nueva clave: EMDASH_ENCRYPTION_KEY="nueva,antigua", redesplegar, eliminar antigua después
Invalidar todos los enlaces de vista previaEliminar la fila de opción emdash:preview_secret (o cambiar el override de env)
Reiniciar hashing de rate-limit de comentariosCambiar EMDASH_IP_SALT (o eliminar la fila de opción emdash:ip_salt)
Revocar un token API filtradoAdmin → Usuarios → Tokens API → revocar, luego crear reemplazo
Terminar todas las sesionesLimpiar el almacén de sesiones (namespace Workers KV / directorio de sesiones)
Reemplazar una credencial de proveedorRotar en el proveedor, actualizar variable de env, redesplegar
Reemplazar una clave API de pluginRotar en el proveedor, re-ingresar en la configuración admin del plugin