Secrets Store: el almacén centralizado de la cuenta
El Secrets Store de Cloudflare: un almacén de secretos a nivel de cuenta, su binding `secrets_store_secrets`, cómo un mismo secreto se reutiliza entre varios Workers, y por qué su acceso asíncrono con `.get()` centraliza la rotación y el gobierno.
Los secretos de wrangler secret put viven pegados a un Worker: cada Worker guarda su propia copia. Funciona de maravilla hasta que diez Workers necesitan la misma clave de un proveedor y descubres que tienes diez copias que rotar a mano, sin garantía de que no se te olvide una. El Secrets Store resuelve exactamente eso: eleva el secreto del Worker a la cuenta. Lo defines una vez, en un almacén central, y cualquier Worker lo referencia por un binding. Una fuente de verdad, un solo sitio donde rotar, un solo lugar donde auditar quién accede a qué.
- Situar el Secrets Store como almacén de secretos a nivel de cuenta, no de Worker.
- Declarar el binding
secrets_store_secretspara referenciar un secreto del almacén. - Leer el valor en el Worker con el acceso asíncrono
.get()del binding. - Entender qué gana un equipo al centralizar: rotación, reutilización y gobierno.
El problema: el mismo secreto en diez Workers
Un secreto por Worker es el modelo por defecto y el correcto cuando el valor es exclusivo de ese Worker. Pero las arquitecturas del edge tienden a fragmentarse en muchos Workers pequeños —uno por servicio, compuestos con service bindings— y muchos de ellos comparten credenciales: la misma clave de un proveedor de pagos, el mismo token de un servicio de correo, la misma cadena de conexión.
Con secretos por Worker, ese valor compartido se copia N veces. Cada copia es independiente: no hay ningún vínculo entre ellas. Cuando llega el día inevitable de rotar la clave —porque caducó o porque se filtró—, tienes que ejecutar wrangler secret put en los N Workers, y si te saltas uno, ese Worker sigue usando la credencial vieja hasta que algo se rompe en producción. La duplicación no es solo trabajo: es deriva, la certeza estadística de que tarde o temprano tus copias dejarán de coincidir.
Esta fragmentación no es un mal diseño que puedas evitar: es la forma natural del edge. Componer una aplicación como varios Workers pequeños comunicados por service bindings tiene ventajas reales de despliegue, aislamiento y escalado. Pero cada frontera que trazas entre Workers es una frontera que las credenciales compartidas tienen que cruzar, y multiplicar copias de un mismo secreto por diseño es sembrar el problema de la deriva desde el primer día.
La deriva, además, casi nunca se manifiesta de forma limpia. El Worker que quedó con la clave vieja no falla al desplegar ni al arrancar: falla más tarde, cuando llega la petición que usa esa credencial, con un error de autorización que parece venir del proveedor y no de tu configuración. Perseguir ese fallo hasta descubrir que una de diez copias no se rotó es exactamente el tipo de tarde perdida que la centralización elimina de raíz.
Nada de esto es exclusivo de los secretos: es el mismo argumento por el que no duplicas la lógica de negocio en diez copias pegadas. La credencial compartida es estado compartido, y el estado compartido quiere un único dueño. Verlo así conecta este nivel con un principio que reaparece en todo el track del edge.
Un secreto, muchos Workers
El Secrets Store invierte el modelo. Creas un almacén en la cuenta, guardas el secreto ahí una sola vez, y cada Worker que lo necesita no guarda una copia sino una referencia. Esa referencia se declara como un binding en wrangler.jsonc:
{
"name": "servicio-pagos",
"main": "src/index.ts",
"compatibility_date": "2026-01-01",
"secrets_store_secrets": [
{
"binding": "STRIPE_KEY",
"store_id": "a1b2c3d4e5f6",
"secret_name": "stripe-produccion"
}
]
}
El binding no lleva el valor: lleva las coordenadas del secreto en el almacén —el store_id y el secret_name—. Dos Workers distintos pueden apuntar al mismo secret_name del mismo almacén, y entonces comparten literalmente el mismo valor, no dos copias que casualmente coinciden. La gestión del almacén se hace por el panel de Cloudflare o con la familia de comandos wrangler secrets-store:
# Crea un almacen a nivel de cuenta
wrangler secrets-store store create mi-almacen
# Guarda un secreto dentro del almacen
wrangler secrets-store secret create <STORE_ID> --name stripe-produccion --scopes workers
# Lista los secretos del almacen (nombres, no valores)
wrangler secrets-store secret list <STORE_ID>
Organiza los almacenes y los nombres con la misma intención con que organizarías una base de datos. Un almacén por dominio de confianza —producción, un cliente concreto, un equipo— y nombres de secreto descriptivos y estables, porque ese secret_name es la clave por la que muchos Workers encontrarán el valor. Cambiar el nombre de un secreto compartido es como renombrar una columna de la que dependen diez consultas: se puede, pero se paga en cada consumidor.
Los secretos del almacén, además, pueden acotarse a los servicios que tienen derecho a usarlos, de modo que declarar un binding no basta para que cualquier Worker de la cuenta lea cualquier valor. Esa capa de alcance es justo lo que convierte un almacén compartido en algo distinto de una carpeta común: compartir no significa abrir a todos, sino compartir de forma gobernada con quien corresponde.
En proyectos grandes, esa gobernanza se vuelve tan importante como el propio valor: saber qué Workers dependen de un secreto es lo que te permite rotarlo con confianza, porque conoces de antemano a quién afecta el cambio. El almacén, al ser el punto por el que todos pasan, es también el inventario natural de esas dependencias.
El binding se lee distinto
Aquí hay una diferencia de API que no puedes pasar por alto. Un secreto de wrangler secret put aparece en env como una cadena ya resuelta. Un secreto del Secrets Store aparece como un binding con un método get() asíncrono: no es el valor, es un handle desde el que pides el valor.
export default {
async fetch(request, env) {
// el binding NO es una cadena: es un handle que se resuelve async
const stripeKey = await env.STRIPE_KEY.get();
const cobro = await fetch("https://api.stripe.com/v1/charges", {
method: "POST",
headers: { authorization: `Bearer ${stripeKey}` },
});
return new Response("ok");
},
} satisfies ExportedHandler<Env>;
Ese await ... .get() no es un capricho de la API: refleja que el valor se resuelve contra el almacén de la cuenta y que el acceso es un punto donde Cloudflare puede aplicar control y registro. Léelo solo cuando lo necesites, en el servidor, y no lo guardes en un ámbito que sobreviva a la petición.
Ese acceso asíncrono tiene además una implicación de rendimiento menor pero real: resolver el secreto es una operación, no la lectura de un campo ya presente. En la práctica es rápida y se resuelve dentro de la invocación, pero es una razón más para pedirlo una vez y reutilizar el resultado en lugar de llamar a get() en cada punto que lo necesita.
En la práctica, resuelve el secreto una sola vez por invocación, en el punto donde lo necesitas, y pásalo hacia abajo como argumento si varias funciones lo requieren. No lo guardes en una variable de módulo que sobreviva entre peticiones ni lo registres para depurar: un secreto del almacén central, si se filtra, no compromete un Worker sino todos los que lo comparten, así que el cuidado al manejarlo debe ser proporcional a ese alcance mayor.
El Secrets Store no sustituye a wrangler secret put: lo complementa. La regla práctica es de propiedad. Si un secreto pertenece a un solo Worker y nadie más lo usará, un secreto por Worker es más simple y basta. Si un secreto lo comparten dos o más Workers, o prevés que lo harán, vive en el Secrets Store desde el principio: el coste de centralizarlo tarde —encontrar todas las copias y unificarlas sin romper nada— siempre es mayor que el de hacerlo bien de entrada.
Una consecuencia agradable de esta regla es que centralizar temprano casi nunca se lamenta, mientras que centralizar tarde casi siempre duele. Si dudas, el sesgo correcto es hacia el almacén: el coste de una indirección asíncrona de más es trivial comparado con el de una copia olvidada que nadie recuerda rotar.
flowchart TD STORE[secrets store de la cuenta] --> W1[worker de pagos] STORE --> W2[worker de facturas] STORE --> W3[worker de correo] ROT[rotar una vez en el almacen] --> STORE style STORE fill:#cba6f7,color:#11111b style ROT fill:#a6e3a1,color:#11111b
Gobierno: una llave, muchas cerraduras
El verdadero producto del Secrets Store no es el ahorro de teclear el secreto varias veces, sino el gobierno que habilita. Cuando un valor sensible vive en un punto único de la cuenta, alrededor de ese punto pueden existir controles que serían imposibles sobre diez copias dispersas.
Fuente única de verdad
Un solo valor canónico. Los Workers no lo tienen: lo referencian. Desaparece la pregunta de cuál de las copias es la buena.
Rotación en un sitio
Cambias el valor una vez en el almacén y todos los consumidores lo ven. La rotación deja de ser una campaña y pasa a ser una escritura.
Control de acceso
Permisos a nivel de cuenta sobre quién lee o modifica cada secreto, en vez de esparcidos por la configuración de cada Worker.
Auditoría
Un punto único donde registrar quién accedió a qué y cuándo. La trazabilidad es viable porque el acceso pasa siempre por el mismo sitio.
Nada de esto significa que todo secreto deba ir al almacén central. Un Worker único con una credencial que solo él usará no gana nada centralizándola y añade una indirección asíncrona que no necesita. La heurística es la misma que gobierna cualquier decisión sobre estado compartido: centraliza lo que de verdad se comparte, mantén local lo que es local, y no pagues el coste de la coordinación cuando no hay nada que coordinar.
El día que un secreto por Worker se convierta en compartido, la migración es mecánica pero requiere orden: crea el secreto en el almacén, añade el binding secrets_store_secrets a cada Worker consumidor, cambia el código de leer env.X a await env.X.get(), despliega, verifica, y solo entonces elimina las copias antiguas con wrangler secret delete. Borrar las copias antes de tiempo deja Workers sin credencial; no borrarlas nunca deja secretos huérfanos que alguien tendrá que rotar a ciegas.
Lo que el Secrets Store enseña, más allá de su mecánica, es que la seguridad y la operabilidad de un sistema no se juegan solo en la fuerza de un cifrado sino en la topología de la información. Un mismo secreto copiado en diez sitios no es diez veces más seguro: es diez veces más frágil, porque la superficie que debes proteger, rotar y auditar se multiplica, y porque introduces la posibilidad de que las copias diverjan, que es una clase de fallo que no existía cuando había una sola. Centralizar el secreto en un almacén de cuenta convierte tres problemas operativos en uno. La rotación deja de ser una campaña coordinada entre Workers y pasa a ser una escritura única que todos ven al instante. La reutilización deja de significar duplicación y pasa a significar referencia: los Workers no tienen el secreto, apuntan a él. Y el gobierno —quién puede leer o modificar qué credencial— deja de estar disperso en la configuración de cada Worker y se concentra donde puede existir un control de acceso y un registro de auditoría reales, a nivel de cuenta. La lección profunda es que cuando un dato es compartido, su lugar correcto no es dentro de cada consumidor sino en un punto único al que todos apuntan; lo contrario, copiar el estado compartido, es la misma raíz de la que brotan las incoherencias de caché, las réplicas desincronizadas y los secretos que nadie recuerda haber olvidado rotar.
- Crea un almacén con
wrangler secrets-store store createy guarda en él un secreto de prueba con un nombre claro. - Declara el binding
secrets_store_secretsen dos Workers distintos apuntando al mismosecret_name, y léelo en ambos conawait env.BINDING.get(). - Rota el valor una sola vez en el almacén y comprueba que ambos Workers reciben el nuevo valor sin que toques su configuración.
- Escribe una regla para tu equipo: ¿qué criterio decide si un secreto nuevo va al almacén central o se queda como secreto por Worker? Defiéndela en dos frases.
- Simula la deriva: crea el mismo secreto como copia por Worker en dos Workers, cambia solo una de las copias, y observa el fallo tardío de autorización en el Worker que no rotaste. Luego resuélvelo migrando ambos al almacén.