Capítulo 28 de 33 9 secciones 6 min

El día que subes una clave sin querer

Qué hacer primero, qué hacer después y qué no sirve de nada

<strong>Rota la clave antes de tocar el repositorio.</strong> Entra al proveedor, genera una nueva y anula la vieja: eso la vuelve inútil y es lo único que de verdad cierra el problema. Borrar el archivo no sirve, porque sigue en la historia, y limpiar la historia tampoco basta, porque los robots que rastrean GitHub buscando claves suelen copiarlas en minutos. Limpiar y poner un <code>.gitignore</code> viene después.

Este capítulo lo escribo con cariño porque le pasa a todo el mundo, incluida gente con veinte años de oficio. Un git add . se llevó el .env, y ahora las claves de la base de ventas están en internet 😬

Lo importante es el orden. Casi todo el mundo lo hace al revés.

El orden correcto

PasoQuéPor qué
1Rotar la clave en el proveedorEs lo único que la vuelve inútil
2Poner el repositorio en privado, si era públicoCorta el goteo mientras limpias
3Sacar el archivo y agregarlo al .gitignorePara que no vuelva a entrar
4Limpiar la historia, si hace faltaEs lo más caro y lo menos urgente

Fíjate en que limpiar la historia es el último paso y no el primero. Es el que más tiempo cuesta y el que menos resuelve 🧯

Por qué borrar el archivo no basta

mkdir tienda
cd tienda
git init -q
printf 'ciudad,monto\nLima,1200\n' > ventas.csv
printf 'API_KEY=clave-de-ejemplo-1234\n' > .env
git add .
git commit -q -m "Conexion a la base de ventas"
git rm -q .env
git commit -q -m "Se quita el archivo de configuracion"
ls -a
git log --oneline
.
..
.git
ventas.csv
e115bef Se quita el archivo de configuracion
baabc8f Conexion a la base de ventas

El archivo ya no está en la carpeta. Pero:

git show HEAD~1:.env
git log --all --oneline -- .env
API_KEY=clave-de-ejemplo-1234
e115bef Se quita el archivo de configuracion
baabc8f Conexion a la base de ventas

Ahí está la clave, entera, sacada de la historia con un comando. Cualquiera con acceso al repositorio puede hacer eso, y en GitHub además quedó en la vista de commits 🔍

Que no vuelva a entrar

printf 'API_KEY=otra-clave-de-ejemplo\n' > .env
printf '.env\n*.key\n' > .gitignore
git add .gitignore
git commit -q -m "El archivo de configuracion no entra al repositorio"
git status --short
git check-ignore -v .env
.gitignore:1:.env	.env

Ese check-ignore te dice qué línea del .gitignore está tapando el archivo, que es lo que hay que comprobar y no suponer. Todo esto está en 9 🚫

Y lo que sí va al repositorio

La costumbre que resuelve esto para siempre: un archivo de ejemplo, sin valores, que sí se sube y le dice a quien clone qué tiene que rellenar.

printf 'API_KEY=\nBASE_URL=\n' > .env.ejemplo
git add .env.ejemplo
git commit -q -m "Ejemplo de configuracion, sin valores"
cat .env.ejemplo
git ls-files
API_KEY=
BASE_URL=
.env.ejemplo
.gitignore
ventas.csv

El repositorio lleva el molde y nunca los valores. Es lo que hace todo proyecto serio 📄

Limpiar la historia, si hace falta

Existe, se hace con la herramienta git filter-repo, y hay que saber tres cosas antes:

  • Reescribe todos los commits, o sea que cambian todos los hashes, con lo que vimos en 27.
  • Todo el que tenga una copia tiene que clonar de nuevo.
  • Los pull requests viejos de GitHub pueden seguir mostrando el contenido, y hay que pedirle soporte a GitHub que los purgue.

O sea que es caro. Y con la clave ya rotada, casi nunca es urgente: lo que queda en la historia es una clave que no abre nada 🔒

Buscar antes de subir

grep -rn "API_KEY\|PASSWORD\|SECRET" . --exclude-dir=.git --exclude=".env" || echo "limpio"
git ls-files
./.env.ejemplo:1:API_KEY=
.env.ejemplo
.gitignore
ventas.csv

Ese grep, corrido antes del primer push de un proyecto, es de las cosas que más disgustos ahorran. Y GitHub tiene lo suyo: el secret scanning, que avisa solo cuando detecta una clave de un proveedor conocido 🔔

La trampa

Subiste sin querer el archivo con la clave de la API. Lo borras, haces commit y respiras.

$ git rm .env
$ git commit -m "Se quita el archivo de configuracion"
$ git push

$ git log --all --oneline -- .env
8f2a91c Conexion a la base de ventas
Qué está mal

El archivo se fue del presente y sigue en la historia 🔍

Borrar algo en Git es un cambio más: el commit de ayer sigue teniendo el archivo entero, y cualquiera puede sacarlo con un git show. En GitHub, además, quedó en la vista de commits.

Y aunque limpiaras la historia entera, sigue habiendo algo que no controlas: los robots que rastrean GitHub buscando claves ya la copiaron, casi siempre en cuestión de minutos.

Por eso el primer paso nunca es limpiar el repositorio. Es rotar la clave en el proveedor, que la vuelve inútil. Limpiar viene después y con calma.

Comprueba que se entendió

Comprueba que lo tienes

Te das cuenta de que subiste el .env con la clave de la API. ¿Qué haces primero?

  • Rotar la clave en el proveedor
  • Borrar el archivo y hacer push
  • Borrar el repositorio de GitHub
  • Limpiar la historia con filter-repo

Ejercicios

1. Comete el error a propósito

Un git add . que se lleva el archivo de configuración.

cd ..
mkdir bodega
cd bodega
git init -q
printf 'bodega,ciudad\nBodega Inti,Cusco\n' > bodegas.csv
printf 'API_KEY=clave-de-ejemplo-abcd\n' > .env
git add .
git commit -q -m "Conexion al catalogo de bodegas"
git ls-files
.env
bodegas.csv

Ahí está el .env dentro del repositorio.

2. Comprueba que borrarlo no basta

Quítalo y sácalo igual de la historia.

git rm -q .env
git commit -q -m "Se quita el archivo de configuracion"
ls -a
git show HEAD~1:.env
.
..
.git
bodegas.csv
API_KEY=clave-de-ejemplo-abcd

Fuera de la carpeta y dentro de la historia. Por eso se rota primero 🔑

3. Ponle el gitignore

Que no pueda volver a entrar.

printf 'API_KEY=otra-clave\n' > .env
printf '.env\n' > .gitignore
git add .gitignore
git commit -q -m "El .env no entra al repositorio"
git status --short
git check-ignore -v .env
.gitignore:1:.env	.env

Comprobado, no supuesto.

4. Sube el molde sin valores

El archivo de ejemplo que sí va al repositorio.

printf 'API_KEY=\nBASE_URL=\n' > .env.ejemplo
git add .env.ejemplo
git commit -q -m "Ejemplo de configuracion, sin valores"
cat .env.ejemplo
git ls-files
API_KEY=
BASE_URL=
.env.ejemplo
.gitignore
bodegas.csv

Quien clone sabe qué rellenar y no recibe ninguna clave 📄

5. Busca secretos antes de subir

La revisión de cinco segundos antes del primer push.

grep -rn "API_KEY\|PASSWORD" . --exclude-dir=.git --exclude=".env" || echo "limpio"
./.env.ejemplo:1:API_KEY=

Solo aparece el molde vacío, que es justo lo que debe aparecer.

6. Revisa toda la historia, no solo el presente

Busca el archivo en cualquier commit del repositorio.

git log --all --oneline -- .env
d5b0f0c Se quita el archivo de configuracion
ce26339 Conexion al catalogo de bodegas

Dos commits lo tocaron: el que lo metió y el que lo sacó. Los dos lo contienen 🔍

7. Pide un archivo que ya no está en el último commit

Comprueba qué contesta Git cuando pides el .env de ahora.

git show HEAD:.env
fatal: path '.env' exists on disk, but not in 'HEAD'

En el presente no está, y ese es justo el error que hace creer que el problema se resolvió 🙈

Lo que te llevas

Rotar primero. Borrar el archivo no lo saca de la historia, y la historia es lo de menos si la clave ya no abre nada.

¿Tienes alguna duda o consulta?