Problema
Los usuarios que migran a un stack self‑hosted pierden la capa de protección automática que ofrecen los proveedores SaaS. De repente, la responsabilidad de detectar accesos no autorizados recae sobre el propio administrador. En entornos mixtos (Tailscale, VMs en AWS/GCP/Azure, contenedores locales) los logs se dispersan: syslog, CloudTrail, auditd, registros de aplicaciones, etc. Revisarlos manualmente es inviable; los agentes que consumen cada registro consumen recursos y generan ruido. Lo que se necesita es un “cámara de seguridad” centralizada que:
- Recoja eventos críticos de varios orígenes.
- Normalice la información.
- Genere alertas solo cuando el comportamiento se desvía de la norma.
- Lo haga sin depender de IA propietaria ni de configuraciones complejas de SIEM.
Causa
- Falta de correlación – Cada componente escribe en su propio formato. Un intento de fuerza bruta en SSH, un login fallido en la UI de la app y una conexión inesperada en la VPN aparecen en archivos diferentes y rara vez se cruzan.
- Reglas estáticas – Herramientas como Wazuh o Elastic requieren que el operador defina cientos de reglas. En un entorno personal, la sobrecarga de crear y mantener esas reglas supera el beneficio.
- Visibilidad limitada – Los dashboards nativos de los proveedores de nube no envían alertas proactivas a usuarios externos; solo se pueden consultar después de que el daño ya ocurrió.
- Recursos escasos – Los servidores domésticos o los nodos de bajo coste no pueden ejecutar pipelines de análisis pesado 24/7.
Solución
Un enfoque modular basado en tres capas funciona bien en la mayoría de los setups self‑hosted:
1. Recolección ligera con agentes “tail”
Utiliza journalctl -f o tail -F para enviar los últimos eventos a un colector central mediante syslog UDP o un webhook simple. La ventaja es que el agente solo lee los archivos, sin procesar nada.
2. Normalización con un script de “pipeline”
Un script en Bash o Python que recibe líneas crudas, extrae campos clave (timestamp, usuario, IP, tipo de evento) y los convierte a JSON. Mantener la lógica en un único archivo facilita la actualización y evita dependencias pesadas.
3. Regla determinista basada en patrones comunes
En vez de cientos de reglas, define un pequeño conjunto de patrones que cubren la mayor parte de los incidentes:
| Patrón | Acción |
|---|---|
| Más de 5 fallos de login en 1 min por mismo IP | Alertar “brute‑force” |
| Conexión SSH desde IP no presente en whitelist | Alertar “login externo” |
Creación de archivo en directorio sensible (/etc, $HOME/.ssh) fuera de horario |
Alertar “modificación sospechosa” |
| Cambio de clave API sin token de renovación reciente | Alertar “rotación inesperada” |
| Tráfico de red > 1 GB a destinos no catalogados en 10 min | Alertar “exfiltración” |
Los patrones se expresan como expresiones regulares o comparaciones simples dentro del script. Cada coincidencia dispara un webhook a tu canal de notificaciones favorito (Discord, Telegram, correo).
4. Envío de alertas
El webhook puede ser tan sencillo como una petición curl a un endpoint de Discord. El mensaje incluye datos estructurados para que puedas filtrar rápidamente en el cliente.
5. Despliegue con Docker Compose (opcional)
Empaqueta el colector (por ejemplo, rsyslog), el script y un contenedor de cron que reinicie el pipeline cada día. Docker aísla dependencias y permite mover la solución entre máquinas sin cambios.
Cuándo aplicar esta solución
- Entornos personales o de pequeño equipo donde la carga de trabajo es limitada y no se justifica un SIEM completo.
- Aplicaciones heterogéneas (VMs, contenedores, servidores bare‑metal) que comparten una red privada gestionada por Tailscale o VPN.
- Necesidad de alertas en tiempo real sin incurrir en costos de servicios externos.
- Escenarios donde la mayoría de accesos provienen de IPs conocidas y los incidentes son eventos aislados (p.ej., intentos de fuerza bruta, accesos fuera de horario).
No es apropiado cuando:
- Se manejan volúmenes de logs de varios terabytes al día.
- Se requiere cumplimiento normativo estricto (PCI‑DSS, HIPAA) que obliga a auditorías de nivel empresarial.
- El equipo dispone de personal especializado en SIEM y presupuesto para Elastic Stack o Splunk.
Código
#!/usr/bin/env bash
# monitor.sh – pipeline ligero para detección de intrusiones
# Configuración
WHITELIST_IPS=("10.42.0.0/16" "192.168.1.0/24")
ALERT_WEBHOOK="https://discord.com/api/webhooks/XXXXX/XXXXX"
# Función de envío de alerta
alert() {
local title="$1"
local msg="$2"
curl -s -X POST -H "Content-Type: application/json" \
-d "{\"embeds\":[{\"title\":\"$title\",\"description\":\"$msg\"}]}" \
"$ALERT_WEBHOOK" >/dev/null
}
# Detectar 5+ fallos de login en 60 s por IP
tail -F /var/log/auth.log | \
awk '
/Failed password/ {
split($0, a, " ");
for(i=1;i<=NF;i++) if($i=="from") ip=a[i+1];
ts=strftime("%s");
count[ip][ts]++
}
END {
for (ip in count) {
sum=0;
for (t in count[ip]) sum+=count[ip][t];
if (sum>=5) {
printf "%s %s\n", ip, sum > "/dev/stderr"
}
}
}' | while read -r ip cnt; do
alert "Brute‑force detectado" "IP $ip tuvo $cnt intentos fallidos en 1 minuto."
done
# Detectar SSH desde IP no whitelist
tail -F /var/log/auth.log | \
grep "Accepted publickey" | \
while read -r line; do
ip=$(echo "$line" | awk '{for(i=1;i<=NF;i++) if($i=="from") print $(i+1)}')
whitelisted=false
for net in "${WHITELIST_IPS[@]}"; do
if ipcalc -c "$ip" "$net" >/dev/null 2>&1; then
whitelisted=true; break
fi
done
$whitelisted || alert "Login SSH inesperado" "Usuario conectado desde $ip no está en whitelist."
done
Verificación
- Prueba de detección de fuerza bruta – Desde otra máquina, ejecuta
ssh user@hostcon una contraseña incorrecta cinco veces seguidas. Deberías recibir una notificación en Discord en menos de 30 s. - Prueba de whitelist – Añade tu IP a la lista y vuelve a conectar por SSH; no debe generarse alerta. Cambia a una IP fuera de la lista y verifica que la alerta aparezca.
- Revisión de logs – Confirma que
monitor.shestá leyendoauth.logsin errores (systemctl status monitor.servicesi lo ejecutas como servicio). - Carga de CPU – Ejecuta
topmientras el script está activo; el consumo debe mantenerse bajo 2 % en una máquina típica de 2 CPU.
Notas adicionales
- Persistencia: Configura el script como servicio systemd (
/etc/systemd/system/monitor.service) para que arranque automáticamente y se reinicie en caso de fallo. - Escalabilidad: Si la cantidad de fuentes crece, agrega más
tail -Fa la tubería o usarsyslogpara reenviar logs a un socket Unix que el script consuma. - Seguridad del webhook: Usa un token de firma o una URL de un bot privado para evitar que terceros disparen falsas alertas.
- Extensión de patrones: Puedes añadir detección de cambios en archivos críticos usando
inotifywait -m /etc /home/*/.ssh. - Backup de reglas: Mantén el archivo de patrones bajo control de versiones (Git) para revertir cambios accidentalmente dañinos.
Con este enfoque tienes una solución ligera, reproducible y totalmente bajo tu control, adecuada para cualquier entorno self‑hosted que necesite una “cámara de seguridad” sin la complejidad de un SIEM empresarial.