Secretos en Git: cómo tener los secretos versionados siguiendo buenas prácticas de seguridad
Casi todos nuestros proyectos, por no decir absolutamente todos, manejan información sensible. Ya sea ficheros de variables de entorno (tipo .env) u otros. La mayoría de nosotros subimos estos ficheros al repositorio en formato plano o bien esperamos a que el siguiente desarrollador sepa qué valores rellenar siguiendo la documentación (que, seamos sinceros, en muchas ocasiones es deficiente) o bien sea capaz de "por arte de magia" —y con magia me refiero a ir preguntando al equipo— rellenar esa información.
Personalmente, estoy cansado del .env que no tiene valor ninguno porque las variables son totalmente falsas, o de no tener versionados mis secretos, que son necesarios para desplegar mi aplicación en cualquier entorno.
Me parece que seguir utilizando ese tipo de estrategias es una solución a medias que genera fricción, obliga a configurar cada entorno a mano y, a menudo, los ejemplos se quedan desactualizados. Mi filosofía es distinta: quiero tener los ficheros reales de cada entorno en el repositorio, con la información exacta que van a utilizar, pero con la seguridad absoluta de que sólo quien debe verlos, pueda hacerlo.
Para lograr esto sin montar infraestructuras de seguridad complejas, he vuelto a un veterano: git-crypt.
El equilibrio entre seguridad y sencillez
Git-crypt no es un servicio en la nube ni una base de datos compleja. Es una herramienta de línea de comandos que se instala localmente y que utiliza las propias primitivas de Git para funcionar. Su gran ventaja es que no requiere que cambies tu forma de trabajar: sigues usando git add, commit y push como siempre. Lo que hace especial a git-crypt es que cifra los archivos antes de que salgan de tu ordenador y los descifra cuando llegan al de un compañero autorizado, sin que el servidor git remoto (GitHub, Gitlab, etc.) vea jamás el contenido real.
Esto permite lo que conocemos como cifrado transparente. A diferencia de otras herramientas que requieren comandos manuales de cifrado cada vez que haces un cambio, git-crypt se integra en el corazón de Git mediante filtros:
- Filtro Clean: Cuando añades un archivo al "stage", git-crypt lo cifra antes de que se guarde en la base de datos de Git.
- Filtro Smudge: Al hacer un "checkout" o "pull", el archivo se descifra automáticamente para que sea legible en tu carpeta de trabajo.
Esta transparencia significa que en tu máquina trabajas con archivos reales, pero en el repositorio remoto, los archivos son ruido binario ilegible.
Consideraciones antes de lanzarte a usarlo
Pero no es oro todo lo que reluce y, antes de que lo implementes, debes tener en cuenta tres puntos que pueden ser "deal-breakers" según tu proyecto:
- Conflictos de Git (Merge Conflicts): Al cifrar el archivo completo, Git lo trata como un bloque binario. Si dos personas modifican el mismo
.enva la vez, no podrás hacer un "merge" línea por línea; tendrás que elegir una versión o reconstruir el archivo a mano. - Visibilidad de metadatos: git-crypt oculta el contenido, pero no el nombre del archivo ni su existencia. Si alguien entra en tu repo, sabrá que tienes un archivo llamado
prod.db.env. - El riesgo del "Primer Push": Si comiteas un archivo antes de configurar git-crypt, ese secreto ya está en el historial de Git para siempre, aunque luego lo cifres. La configuración inicial debe ser impecable.
Cómo empezar con git-crypt en tu proyecto
En lugar de manuales de instrucciones, definimos un archivo .gitattributes, donde añadimos los patrones de los archivos que contienen la verdad de nuestro sistema:
# .gitattributes
config/dev.env filter=git-crypt diff=git-crypt
config/prod.env filter=git-crypt diff=git-crypt
A la hora de configurar git-crypt para proteger estos archivos, tienes dos caminos principales. La opción rápida es la clave simétrica: generas un archivo de llave único que debes compartir de forma segura (gestor de contraseñas) con tu equipo. Es ideal para configurar rápidamente un servidor de CI/CD o para un proyecto personal. Sin embargo, la opción más robusta y escalable es basar la seguridad en identidades digitales.
Para equipos pequeños, mi recomendación es usar GPG. Permite autorizar a personas específicas de forma nominal. Si alguien sale del proyecto, simplemente dejas de añadir su clave en las futuras rotaciones de secretos. Es sencillo, profesional y auditable.
El siguiente paso: Mozilla SOPS
Si tu proyecto crece, el equipo aumenta a más de 5-10 personas o empiezas a usar Kubernetes de forma intensiva, notarás que las limitaciones de git-crypt (especialmente los conflictos de merge) empiezan a picar.
Cuando la gestión de secretos se vuelve crítica a esa escala, el ecosistema nos ofrece tres niveles de solución. En la cima de la complejidad están los gestores centralizados como HashiCorp Vault, potentes pero costosos de mantener. Luego están los servicios gestionados de nube como AWS KMS o Google Secret Manager, que delegan la custodia. Y finalmente, en el punto dulce entre la sencillez de git-crypt y la potencia de la nube, encontramos las herramientas de cifrado descentralizado modernas.
En ese momento, el siguiente paso lógico es Mozilla SOPS.

¿Por qué SOPS es el "hermano mayor" profesional?
- Cifrado parcial: SOPS entiende la estructura de tus archivos (YAML, JSON, ENV). No cifra el archivo completo, sino solo los valores, dejando las claves visibles. Esto permite resolver conflictos de Git como si fuera texto normal.
- Integración nativa con la Nube: Mientras que git-crypt depende de que tú gestiones las llaves, SOPS se conecta directamente con AWS KMS, Google Cloud KMS o Azure Key Vault. El servidor se autentica por su rol, no por un archivo de llave que tú le pases.
- Auditoría: Es mucho más fácil ver qué cambió en un secreto sin necesidad de descifrarlo primero.
| Característica | git-crypt | Mozilla SOPS |
|---|---|---|
| Ideal para | Proyectos personales / Pequeños equipos | Entornos Cloud-native / Equipos grandes |
| Manejo de conflictos | Difícil (Binario) | Fácil (Texto/Claves visibles) |
| Complejidad | Muy baja | Media |
Como ves, SOPS es una herramienta potente que cubre las carencias de git-crypt en equipos grandes. Dado que su configuración y uso tienen más miga, le dedicaré un artículo en profundidad próximamente para explicar cómo implementarlo paso a paso.
Un ejemplo real con NestJS
Para que no te quedes solo con la teoría, he creado un repositorio de ejemplo con una aplicación NestJS que implementa este flujo de trabajo.
En este proyecto nest-crud podrás ver:
- Gestión Multi-entorno: Cómo conviven
.env,.env.stagey.env.productionen el mismo repositorio, totalmente cifrados. - Integración Transparente: La configuración de
.gitattributespara quegit pushygit pullse encarguen del cifrado/descifrado sin comandos extra. - Carga Dinámica: Cómo configuro el
ConfigModulede NestJS para cargar el archivo de entorno correcto según elNODE_ENV.
Es un ejemplo sencillo pero que sienta las bases de una gestión de secretos profesional y escalable sin la complejidad de herramientas externas.
Conclusión
No todos los proyectos necesitan una caja fuerte de grado militar desde el primer commit. git-crypt me permite mantener la "fuente de la verdad" dentro del repositorio, eliminando el error humano y manteniendo la agilidad. Y si el proyecto escala, siempre tenemos la puerta abierta para migrar a SOPS u otra alternativa más potente y compleja.
