Kill CPU Killers
Internet es una selva, dejas un servidor web y las peticiones
extrañas no tardan en llegar. Por ejemplo, en el servidor de la escuela
nos piden cosas de drupal, wordpress y demás aplicaciones que no
tenemos instaladas. Hay bots que se dedican a buscar vulnerabilidades
por Internet. Ok, normal.
El problema es que algunas de esas
máquinas molestan mucho. Me he encontrado con que algunas peticiones
dejan a nuestros procesos http consumiendo mucha CPU. Además, mientras
hacen el tonto no atienden a nadie mas que al atacante. Y el ancho de
banda que consumen no es despreciable.
Problema: en
cuanto recibimos unas cuantas de estas peticiones, todos nuestros
procesos http están haciendo el tonto y no atienden a nadie. Se ha
producido una denegación de servicio.
Solución: Después de buscar en la documentación de Apache, no encuentro cómo evitar el abuso. Así que tomo medidas para abortar el abuso lo antes posible.
- Utilizando el módulo por defecto de Apache MPM Prefork:
- Desactivamos la conexiones KeepAlive
- Ajustamos el Timeout a un valor más reducido
- Limitamos MaxClients a un número razonable, que evite saturar nuestra máquina con procesos http
- MaxRequestPerChild 1, para que cada petición http sea atendida por un proceso que muere al terminar la petición. Bajo rendimiento pero aseguramos el mayor aislamiento entre peticiones.
[root@proxy root]# crontab -l
# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (/tmp/crontab.30508 installed on Fri Feb 24 22:16:08 2006)
# (Cron version -- $Id: crontab.c,v 2.13 1994/01/17 03:20:37 vixie Exp $)
TERM = xterm
0-59 * * * * /root/bin/kck apache 5 20 /root/kck.log 2>>/root/kck_error.log
Script kck
#!/bin/bash
# kck - Kill CPU Killers by Victor Carceler
#
# This script is under GNU General Public License
#
# Abstract:
#
# Looks for most CPU consuming processes, and if they
# are from specified user and his CPU time is
# over the limit, kck kills them.
#
# kck <user> <cputime> <n>
#
# <user> Username of the processes to kill (apache)
# <cputime> Time limit in seconds
# <n> Number of most CPU consuming processes to kill
# <logfile> Where to log killed PIDs
if [ $# -ne 4 ]
then
echo "USAGE: $0 <user> <cputime> <n>";
echo "<user> Username of the processes to kill (apache)"
echo "<cputime> Time limit in seconds"
echo "<n> Number of most CPU consuming processes to kill"
echo "<logfile>" Where to log killed PIDs
exit 1
fi
n=`expr 7 + $3`
for linea in `top -b -n 1 | head -n $n | tail -n $3 | sed "s/^ *//" | sed 's/ */:/g' | sed 's/\./:/g' | grep -E "^[0-9]+:$1"`
do
pid=`echo -n $linea | cut -d ':' -f 1`
minutos=`echo -n $linea | cut -d ':' -f 13`
segundos=`echo -n $linea | cut -d ':' -f 14`
segundos=`expr $minutos \* 60 + $segundos`
if [ $segundos -gt $2 ]
then
timestamp=`date`
kill $pid
echo "$timestamp -> PID: $pid TIEMPO CPU: $segundos" >>$4
fi
done
Más información
kck nos ha resuelto el problema, pero antes de usarlo conviene asegurarse de que allí donde se va a utilizar funciona correctamente. En especial hay que comprobar que la versión de top que se utiliza muestra 7 líneas de cabecera antes de listar los procesos. Y evidentemente que las columnas de información de los procesos están en el mismo orden que en el top standard.
Cuidado: Cuando root utiliza kck puede matar cualquier proceso.
Desde que ayer por la noche dejé funcionando kck, ya se han matado a los primeros procesos de apache.
[root@proxy root]# tail kck.log
Fri Feb 24 23:49:00 CET 2006 -> PID: 23911 TIEMPO CPU: 9
Sat Feb 25 01:16:00 CET 2006 -> PID: 32467 TIEMPO CPU: 6
Sat Feb 25 05:37:01 CET 2006 -> PID: 7423 TIEMPO CPU: 34
Sat Feb 25 10:18:00 CET 2006 -> PID: 11638 TIEMPO CPU: 12
Sat Feb 25 10:38:00 CET 2006 -> PID: 11961 TIEMPO CPU: 45