← Blog ·

Secretos en serverless: Lambda, Vercel Functions y el problema del arranque en frío

La gestión de secretos en serverless debería ser sencilla: sin servidores que parchear, sin procesos de larga duración que comprometer. En la práctica, las funciones Lambda y las Vercel Functions hacen que los secretos sean más difíciles de gestionar bien, no menos — sobre todo por cómo arrancan los entornos de ejecución.

Por qué serverless complica los secretos

Un servidor tradicional arranca una vez y mantiene un secreto en memoria (o lo pide a un vault) durante días. Una función Lambda o Vercel puede arrancar decenas o cientos de veces por hora, cada arranque en frío partiendo de cero. Cada cold start es una decisión: ¿de dónde saco este secreto y cuánta latencia estoy dispuesto a añadir para conseguirlo?

La mayoría de equipos lo resuelve horneando los secretos en variables de entorno en el momento del despliegue. Es rápido — cero latencia añadida — pero significa que tu STRIPE_SECRET_KEY está en texto plano en la consola de Lambda, en tu estado de CloudFormation/Terraform, o en el dashboard de Vercel, visible para cualquiera con acceso al proyecto y a menudo registrado por sistemas de CI que imprimen diffs de entorno.

El problema del arranque en frío, en concreto

Si no quieres secretos en variables de entorno en texto plano, la alternativa estándar es llamar a AWS Secrets Manager o SSM Parameter Store (o la integración de Vercel con un vault) desde dentro del handler. Funciona, pero:

  • Secrets Manager: añade normalmente entre decenas y varios cientos de milisegundos por llamada, y es un coste por invocación si no cacheas entre ejecuciones.
  • Parameter Store: más barato, pero sigue añadiendo un round trip de red en cada arranque en frío.
  • Ambos requieren permisos IAM bien acotados por función, lo cual es en sí mismo una fuente recurrente de errores de configuración.

La solución habitual — pedir el secreto una vez y cachearlo en una variable a nivel de módulo, reutilizándola en invocaciones calientes — ayuda, pero significa que cada cold start sigue pagando el coste de latencia, y el secreto sigue viviendo descifrado en la memoria de la función durante toda la vida del contenedor.

Dónde se filtran realmente los secretos en serverless hoy

Esta es la parte que los equipos subestiman. La filtración normalmente no es un ataque sofisticado — es:

  • Un secreto pegado directamente en la consola de Vercel o AWS, compartido después en pantalla, exportado, o dejado en el historial de shell de un compañero.
  • Un asistente de IA leyendo tu archivo .env para "ayudarte a depurar la integración" y devolviendo el valor en un log de chat o en un archivo generado que acaba commiteado.
  • Un .env.local que termina en una capa de imagen Docker o en un zip de despliegue de Lambda.
  • Logs de CI que imprimen el entorno completo cuando falla un build.

Si estás generando handlers serverless con un asistente de IA, este riesgo se agrava: el asistente hardcodeará alegremente una clave que encontró en tu .env "solo para que funcione", y la revisión de código a menudo no lo detecta porque parece configuración normal. Hemos escrito más sobre este patrón en exposición de secretos en la era de la IA — es el fallo más común que vemos hoy en código generado por IA.

Las soluciones habituales, y sus contrapartidas

  • Variables de entorno: lo más rápido y simple, la peor postura de seguridad. Bien para configuración no sensible, arriesgado para API keys.
  • AWS Secrets Manager / SSM: mejor postura de seguridad, coste real de latencia, y el secreto sigue descifrándose a texto plano en la memoria de la función.
  • HashiCorp Vault: potente, pero operar un clúster de Vault para un puñado de funciones Lambda suele ser más infraestructura de la que el problema justifica.
  • Variables de entorno cifradas (envueltas con KMS): resuelve la exposición en reposo en la consola, pero sigues necesitando la llamada de descifrado en el arranque en frío, y la política de la clave KMS pasa a ser lo nuevo que hay que configurar bien.

Ninguna de estas soluciones arregla la fuga por el lado humano: una clave que estaba bien en AWS Secrets Manager puede acabar igualmente hardcodeada por un asistente de IA, commiteada a un repo, o pegada en un ticket de soporte.

Qué cambia Koove — y qué no

El modelo de Koove es cifrado por sobres (envelope encryption): los secretos se cifran del lado del cliente con X25519 + AES-256-GCM antes de llegar a nuestros servidores, así que solo almacenamos ciphertext. El flujo empieza igual sea cual sea el runtime:

koove set STRIPE_SECRET_KEY sk_live_xxx --env prod
koove set DATABASE_URL postgres://usuario:pass@host/db --env prod
koove list --env prod

Tu código — y tu asistente de IA — solo necesita referenciar STRIPE_SECRET_KEY por nombre, sin pegar nunca su valor en un archivo, un chat o una consola. Solo eso elimina el vector de fuga más común que vemos en código serverless: la clave hardcodeada sugerida por IA.

Donde importa la honestidad: el camino de descifrado atestiguado y totalmente documentado de Koove hoy es el SDK móvil — los secretos se descifran en un dispositivo verificado con Apple App Attest o Google Play Integrity más biometría. Es una garantía fuerte, pero es una garantía para consumidores móviles, no un layer de Lambda listo para instalar. Las primitivas open source de @koove/crypto (generateIdentityKeyPair, encryptSecret, decryptSecret, addRecipient, sealKey/openKey) están disponibles para construir tu propio camino de descifrado en backend para consumidores del lado del servidor ("backends autorizados" en nuestra arquitectura), pero eso es una integración real que tienes que construir tú, no un import de una línea para Lambda hoy. Si tu prioridad es un SDK totalmente llave en mano para runtimes serverless, sé claro contigo mismo antes de comprometerte: revisa /security para la arquitectura actual y /faq para ver qué está lanzado frente a qué está en el roadmap.

Un patrón práctico que funciona hoy

  1. Usa koove set para cada secreto, por entorno, en el momento en que se crea — antes de que toque nunca un archivo .env o una consola.
  2. Limita tus variables de entorno de Lambda/Vercel a configuración no sensible (región, feature flags) y nombres de claves, nunca valores.
  3. Para el camino de descifrado de tu backend, usa @koove/crypto directamente si construyes consumo del lado del servidor a medida, y trata esa clave de identidad con el mismo cuidado que cualquier clave privada.
  4. Audita regularmente listas de dispositivos y accesos con koove list y koove devices; revoca lo que no se use con koove device-revoke.

Los límites, con honestidad

El cifrado por sobres de Koove no tiene forward secrecy — no es un ratchet de mensajería, y no reivindicamos propiedades del nivel de Signal. Revocar un dispositivo detiene el descifrado futuro; no borra un secreto que ya fue descifrado y quedó cacheado en algún sitio. Los arranques en frío y la latencia de red son problemas de física que ningún esquema de cifrado resuelve por ti — sigues necesitando diseñar bien tu estrategia de caché.

Si tus funciones serverless están sacando secretos hoy de dashboards de proveedores, el primer arreglo no es un SDK nuevo — es asegurarte de que no exista ningún secreto en texto plano en ningún sitio donde un asistente de IA, un compañero o un log mal configurado puedan leerlo. Empieza en /register y configura tu primer secreto en menos de un minuto.

Código generado por IA

Tu IA escribe el código. ¿Quién guarda los secretos?

El fallo de seguridad más común en apps generadas con IA son las credenciales expuestas. Con Koove, tu propio asistente guarda cada token desde la CLI — cifrado en tu máquina, nunca en el código ni en el repo.