Gestión de secretos en aplicaciones a medida
Gestión de secretos y variables de entorno en una aplicación a medida
Voy a empezar con la frase que más veces he tenido que decir en una revisión de código: ese token no va ahí. "Ahí" suele ser el repositorio, un fichero de configuración versionado, o peor, un comentario de un Slack que lleva tres años indexado. Cuando trabajas en una aplicación a medida tienes la ventaja de que controlas la arquitectura de arriba abajo, y la responsabilidad de que no haya credenciales paseándose por sitios donde no deberían.
La gestión de secretos no es un tema sexy. No sale en la demo, el cliente no lo ve, y casi siempre se aborda tarde, cuando alguien ha filtrado una clave de AWS y el coste de la factura del mes te lo recuerda. Vamos a hacerlo bien desde el principio.
Qué es un secreto y por qué no va en el repositorio
Un secreto es cualquier dato que da acceso a algo y que, si cae en malas manos, te genera un problema. En la práctica:
- API keys de servicios de terceros (Stripe, SendGrid, una pasarela bancaria).
- Contraseñas y cadenas de conexión de bases de datos.
- Tokens de acceso, refresh tokens, JWT de firma.
- Certificados y claves privadas (TLS, claves SSH, claves de firma de apps).
- Secretos de cifrado que protegen otros datos.
La diferencia entre un secreto y una variable de configuración normal es sencilla: si lo publicas en un tablón de la oficina y no pasa nada, es configuración; si te entra el sudor frío, es un secreto.
¿Por qué no va hardcodeado en el código ni en el repositorio? Porque el repositorio es el sitio menos privado que existe. Se clona en quince portátiles, se sube a un CI, se copia a un backup, queda en el historial de git para siempre. Aunque borres la línea en un commit posterior, ahí sigue: git log -p la recupera en dos segundos. Y si el repo es privado hoy, no garantizas que lo siga siendo dentro de dos años, ni que el portátil de un becario no acabe en un tren de Cercanías.
Hardcodear un secreto en el código es asumir que tu código es secreto. No lo es. Trátalo como si fuera a hacerse público mañana.
Variables de entorno y ficheros .env: hasta dónde llegan
La primera respuesta, y la correcta para empezar, es sacar los secretos del código y meterlos en el entorno. Esto entronca directamente con la metodología 12-factor, cuyo tercer factor lo dice sin medias tintas: la configuración que cambia entre despliegues (incluidas las credenciales) vive en variables de entorno, no en el código.
La ventaja es real. El mismo artefacto (la misma imagen Docker, el mismo build) se promociona de dev a staging a producción sin tocar una línea; lo único que cambia es el entorno que lo rodea. Eso es lo que quieres.
En local solemos usar un fichero .env:
DATABASE_URL=postgres://app:devpassword@localhost:5432/miapp
STRIPE_API_KEY=sk_test_xxxxx
JWT_SECRET=clave-solo-para-desarrollo
Y la regla de oro que se incumple constantemente:
# .gitignore
.env
.env.*
!.env.example
El .env.example se versiona con las claves vacías o de ejemplo, para que cualquiera sepa qué variables hace falta rellenar. El .env real nunca, jamás.
Ahora la parte incómoda: el .env no es una solución de seguridad, es una comodidad de desarrollo. Tiene límites serios.
- Está en texto plano en el disco de cada desarrollador.
- No tiene control de acceso granular: quien lee el fichero lo lee entero.
- No hay auditoría: nadie sabe quién consultó qué secreto ni cuándo.
- No hay rotación: cambiar una clave implica avisar a mano a media docena de personas y rezar.
- Se comparte por Slack o por mail, que es como repartir copias de las llaves de casa por correo postal.
Para producción, un fichero .env plano en el servidor es el mínimo aceptable, y ni eso en cuanto el proyecto crece. Ahí entran los gestores de secretos.
Gestores de secretos: el siguiente nivel
Un gestor de secretos es un almacén centralizado, cifrado y auditado, del que tu aplicación pide las credenciales en tiempo de arranque o de ejecución. Las opciones que veo en proyectos reales en España:
- HashiCorp Vault. El más completo y el más exigente de operar. Cifrado, políticas de acceso por rol, auditoría detallada y, lo mejor, secretos dinámicos: Vault genera una credencial de base de datos efímera, válida una hora, y la revoca sola. Si no tienes un equipo de plataforma que lo mantenga, te puede quedar grande.
- AWS Secrets Manager / SSM Parameter Store. Si ya estás en AWS, es lo natural. Secrets Manager incluye rotación automática integrada con RDS; Parameter Store es más barato y suficiente para muchos casos. Ambos se integran con IAM, así que el control de acceso ya lo tienes resuelto.
- Google Secret Manager. El equivalente en GCP, integrado con IAM de Google. Sencillo, versionado de secretos y control de acceso por servicio.
- Doppler. SaaS agnóstico de nube, muy cómodo para equipos que no quieren montar infraestructura. Sincroniza secretos a distintos entornos y se integra bien con los CI/CD habituales.
No hay una respuesta universal. Si tu aplicación a medida ya vive en AWS, no montes un Vault para presumir: usa Secrets Manager y a otra cosa. Si tienes multinube o quieres independencia del proveedor, Doppler o Vault tienen más sentido. El criterio es: el menor número de piezas móviles que resuelva el problema con auditoría y control de acceso.
Cifrado en reposo y en tránsito
Dos frentes que no son negociables. En reposo: el secreto se guarda cifrado en el almacén (los gestores anteriores lo hacen por defecto, normalmente con una KMS detrás). En tránsito: cuando tu app pide el secreto, viaja por una conexión TLS. De nada sirve un Vault impecable si la aplicación lo consulta por HTTP plano dentro de la red.
Y un detalle que se olvida: una vez el secreto llega a la aplicación, vive en memoria. No lo escribas en disco, no lo metas en un log, no lo expongas en un endpoint de debug.
Separación estricta por entornos
Dev, staging y producción tienen secretos distintos. Siempre. Esto no es burocracia, es contención de daños.
La clave de Stripe de desarrollo es sk_test_... y mueve dinero de mentira. La de producción mueve dinero de verdad. Si un desarrollador prueba contra la base de datos de producción "un momentín" porque tiene la credencial a mano, ese momentín acaba en un DELETE sin WHERE.
La regla:
- Cada entorno tiene su propio conjunto de credenciales.
- Nadie en desarrollo debería poder leer los secretos de producción.
- El acceso a producción se concede a personas concretas y se audita.
- Si comprometen el entorno de staging, producción no se ve afectada.
Con un gestor de secretos esto se modela con políticas o caminos separados (secret/dev/..., secret/prod/...) y permisos por rol. Con ficheros .env se modela rezando, que es justo por lo que los ficheros .env no escalan.
Evitar fugas en git, y qué hacer si ya se filtró
El sitio por el que más secretos se escapan es el commit despistado. Hay herramientas para frenarlo antes de que ocurra:
- Pre-commit hooks que escanean los cambios antes de permitir el commit.
- git-secrets (de AWS), que bloquea patrones conocidos como claves de AWS.
- gitleaks, más completo, detecta multitud de patrones de secretos y se integra perfectamente en el CI para que ningún PR pase con una credencial dentro.
Lo recomendable es doble barrera: gitleaks como hook local para feedback inmediato, y gitleaks de nuevo en el pipeline de CI como red de seguridad por si alguien se salta el hook con --no-verify.
Ahora el escenario malo. Se ha filtrado un secreto. Alguien lo ha subido al repo, o ha quedado en un log público, o lo ha pegado en un ticket. El instinto de borrar la línea y commitear encima es el error clásico, porque el secreto sigue vivo en el historial y, sobre todo, alguien pudo haberlo copiado ya.
El procedimiento correcto, en este orden:
- Rotar la credencial ya. Genera una nueva, invalida la antigua. Esto es lo primero y lo más urgente: a partir de la rotación, el secreto filtrado no sirve para nada. Todo lo demás es secundario.
- Actualizar la aplicación y los entornos con la credencial nueva.
- Limpiar el historial de git si procede (con
git filter-repoo BFG), asumiendo que es un parche cosmético, no la solución. - Revisar logs de acceso del servicio afectado por si hubo uso indebido.
Repito el punto uno porque es el que la gente se salta: limpiar el repo sin rotar la clave es como cambiar la cerradura de la foto pero dejar la llave puesta. Rotar primero, limpiar después.
Inyección de secretos en CI/CD sin exponerlos
El pipeline necesita secretos para desplegar: la credencial para subir la imagen, la clave para conectarse al servidor, el token de despliegue. Y el CI/CD es un sitio peligroso porque lo registra todo en logs que mucha gente puede ver.
Las pautas que aplico:
- Usar el almacén de secretos del propio CI (GitHub Actions secrets, GitLab CI variables, etc.) o, mejor aún, que el pipeline los lea del gestor de secretos central en tiempo de ejecución.
- Inyectarlos como variables de entorno, nunca pasarlos como argumentos de línea de comandos: los argumentos aparecen en la lista de procesos y a veces en los logs.
- Marcar las variables como protegidas / enmascaradas para que el CI las censure si aparecen por accidente en la salida.
- Nada de
echo $SECRETniset -xcon secretos en pantalla. Suena obvio; lo veo cada mes. - Limitar el alcance: el token de despliegue solo despliega, no tiene permisos de administrador "por si acaso".
La idea de fondo es que el secreto exista en el job el tiempo justo, en memoria, y desaparezca al terminar sin dejar rastro en ningún log.
Rotación de credenciales: por qué y cada cuánto
Las credenciales caducan, aunque no lo parezca. Cuanto más tiempo vive un secreto, más copias ha generado, más manos lo han tocado, más backups lo guardan. La rotación periódica reduce esa ventana de exposición.
Rotas porque:
- Limita el daño de una filtración que no has detectado.
- Invalida credenciales de gente que ya no está en el equipo.
- Es un requisito en muchos marcos de cumplimiento.
El sueño es la rotación automática (Secrets Manager con RDS, o los secretos dinámicos de Vault), donde la credencial se renueva sola sin intervención humana ni downtime. Si no llegas a eso, al menos ten un calendario y un procedimiento documentado de rotación manual, y rota inmediatamente ante cualquier sospecha o salida de un miembro del equipo con acceso.
Cuando el secreto da acceso a datos personales: RGPD
Aquí dejamos de hablar solo de buenas prácticas y entramos en obligación legal. Si un secreto protege el acceso a una base de datos con datos de tus usuarios (nombres, emails, DNI, datos de salud, lo que sea), la gestión de ese secreto es una medida de seguridad en el sentido del artículo 32 del RGPD, que exige aplicar medidas técnicas y organizativas apropiadas al riesgo, incluido el cifrado.
En España esto lo supervisa la AEPD, y una credencial filtrada que dé acceso a datos personales puede constituir una violación de seguridad notificable en 72 horas. No es teoría: tener una clave de base de datos en un repo público, con datos de clientes detrás, es exactamente el tipo de fallo que acaba en sanción.
Lo que esto implica para tu aplicación a medida:
- Los secretos que tocan datos personales merecen el tratamiento más estricto: gestor centralizado, cifrado, acceso mínimo y auditado.
- La auditoría de quién accedió a qué secreto y cuándo no es un lujo, es lo que te permite demostrar diligencia ante la AEPD si algo sale mal.
- La separación por entornos protege que un fallo en desarrollo no exponga datos reales de producción.
Tratar bien los secretos no es solo higiene de ingeniería: es parte de cumplir la normativa.
Qué revisar este mismo sprint
Sin grandes proyectos ni reuniones. Cosas que puedes comprobar hoy:
git grep -iE "(password|secret|api[_-]?key|token)"en tu repo. Si aparece algo real, rótalo ya y planifica sacarlo.- Confirma que
.envestá en.gitignorey que existe un.env.examplecon valores vacíos. - Instala gitleaks como pre-commit hook y añádelo al pipeline de CI.
- Verifica que dev, staging y producción usan credenciales distintas, y que nadie de desarrollo puede leer las de producción.
- Revisa los logs del último despliegue buscando secretos impresos por accidente.
- Si todavía vives de ficheros
.enven servidores, evalúa mover los secretos de producción a un gestor (Secrets Manager si estás en AWS, Doppler si quieres algo rápido). - Apunta una fecha de rotación para las credenciales más sensibles.
Si al hacer esta revisión encuentras más de lo que esperabas, no es raro, y es justo el momento de ordenarlo antes de que crezca. Si quieres una mano para diseñar la gestión de secretos de tu aplicación a medida con criterio de seguridad y cumplimiento, cuéntanos tu proyecto.