Actualizar puede ser una tarea simple y hasta divertida cuando se tratan de unos pocos servidores, pero ya no tanto cuando el número comienza a ascender! Por lo tanto la idea de esta entrada es definir un mecanismo que nos permita:
-Identificar entre actualizaciones de seguridad y el resto.
-Automatizar los avisos de actualizaciones.
El modelo es el siguiente:
-Utilizamos nagios para recolectar y presentar la información.
-No buscaremos actualizaciones cada 5 minutos, las actualizaciones no salen con tanta frecuencia por lo tanto estaríamos consumiendo ancho de banda de manera innecesaria. En el esquema planteado los servidores buscaran sus actualizaciones una vez en el día, y el resto del día mostraran los datos de esa recolección hasta que sean actualizados.
-Tendremos 2 scripts:
- updateNombreDelSO.pl que dependerá del sistema operativo y será el que se ejecute automáticamente una vez al día para recolectar las actualizaciones disponibles. Este script generará el segundo.
- check_actualizaciones.sh que será el script que ejecuté nrpe en los servidores, bajo la demanda del servidor corriendo nagios. Este script es la salida del primero, solo imprime la cantidad de actualizaciones pendientes de seguridad y extra, y un código de salida acorde a la situación.
updateUbuntu.pl
#!/usr/bin/perl
$STATUS_OK=0;
$STATUS_WARNING=1;
$STATUS_CRITICAL=2;
$STATUS_UNKNOWN=3;
$PATCHS=`/usr/lib/update-notifier/apt-check 2>&1`;
@A=split(';',$PATCHS);
$SALIDA="#!/bin/bash\n";
$EXIT=$STATUS_UNKNOWN;
$FILE="/usr/lib/nagios/plugins/check_actualizaciones.sh";
if($A[0] eq "0" and $A[1] eq "0")
{
open(F,">$FILE");
print F "$SALIDA"."echo \"Existen ".$A[0]." actualizaciones.\"\n";
print F "exit $STATUS_OK";
close(F);
chmod (0777,$FILE);
exit;
}
if($A[0] > 0)
{
$SALIDA = $SALIDA . "echo \"ERROR - Existen ".$A[0]." actualizaciones de seguridad y ".$A[1]." extras\"\n";
$EXIT = $STATUS_CRITICAL;
}
else
{
$SALIDA = $SALIDA . "echo \"WARNING - Existen ".$A[1]." actualizaciones extras.\"\n";
$EXIT = $STATUS_WARNING;
}
open(F,">$FILE");
print F $SALIDA;
print F "exit $EXIT";
close(F);
chmod (0777,$FILE);
$STATUS_OK=0;
$STATUS_WARNING=1;
$STATUS_CRITICAL=2;
$STATUS_UNKNOWN=3;
$PATCHS=`/usr/lib/update-notifier/apt-check 2>&1`;
@A=split(';',$PATCHS);
$SALIDA="#!/bin/bash\n";
$EXIT=$STATUS_UNKNOWN;
$FILE="/usr/lib/nagios/plugins/check_actualizaciones.sh";
if($A[0] eq "0" and $A[1] eq "0")
{
open(F,">$FILE");
print F "$SALIDA"."echo \"Existen ".$A[0]." actualizaciones.\"\n";
print F "exit $STATUS_OK";
close(F);
chmod (0777,$FILE);
exit;
}
if($A[0] > 0)
{
$SALIDA = $SALIDA . "echo \"ERROR - Existen ".$A[0]." actualizaciones de seguridad y ".$A[1]." extras\"\n";
$EXIT = $STATUS_CRITICAL;
}
else
{
$SALIDA = $SALIDA . "echo \"WARNING - Existen ".$A[1]." actualizaciones extras.\"\n";
$EXIT = $STATUS_WARNING;
}
open(F,">$FILE");
print F $SALIDA;
print F "exit $EXIT";
close(F);
chmod (0777,$FILE);
El script es bastante, sencillo, "/usr/lib/update-notifier/apt-check" nos devuelve una linea de la forma act_seguridad;act_extras, que separamos con split y guardamos así el número de actualizaciones de seguridad en $A[0] y el número de actualizaciones extras en $A[1]. Luego de eso simplemente definimos la salida según las actualizaciones que haya para hacer. La salida de este script es un archivo bash con el formato:
#!/bin/bash
echo "ERROR - Existen 3 actualizaciones de seguridad y 2 extras"
exit 2
Este archivo es el que ejecutará nrpe cada vez que nagios consulte por el plugin, por lo tanto debemos agregarlo al archivo de configuracion de nrpe:
#echo "command[check_actualizaciones]=/usr/lib/nagios/plugins/check_actualizaciones.sh">> /etc/nagios/nrpe.cfg
Ahora nos encargamos de que ĺa recolección de actualizaciones se haga una vez al día:
#echo "@daily root /path/to/script/updateUbuntu.pl" >> /etc/crontab
No olvidarse de reiniciar nrpe una vez que se agregue la linea y se ejecute manuelmente por primera vez "/path/to/script/updateUbuntu.pl".
Para este script necesitamos instalar un agregado de yum, ejecutar como root: "yum -y install yum-security" .
#!/usr/bin/perl
$STATUS_OK=0;
$STATUS_WARNING=1;
$STATUS_CRITICAL=2;
$STATUS_UNKNOWN=3;
$SALIDA="#!/bin/bash\n";
$EXIT=$STATUS_UNKNOWN;
$FILE="/usr/lib/nagios/plugins/check_actualizaciones.sh";
@PATCHS=`yum -q --security check-update 2>/dev/null`;
$A[0]=0;
$A[1]=0;
foreach $i (@PATCHS)
{
$A[0]=$A[0]+1;
}
@PATCHS=`yum -q check-update 2>/dev/null`;
foreach $i (@PATCHS)
{
$A[1]=$A[1]+1;
}
if($A[0] eq "0" and $A[1] eq "0")
{
open(F,">$FILE");
print F "$SALIDA"."echo \"Existen ".$A[0]." actualizaciones.\"\n";
print F "exit $STATUS_OK";
close(F);
chmod (0777,$FILE);
exit;
}
if($A[0] > 0)
{
$SALIDA = $SALIDA . "echo \"ERROR - Existen ".$A[0]." actualizaciones se seguridad y ".$A[1]." extras\"\n";
$EXIT = $STATUS_CRITICAL;
}
else
{
$SALIDA = $SALIDA . "echo \"WARNING - Existen ".$A[1]." actualizaciones extras.\"\n";
$EXIT = $STATUS_WARNING;
}
open(F,">$FILE");
print F $SALIDA;
print F "exit $EXIT";
close(F);
chmod (0777,$FILE);
$STATUS_OK=0;
$STATUS_WARNING=1;
$STATUS_CRITICAL=2;
$STATUS_UNKNOWN=3;
$SALIDA="#!/bin/bash\n";
$EXIT=$STATUS_UNKNOWN;
$FILE="/usr/lib/nagios/plugins/check_actualizaciones.sh";
@PATCHS=`yum -q --security check-update 2>/dev/null`;
$A[0]=0;
$A[1]=0;
foreach $i (@PATCHS)
{
$A[0]=$A[0]+1;
}
@PATCHS=`yum -q check-update 2>/dev/null`;
foreach $i (@PATCHS)
{
$A[1]=$A[1]+1;
}
if($A[0] eq "0" and $A[1] eq "0")
{
open(F,">$FILE");
print F "$SALIDA"."echo \"Existen ".$A[0]." actualizaciones.\"\n";
print F "exit $STATUS_OK";
close(F);
chmod (0777,$FILE);
exit;
}
if($A[0] > 0)
{
$SALIDA = $SALIDA . "echo \"ERROR - Existen ".$A[0]." actualizaciones se seguridad y ".$A[1]." extras\"\n";
$EXIT = $STATUS_CRITICAL;
}
else
{
$SALIDA = $SALIDA . "echo \"WARNING - Existen ".$A[1]." actualizaciones extras.\"\n";
$EXIT = $STATUS_WARNING;
}
open(F,">$FILE");
print F $SALIDA;
print F "exit $EXIT";
close(F);
chmod (0777,$FILE);
Este script mantiene el mismo concepto, salvo que en lugar de ejecutar un solo programa ejecuta dos, el primero obtiene las actualizaciones de seguridad disponibles y el segundo las extras.
También debemos agregar la linea en el archivo de configuración de nrpe como se explicó antes, así como también la línea en crontab para la ejecución. Reiniciar nrpe y ejecutarlo manualmente la primera vez.
#!/usr/bin/perl
$STATUS_OK=0;
$STATUS_WARNING=1;
$STATUS_CRITICAL=2;
$STATUS_UNKNOWN=3;
@PATCHS=`zypper -q lp 2>/dev/null | grep -i needed`;
$FLAG=0;
$c=0;
$SALIDA="#!/bin/bash\n";
$EXIT=$STATUS_UNKNOWN;
$FILE="/usr/lib/nagios/plugins/check_actualizaciones.sh";
foreach $i (@PATCHS)
{
$c=$c+1;
@aux=split('\|',$i);
#solo uso los campos 1, 2 y 3
if($i =~ /security/)
{
push(@SEGURIDAD,$aux[1]);
}
else
{
push(@OTROS,$aux[1]);
}
$FLAG=1;
}
if(@SEGURIDAD == 0 and @OTROS == 0)
{
open(F,">$FILE");
print F "$SALIDA"."echo \"Existen ".@SEGURIDAD." actualizaciones.\"\n";
print F "exit $STATUS_OK";
close(F);
chmod (0777,$FILE);
exit;
}
if(@SEGURIDAD > 0)
{
$SALIDA = $SALIDA . "echo \"ERROR - Existen ".@SEGURIDAD." actualizaciones de seguridad y ".@OTROS." extras\"\n";
$EXIT = $STATUS_CRITICAL;
}
else
{
$SALIDA = $SALIDA . "echo \"WARNING - Existen ".@OTROS." actualizaciones extras.\"\n";
$EXIT = $STATUS_WARNING;
}
open(F,">$FILE");
print F $SALIDA;
print F "exit $EXIT";
close(F);
chmod (0777,$FILE);
Nuevamente pero esta vez para openSuSE, también se deben aplicar los puntos de los otros dos casos.
No voy a incluir la configuración de nagios (por tiempo, ya me dio sueño :P, si alguien la precisa la tengo), pero básicamente consiste en definir un servicio y utilizar nrpe para ejecutar remotamente "check_actualizaciones.sh", de esta forma nagios nos estaría avisando cuántas actualizaciones pendientes tenemos y de qué tipo son.
Cabe aclarar que si actualizamos un servidor, las alertas no se irán hasta que no se vuelva a hacer la recolección, pero como esto pasa una vez al día estaríamos viendo alertas el resto del día. Por lo tanto recomiendo que una vez actualizado el servidor se ejecute manualmente el archivo de recolección para que las alarmas se vayan :D.
Concejos, dudas y demás serán bien recibidos!