Gestión de secretos
La configuración del backend incluye credenciales de alto impacto. Esta página describe cómo tratarlas.
Qué hay en el .env
Toda la configuración vive en docker-compose.yml, escrita literalmente. Lo
único que llega del entorno son estas claves, y por eso el .env es el único
archivo que nunca se versiona.
Sin ellas el stack no arranca — pero se generan solas
| Secreto | Impacto si se filtra |
|---|---|
DB_PASSWORD | Acceso total a la base de datos. |
JWT_SECRET | Clave maestra. Falsifica sesiones, descifra las claves privadas guardadas y las credenciales de Datadis, y deriva carteras. Ver API de Zertipower. |
Opcionales — el stack arranca sin ellas
| Clave | Qué se pierde |
|---|---|
GOOGLE_CLIENT_ID y GOOGLE_CLIENT_SECRET | El botón «Iniciar sesión con Google» del Panel deja de funcionar; se entra con usuario y contraseña. Van en pareja: con una sola tampoco funciona. El secreto lo es de verdad; el ID no — ver Acceso con Google, paso a paso. |
ZERTIAUTH_APP_SECRET | No se puede derivar la cartera, así que falla el primer acceso con Google de cada usuario. Los que ya tengan cuenta entran igual. Sigue siendo una clave maestra: quien la tenga deriva la cartera de cualquiera. |
PK | No se firma nada on-chain: la capa blockchain queda inerte. El instalador genera una al azar, así que rara vez falta — pero la generada es una cartera vacía. Sigue siendo un secreto: quien tenga la de verdad controla la cartera y sus fondos. |
STRIPE_SECRET_KEY | Dejan de funcionar los endpoints /stripe: no se pueden comprar EKW desde el Contador. Sigue siendo un secreto — en local, siempre sk_test_…. |
GOOGLE_MAPS_API_KEY | El mapa no carga y la geocodificación responde REQUEST_DENIED. |
SOLAR_API_AUTH_CODE | La predicción de producción solar devuelve error. |
Es una clave de navegador: acaba dentro del HTML que se sirve, así que no se puede ocultar. Se protege restringiéndola por dominio en Google Cloud Console, no manteniéndola en secreto. Está aquí porque conviene no regalarla, no porque ocultarla sirva de algo.
Cómo rellenarlas
Al ejecutar ./setup.sh o setup.bat sin un .env presente, el instalador
escribe uno completo sin preguntar nada… salvo las dos claves de Google, que
son lo único que no puede deducir. El secreto no se muestra al teclear; el
client ID sí, porque no es secreto y así se ve una errata al pegarlo.
DB_PASSWORD, JWT_SECRET y PK se generan al azar, en hexadecimal. No hay que
elegirlas, y el hexadecimal evita que un carácter especial rompa la cadena de
conexión a la base de datos.
Las demás —ZERTIAUTH_APP_SECRET, STRIPE_SECRET_KEY, GOOGLE_MAPS_API_KEY,
SOLAR_API_AUTH_CODE— quedan escritas y vacías en el .env, cada una con un
comentario que explica qué se pierde sin ella. Para ponerlas, se edita el
archivo.
Las de Google no se saltan pulsando INTRO
Dejarlas en blanco era lo cómodo, y salía caro: la instalación parecía terminada y nadie podía entrar con Google, con el fallo apareciendo mucho después y lejos de su causa.
Ahora el instalador insiste. Si las dejas vacías, explica que faltan y las
vuelve a pedir. Se puede instalar sin ellas, pero hay que decirlo a propósito
escribiendo SALTAR; a la tercera ronda continúa igualmente, para no dejar
una instalación colgada.
Si sales sin ponerlas, se entra con admin / admin123, y cuando tengas el
cliente de OAuth basta con añadirlas al .env y reiniciar el backend:
./dev.sh up -d backend
Cómo crear el cliente: Acceso con Google, paso a paso.
Las únicas dos que el compose exige sin valor por defecto, DB_PASSWORD y
JWT_SECRET, las genera el instalador, así que siempre están. Todo lo demás
puede quedarse vacío: el sistema arranca y sólo se pierde la función que dependa
de esa clave.
DB_PASSWORD, JWT_SECRET y PK no se preguntan: se generan al azar en
hexadecimal. Esto último importa —ver la regla 6 más abajo.
ZERTIAUTH_APP_SECRET no se genera nuncaEs la excepción a lo anterior, y la razón por la que no se generan todas. Vacía es segura: la derivación lanza un error claro y no crea ninguna cartera. Un valor inventado no falla — deriva carteras distintas de las reales, sin avisar, y el usuario pierde el acceso a lo que tuviera on-chain.
Por eso el instalador la pregunta y la deja en blanco si no la sabes, en vez de
rellenarla con algo. Sale de la columna secret de la tabla apps de Zertiauth.
PK generada no sirve para firmarDB_PASSWORD y JWT_SECRET se pueden generar porque cualquier valor aleatorio
es correcto: el instalador configura los dos lados a la vez. PK no funciona
así. Su contraparte —la cartera que ya posee los contratos— existe fuera del
sistema y no se reconfigura, de modo que la clave generada corresponde a una
cartera nueva y vacía: sin gas y sin permisos.
Sirve para que el sistema arranque sin preguntar nada. Para usar la blockchain de
verdad hay que sustituirla en el .env por la clave real. El archivo que genera
el instalador lleva un comentario que lo recuerda.
Si el .env ya existe pero está incompleto
Es el caso más habitual al heredar una instalación. El instalador repasa el archivo y completa lo que falte, sin tocar lo que ya hay:
DB_PASSWORDyJWT_SECRET, si faltan, se generan al azar. No se preguntan nunca.PKigual.- Las demás, si ni siquiera están escritas en el archivo, se preguntan una vez y se escriben aunque las dejes en blanco, para no volver a preguntarlas en cada ejecución. Una clave escrita y vacía es una decisión tomada, y se respeta: sólo se recuerda qué se pierde sin ella.
- Lo que el archivo ya tiene no se toca, comentarios incluidos.
- Una clave vacía se rellena en su sitio; una que no estuviera se añade al final.
- Antes de modificar nada deja una copia en
.env.backup-<fecha>, que está cubierta por.gitignore. - En modo
--desatendidono puede preguntar: genera las que sabe generar y avisa de las que quedan vacías, pero no se detiene, porque ya ninguna impide arrancar.
Las opcionales no detienen nada. De las que ni siquiera estén escritas en el archivo te pregunta una vez, y las escribe aunque las dejes en blanco: así no vuelve a preguntártelas en cada ejecución. Una clave escrita y vacía es una decisión tomada, y se respeta.
Los dos son opcionales y el instalador los pide juntos, porque van en pareja: un
secreto con el ID de otro cliente da invalid_client, y el ID solo tampoco
sirve. Si pones uno y el otro no, avisa.
Reglas
- El
.envnunca se versiona. Debe estar en.gitignore. Lo que se versiona es.env.example, sólo con marcadores de posición. - Los secretos no van en la documentación. Esta documentación es un artefacto compartible: describe el procedimiento, no los valores.
- Nada de credenciales en la línea de comandos. Quedan en el historial del shell y en la lista de procesos. Usa un archivo de opciones (ver Volcado remoto).
- En local, claves de test. Stripe en modo test; nunca claves
sk_live_. - Copias mínimas. Cada copia adicional de un secreto es una superficie de fuga más. Borra los volcados y archivos temporales cuando dejen de hacer falta.
DB_PASSWORD, sólo letras y dígitos. Se interpola tal cual dentro de la URL de conexión, sin codificar, así que un#,/,@,:,?o%la parte y el backend no arranca — con un error que despista mucho, invalid port number in database URL. Genérala conopenssl rand -hex 32; no con-base64, cuyo alfabeto incluye/y+.- Entrecomilla los valores con comillas simples. En un
.env, Compose interpreta el símbolo de dólar incluso entre comillas dobles, y una almohadilla precedida de espacio abre un comentario. Las comillas simples evitan ambas cosas.
Comprobar que no se ha filtrado nada
Antes de hacer commit, comprueba que ningún secreto real ha entrado en archivos versionados:
git grep -nE "sk_live_|BEGIN PRIVATE KEY|password=" -- . ':!*.example'
Y confirma que Git ignora efectivamente el .env:
git check-ignore -v zertipower-zertibuilder/backend/.env
Si el comando no devuelve nada, el archivo no está ignorado: corrígelo antes de seguir.
Rotación
Si un secreto se expone (se pega en un chat, se sube por error, se comparte en una
captura), la única respuesta correcta es rotarlo, no borrar el mensaje. En
particular la clave PK y la contraseña de producción.