Pipeline filtrando secretos
Enunciado
El equipo de desarrollo lleva meses subiendo código a Gitea. Hace una semana, un API key de un servicio crítico apareció en un repositorio público de GitHub. El CTO te pide auditar todo el historial de los repositorios internos y evitar que esto vuelva a pasar.
Herramientas
- Docker
- Gitea
- Jenkins
- Gitleaks
Asignación
-
Ejecuta gitleaks contra cada repositorio. Gitleaks recorre todo el historial de commits, no solo el actual.
-
Añade un job en Jenkins que ejecute gitleaks antes de cada despliegue a producción. Si encuentra un secreto, el pipeline falla y bloquea la operación.
-
Configurar un hook local para que los desarrolladores reciban una advertencia antes de hacer commit.
Pasos realizados
Tenemos nuestro servicio Gitea ejecutándose en nuestro servidor sin ningún inconveniente; este le da alojamiento al código del proyecto.

Descargamos la última versión de Gitleaks desde su repositorio oficial Gitleaks. Para escanear el proyecto, debemos clonarlo y ejecutar la herramienta en el repositorio local.

Ejecutamos la herramienta con:
./gitleaks detect --source ./webapp/ --verbose
Observamos que en la rama Develop se encuentran claves y tokens de servicio que no deberían estar allí:

Automatizar Pruebas con Jenkins
Debemos impedir que los tokens lleguen al ambiente de producción; esto se logra integrando Gitleaks en el pipeline y haciendo que falle al detectar algún secreto en el código.
El siguiente pipeline de Jenkins descarga el código del repositorio, lo analiza con Gitleaks; si este descubre alguna credencial, detiene la ejecución y no realiza el despliegue.
pipeline {
agent any
environment {
// Configuración del repositorio Git (usando el nombre del servicio Gitea en Docker)
BRANCH_NAME = 'develop'
REPO_URL = 'http://172.17.0.1:3000/admin/webapp.git'
GIT_CREDENTIALS_ID = 'gitTeaUser'
// Versión de Gitleaks a descargar
GITLEAKS_VERSION = '8.30.1'
// Para Linux x86_64 (el más común en agentes Jenkins)
GITLEAKS_ARCH = 'linux_x64'
GITLEAKS_TAR = "gitleaks_${GITLEAKS_VERSION}_${GITLEAKS_ARCH}.tar.gz"
GITLEAKS_URL = "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/${GITLEAKS_TAR}"
// Directorio donde se instalará Gitleaks (dentro del workspace)
GITLEAKS_HOME = "${WORKSPACE}/gitleaks_bin"
GITLEAKS_BIN = "${GITLEAKS_HOME}/gitleaks"
}
stages {
// 1. Clonar el repositorio
stage('Checkout') {
steps {
script {
cleanWs()
checkout scmGit(
branches: [[name: "*/${env.BRANCH_NAME}"]],
userRemoteConfigs: [[
url: env.REPO_URL,
credentialsId: env.GIT_CREDENTIALS_ID
]]
)
}
}
}
// 2. Descargar e instalar Gitleaks (con rutas entre comillas)
stage('Instalar Gitleaks') {
steps {
script {
sh """
echo "📦 Creando directorio para Gitleaks: ${GITLEAKS_HOME}"
mkdir -p "${GITLEAKS_HOME}"
echo "⬇️ Descargando Gitleaks ${GITLEAKS_VERSION} desde GitHub..."
curl -L -o "${GITLEAKS_HOME}/${GITLEAKS_TAR}" "${GITLEAKS_URL}"
# Verificar que el archivo se descargó
if [ ! -f "${GITLEAKS_HOME}/${GITLEAKS_TAR}" ]; then
echo "❌ Error: No se pudo descargar Gitleaks"
exit 1
fi
echo "📂 Extrayendo el binario en ${GITLEAKS_HOME}..."
tar -xzf "${GITLEAKS_HOME}/${GITLEAKS_TAR}" -C "${GITLEAKS_HOME}"
echo "🔧 Haciendo ejecutable el binario..."
chmod +x "${GITLEAKS_BIN}"
echo "✅ Gitleaks instalado correctamente en ${GITLEAKS_BIN}"
"""
}
}
}
// 3. Análisis con Gitleaks (escanea el código clonado)
stage('Análisis con Gitleaks') {
steps {
script {
sh """
echo "🔍 Ejecutando Gitleaks en el repositorio..."
"${GITLEAKS_BIN}" detect --source . --verbose --no-git
GITLEAKS_EXIT=\$?
if [ \$GITLEAKS_EXIT -ne 0 ]; then
echo "❌ Gitleaks ha encontrado secretos. Deteniendo el pipeline."
exit 1
else
echo "✅ No se encontraron secretos. Continuando..."
fi
"""
}
}
}
// 4. Compilación (simulada)
stage('Compilación (Simulada)') {
steps {
script {
echo "🛠️ Iniciando compilación simulada del proyecto..."
sh 'echo " - Compilando código fuente..."'
sh 'echo " - Ejecutando pruebas unitarias..."'
sh 'echo " - Generando artefactos..."'
sleep time: 5, unit: 'SECONDS'
echo "✅ Compilación simulada completada con éxito."
}
}
}
// 5. Despliegue a producción (simulado)
stage('Despliegue a Producción (Simulado)') {
steps {
script {
echo "🚀 Iniciando despliegue a producción (simulado)..."
sh 'echo " - Empaquetando aplicación..."'
sh 'echo " - Subiendo artefactos al servidor..."'
sh 'echo " - Reiniciando servicios..."'
sleep time: 5, unit: 'SECONDS'
echo "✅ Despliegue a producción simulado completado."
echo "🎉 Pipeline finalizado exitosamente."
}
}
}
}
post {
success {
echo "✅ ¡Pipeline exitoso! El proyecto ha sido compilado y desplegado (simulación)."
}
failure {
echo "❌ El pipeline ha fallado. Revisa los logs para más detalles."
}
always {
echo "🏁 Pipeline finalizado. Estado: ${currentBuild.currentResult}"
// Limpieza opcional del binario descargado (descomentar si se desea)
// sh "rm -rf \"${GITLEAKS_HOME}\""
}
}
}


Como vemos, el pipeline no continúa, ya que detecta credenciales.
Creación de hook local
Para crear un hook local, accedemos al directorio .git del proyecto:

Dentro de la carpeta hooks debemos crear un archivo llamado pre-push sin extensión.
cd /var/lib/gitea/repositories/<usuario>/<repositorio>.git/hooks/
nano pre-push
Creamos el script a ejecutar al subir cambios; si Gitleaks encuentra un secreto, debe salir un error y rechazar el push.
#!/bin/bash
# Hook pre-push simple: escanea todo el directorio actual con Gitleaks
GITLEAKS_BIN="${GITLEAKS_BIN:-gitleaks}"
echo "🔍 Escaneando todos los archivos del repositorio (incluyendo historial)..."
# Escaneamos todo el repositorio (archivos actuales + historial con --no-git? no, usamos --source . pero eso escanea solo archivos actuales)
# Para escanear el historial de commits, Gitleaks debe ejecutarse con --source . y --no-git NO se usa, o se usa sin --no-git
# Pero sin --no-git, Gitleaks escanea el historial de Git directamente.
# Esa es la forma más simple y efectiva para un hook local:
$GITLEAKS_BIN detect --source . --verbose
GITLEAKS_EXIT=$?
if [ $GITLEAKS_EXIT -ne 0 ]; then
echo "❌ Gitleaks ha detectado secretos en el repositorio. Push bloqueado."
echo " Utiliza 'git push --no-verify' para forzar (no recomendado)."
exit 1
else
echo "✅ Sin secretos detectados. Continuando..."
exit 0
fi
Al intentar subir cambios al repositorio, Gitleaks impide la operación, ya que detecta tokens en el proyecto.


Con esto evitamos que sean subidos al repositorio tokens y claves de muchos de los servicios web y cloud.