Usa este inventario para decidir qué valores pertenecen al entorno de runtime, cuáles se generan en la base de datos y cuáles almacenan los plugins. Cada sección indica cómo la rotación afecta a un sitio en ejecución.
En Node.js, coloca los secretos de runtime en el gestor de secretos de la plataforma de hosting para que entren en process.env al arrancar el proceso. Para un Worker, usa wrangler secret put. No pongas valores secretos en astro.config.mjs, wrangler.jsonc ni import.meta.env; Vite puede incrustar valores de tiempo de build en el bundle del servidor.
Resumen
| Secreto | Origen | Almacenado en | Impacto si se pierde la clave |
|---|---|---|---|
EMDASH_ENCRYPTION_KEY | Operador (emdash secrets generate) | Solo entorno / secreto de Worker | Los ajustes cifrados del plugin no se pueden leer hasta restaurar la clave coincidente |
| Secreto de preview | Autogenerado (override de env) | Tabla options (emdash:preview_secret) | Los enlaces de preview pendientes dejan de funcionar; los nuevos están bien |
| Sal de IP | Autogenerado (override de env) | Tabla options (emdash:ip_salt) | La continuidad del rate-limit de comentarios se reinicia |
| Tokens de sesión y API | Generados por sesión/token | Almacén de sesión / base de datos (solo hashes) | Nada — el texto plano nunca se almacena |
| Credenciales de proveedor OAuth | Tú (consola Google/GitHub) | Entorno | El inicio de sesión por ese proveedor se detiene hasta reemplazarlo |
| Secreto de Turnstile | Tú (panel de Cloudflare) | Entorno | La verificación CAPTCHA de comentarios falla |
| Credenciales S3 | Tú (proveedor de almacenamiento) | Entorno de runtime | La subida/descarga de medios falla hasta reemplazarlas |
| Secretos de plugin | Tú (UI de ajustes del admin) | Ajuste cifrado en la base de datos | Restaura la clave de cifrado coincidente o vuelve a introducir el valor |
| Credenciales de CLI | Flujos de dispositivo emdash login / emdash plugin publish | ~/.config/emdash/auth.json (modo 0600) | Ejecuta el flujo de dispositivo de nuevo |
| Credenciales de CLI del registro | OAuth atproto de emdash-plugin | ~/.emdash/oauth/, ~/.emdash/credentials.json (modo 0600) | Vuelve a iniciar sesión; la identidad vive en tu PDS |
La clave de cifrado
EMDASH_ENCRYPTION_KEY cifra los ajustes de plugin declarados con type: "secret". EmDash usa AES-GCM con el ID del plugin y la clave del ajuste como datos autenticados. Un valor malformado produce un mensaje de arranque orientado al operador, y las operaciones que necesitan ajustes cifrados del plugin fallan en cerrado. Las peticiones del sitio no relacionadas siguen funcionando.
El siguiente comando genera un valor con el formato correcto. Guárdalo en el entorno de runtime o como secreto de Worker si tu despliegue usa esta variable.
npx emdash secrets generate
# emdash_enc_v1_<43 base64url chars>
# Cloudflare:
wrangler secret put EMDASH_ENCRYPTION_KEY
El formato es emdash_enc_v1_ seguido de 32 bytes aleatorios como base64url sin relleno. El valor lo proporciona el operador y no se almacena en la base de datos. Guárdalo en un gestor de secretos y en una copia de recuperación separada.
Para rotar la clave, antepone un valor nuevo y conserva el valor antiguo tras una coma:
EMDASH_ENCRYPTION_KEY=emdash_enc_v1_<new-key>,emdash_enc_v1_<old-key>
EmDash cifra los valores nuevos y vueltos a guardar con la primera clave. Usa la huella kid almacenada para seleccionar una clave más antigua en lecturas. Vuelve a guardar cada secreto de plugin antes de quitar la clave antigua, y verifica esas integraciones desde un despliegue que contenga solo la clave nueva. EmDash no informa actualmente qué IDs de clave siguen en uso, así que mantén un inventario de las credenciales que vuelves a guardar y no quites una clave antigua hasta que cada integración haya pasado esa verificación.
Secretos de sitio generados
Dos secretos se generan automáticamente en el primer uso y se persisten en la tabla options, de modo que son estables entre peticiones, despliegues e isolates. La generación es atómica: arranques en frío concurrentes convergen en un valor.
Secreto de preview
Firma URLs de preview (HMAC). Almacenado como emdash:preview_secret; 32 bytes aleatorios, base64url.
- Override: establece
EMDASH_PREVIEW_SECRET(alias legado:PREVIEW_SECRET) si necesitas el mismo secreto en varios procesos o quieres fijarlo por auditoría. El entorno siempre gana sobre el valor almacenado. - Rotación: elimina la fila
emdash:preview_secret(o cambia la variable de entorno) y vuelve a desplegar. Impacto: los enlaces de preview emitidos antes dejan de validar. Nada más se rompe: se genera un secreto nuevo (o se lee del entorno) en la siguiente petición de preview. - Si se pierde: nada es irrecuperable. Los enlaces de preview son de corta duración por diseño.
Consulta la guía de preview sobre cómo se construyen y verifican las URLs de preview.
Sal de IP
Salsa el hash SHA-256 de las direcciones IP de comentaristas (ip_hash en comentarios) usado para el rate-limit de comentarios. Almacenado como emdash:ip_salt. Específico del sitio, de modo que los hashes no son correlacionables entre instalaciones de EmDash.
- Override: establece
EMDASH_IP_SALT. Por compatibilidad hacia atrás, también se consultanEMDASH_AUTH_SECRET/AUTH_SECRET: las instalaciones que históricamente derivaban la sal de ellos mantienen hashes estables. - Rotación: cambia la variable de entorno o elimina la fila
emdash:ip_salt. Impacto: los nuevos envíos de comentarios hacen hash a valores distintos, así que el conteo del rate-limit reinicia para todos. Los comentarios existentes y sus hashes almacenados no se tocan. - Si se pierde: no hay pérdida de datos. Solo se reinicia la continuidad del rate-limit.
Tokens de sesión y API
- Sesiones usan el almacén de sesión 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 vacía el almacén de sesión (p. ej. el namespace KV) para forzar a todos a iniciar sesión de nuevo.
- Tokens de API (prefijos
ec_pat_,ec_oat_,ec_ort_) son valores aleatorios opacos de 256 bits; solo se almacena su hash SHA-256. El texto plano se muestra una vez al crearlo. Rota revocando y volviendo a crear en el admin. - Tokens de invitación, magic-link y recuperación son de un solo propósito, almacenados como hashes SHA-256 en
auth_tokens, y con límite de tiempo (invitaciones 7 días, magic links 15 minutos).
No hay nada que respaldar ni rotar de forma proactiva: una filtración de la base de datos solo expone hashes, y cada token se puede revocar o reemitir desde el admin.
Credenciales de servicio proporcionadas por el usuario
Las credenciales de servicios externos se leen del entorno y nunca se escriben en la base de datos. Rótalas en el proveedor, actualiza la variable, vuelve a desplegar.
| Servicio | Variables |
|---|---|
| Inicio de sesión con Google | EMDASH_OAUTH_GOOGLE_CLIENT_ID, EMDASH_OAUTH_GOOGLE_CLIENT_SECRET (o alias sin prefijo) |
| Inicio de sesión con GitHub | EMDASH_OAUTH_GITHUB_CLIENT_ID, EMDASH_OAUTH_GITHUB_CLIENT_SECRET (o alias sin prefijo) |
| Publicación en Marketplace (CI) | EMDASH_MARKETPLACE_TOKEN |
| Turnstile (comentarios) | EMDASH_TURNSTILE_SECRET_KEY (o TURNSTILE_SECRET_KEY) |
| Almacenamiento compatible con S3 | S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_ENDPOINT, S3_BUCKET, S3_REGION |
En Cloudflare, configúralas con wrangler secret put; para desarrollo local, ponlas en .env. Wrangler lee .dev.vars o .env, no ambos, y .dev.vars tiene prioridad cuando está presente. R2 mediante un binding no necesita variables de access key porque el binding concede acceso en runtime. Consulta almacenamiento de medios.
Secretos de plugin
Los ajustes que un plugin declara con type: "secret" (claves API para proveedores de correo, CAPTCHAs de formularios, etc.) se introducen en la UI del admin y se cifran en la tabla options bajo plugin:<id>:settings:<key>. El admin solo recibe si un secreto está establecido, incluso cuando la clave de cifrado coincidente no está disponible, de modo que un administrador puede reemplazar una credencial ilegible. El código del plugin lee el texto plano mediante ctx.settings dentro de su runtime aislado. Los valores almacenados fuera de un esquema de ajustes declarado, incluidas entradas arbitrarias de KV y estado del plugin, no usan esta ruta de cifrado.
- Rotación de credenciales: rota la credencial en el proveedor y pega el valor nuevo en la página de ajustes del plugin. El guardado escribe un nuevo sobre cifrado.
- Migración de texto plano: los secretos almacenados por una versión anterior de EmDash siguen siendo legibles. Guarda cada valor de nuevo para cifrarlo.
- Si se pierde la clave de cifrado: restaura el
EMDASH_ENCRYPTION_KEYcoincidente desde la copia de seguridad separada de la clave. Si no existe ninguna copia, reemplaza cada credencial afectada en su proveedor e introduce los reemplazos tras configurar una nueva clave de cifrado.
Credenciales de CLI
La CLI emdash guarda dos tipos de credenciales, ambas en ~/.config/emdash/auth.json (respetando XDG_CONFIG_HOME), creadas con permisos solo del propietario (0600):
- Tokens de sitio —
emdash loginautentica contra tu instancia de EmDash mediante un flujo de dispositivo OAuth y almacena el token resultante indexado por URL de instancia.emdash logoutlo elimina; por invocación,--tokenoEMDASH_TOKENanulan el token almacenado. - Tokens de Marketplace —
emdash plugin publishautentica en el EmDash Marketplace mediante un flujo de dispositivo de GitHub y almacena el JWT resultante indexado pormarketplace:<origin>. Para publicación en CI, estableceEMDASH_MARKETPLACE_TOKENen su lugar: tiene prioridad sobre la credencial almacenada.
Perder el archivo es inocuo: ejecuta emdash login (o emdash plugin publish, que vuelve a ejecutar el flujo de dispositivo) de nuevo.
Credenciales de CLI del registro de plugins
La CLI separada emdash-plugin (paquete @emdash-cms/plugin-cli) apunta al registro AT Protocol experimental. Publicar allí está ligado a tu identidad AT Protocol (tu DID de publisher): el sitio en sí no guarda credenciales de publicación, y las instalaciones verifican artefactos frente a sumas de verificación de registros de release atribuidos a ese DID.
- Se autentica mediante OAuth atproto. Los blobs de sesión/estado OAuth viven en
~/.emdash/oauth/, y la identidad del publisher (DID, handle, PDS) se almacena en caché en~/.emdash/credentials.json; ambos se escriben con permisos solo del propietario. - En CI, proporciona la identidad mediante
EMDASH_PUBLISHER_DID,EMDASH_PUBLISHER_HANDLEyEMDASH_PUBLISHER_PDS;EMDASH_REGISTRY_URLanula el host del registro. Elpublishautomatizado desde CI sigue necesitando los archivos de sesión OAuth en~/.emdash/oauth/en el runner: las variables de entorno solas no llevan la sesión OAuth. - Rotar o revocar el acceso de publicación ocurre en tu cuenta AT Protocol (p. ej. contraseñas de app), no en EmDash. Consulta autenticación Atmosphere.
Referencia rápida de rotación
| Quiero… | Haz esto |
|---|---|
| Rotar el cifrado de ajustes de plugin | Anteponer la clave nueva, volver a guardar secretos de plugin, luego quitar la clave antigua |
| Invalidar todos los enlaces de preview | Eliminar la fila de opción emdash:preview_secret (o cambiar el override de env) |
| Reiniciar el hashing del rate-limit de comentarios | Cambiar EMDASH_IP_SALT (o eliminar la fila de opción emdash:ip_salt) |
| Revocar un token de API filtrado | Admin → Users → API tokens → revocar, luego crear un reemplazo |
| Matar todas las sesiones | Vaciar el almacén de sesión (namespace KV de Workers / directorio de sesión) |
| Reemplazar una credencial de proveedor | Rotar en el proveedor, actualizar la variable de entorno, volver a desplegar |
| Reemplazar una clave API de plugin | Rotar en el proveedor, volver a introducir en los ajustes de admin del plugin |