Gestionar secretos y claves

En esta página

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

SecretoOrigenAlmacenado enImpacto si se pierde la clave
EMDASH_ENCRYPTION_KEYOperador (emdash secrets generate)Solo entorno / secreto de WorkerLos ajustes cifrados del plugin no se pueden leer hasta restaurar la clave coincidente
Secreto de previewAutogenerado (override de env)Tabla options (emdash:preview_secret)Los enlaces de preview pendientes dejan de funcionar; los nuevos están bien
Sal de IPAutogenerado (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 sesión / base de datos (solo hashes)Nada — el texto plano nunca se almacena
Credenciales de proveedor OAuthTú (consola Google/GitHub)EntornoEl inicio de sesión por 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 de runtimeLa subida/descarga de medios falla hasta reemplazarlas
Secretos de pluginTú (UI de ajustes del admin)Ajuste cifrado en la base de datosRestaura la clave de cifrado coincidente o vuelve a introducir el valor
Credenciales de CLIFlujos de dispositivo emdash login / emdash plugin publish~/.config/emdash/auth.json (modo 0600)Ejecuta el flujo de dispositivo de nuevo
Credenciales de CLI del registroOAuth 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 consultan EMDASH_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.

ServicioVariables
Inicio de sesión con GoogleEMDASH_OAUTH_GOOGLE_CLIENT_ID, EMDASH_OAUTH_GOOGLE_CLIENT_SECRET (o alias sin prefijo)
Inicio de sesión con GitHubEMDASH_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 S3S3_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_KEY coincidente 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 login autentica contra tu instancia de EmDash mediante 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 anulan el token almacenado.
  • Tokens de Marketplace — emdash plugin publish autentica en el EmDash Marketplace mediante un flujo de dispositivo de GitHub y almacena el JWT resultante indexado por marketplace:<origin>. Para publicación en CI, establece EMDASH_MARKETPLACE_TOKEN en 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_HANDLE y EMDASH_PUBLISHER_PDS; EMDASH_REGISTRY_URL anula el host del registro. El publish automatizado 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 pluginAnteponer la clave nueva, volver a guardar secretos de plugin, luego quitar la clave antigua
Invalidar todos los enlaces de previewEliminar la fila de opción emdash:preview_secret (o cambiar el override de env)
Reiniciar el hashing del rate-limit de comentariosCambiar EMDASH_IP_SALT (o eliminar la fila de opción emdash:ip_salt)
Revocar un token de API filtradoAdmin → Users → API tokens → revocar, luego crear un reemplazo
Matar todas las sesionesVaciar el almacén de sesión (namespace KV de Workers / directorio de sesión)
Reemplazar una credencial de proveedorRotar en el proveedor, actualizar la variable de entorno, volver a desplegar
Reemplazar una clave API de pluginRotar en el proveedor, volver a introducir en los ajustes de admin del plugin