Configurare Nagios per ricevere Trap SNMP

18

nagios

Per sua stessa natura, Nagios funziona generalmente in maniera “attiva”, andando ad eseguire lui stesso i check verso gli host remoti, tramite script già forniti o custom, oppure interrogando direttamente un demone NRPE presente sulla macchina remota, e che in genere esegue check locali.

Nagios, però, può essere configurato per eseguire dei check “passivi”, ovvero fare in modo che un check che giri, possa essere messo in stati particolari da programmi estetrni. Questo è quello che normalmente succede quando si lavora sull’interfaccia web e si imposta, per esempio, un Acknowledge su un servizio, o si disabilitano le notifiche.

La cosa interessante che andremo a fare in questo tutorial è un’ulteriore step. In pratica faremo in modo che non solo il server su cui gira Nagios possa ricevere delle trap SNMP, ma che Nagios stesso reagisca, in maniera predeterminata, a queste trap.

Facciamo un’esempio pratico (sarà poi quello utilizzato nel tutorial, e che è stato personalmente testato da me): un bilanciatore hardware F5 è stato configurato per lanciare delle trap verso una macchina Nagios. Questo bilanciatore invia non solo trap relative al suo stato, ma anche delle trap che indicano lo stato di un host reale bilanciato.
In pratica, quello che si otterrà è il seguente flusso di eventi:

  1. L’host reale ha qualche problema, e va in down (fisicamente, o anche il solo servizio bilanciato dall’F5)
  2. Il bilanciatore se ne accorge, disabilita il reale dal pool legato al VIP (Virtual IP)
  3. Il bilanciatore manda una trap verso il server su cui gira Nagios, identificando che un particolare host va in down
  4. Il server cattura la trap, la interpreta, ed inietta direttamente in Nagios un comando
  5. Nagios mette un particolare servizio in stato CRITICO, scatenando anche le notifiche del caso

In questo caso vediamo che non ci sono latenze dovute al timeslice di check di Nagios, ma la notifica è immediata alla verifica del problema.

Prima di entrare nel vivo del tutorial, tengo a precisare non verrà trattata l’installazione e/o la configurazione di Nagios (se non per quanto riguarda le parti relative al tutorial stesso), e l’ambiente su cui è stato testato il tutto gira attualmente con questo OS/questi software:

  • Debian GNU/Linux 6.0
  • Nagios3 presente sui repository Debian (Nagios 3.2.1-2)

Quindi farò riferimento ai path di default di questo sistema.
Bando alle ciance, andiamo ad incominciare 🙂

 

Configurare il sistema per ricevere le trap SNMP

Il primo passo è quello di far si che il nostro server (sul quale già sta girando Nagios) possa ricevere delle trap SNMP.
Niente di più semplice, dovreste avere già installato il pacchetto snmpd, nel caso in cui non lo fosse, un semplice

# apt-get install snmpd

vi risolverà il problema.
Questo pacchetto contiene un demone in grado di ricevere delle trap snmp. Per configurarlo editate il file /etc/default/snmpd aggiungendo/modificando le seguenti variabili:

TRAPDRUN=yes
TRAPDOPTS='-On -u snmptt -p /var/run/snmptrapd.pid'

Facendola breve diciamo di far partire il demone per le trap (TRAPDRUN=yes) e lo facciamo lanciare con le seguenti opzioni:

  • -On     Fa si che il demone usi gli OID in formato numerico, ed evita che il traduttore debba eseguire la traduzione dal formato testuale a quello numerico
  • -u snmptt     Fa girare il demone con l’utente snmptt
  • -p /var/run/snmptrapd.pid     Definisce il PIDfile in cui andare a scrivere il pid del processo

Andiamo quindi a definire cosa il demone snmptrapd deve fare alla ricezione di una trap. Modifichiamo quindi il file
/etc/snmp/snmptrapd.conf inserendo le seguenti direttive alla fine:

disableAuthorization yes
traphandle default /usr/sbin/smptt

In questo caso, diciamo al demone di disattivare l’autenticazione per l’invio delle trap (per questo tutorial useremo il metodo KISS: Keep It Simple and Stupid), e diciamo al demone di prendere tutte le trap e girarle al software /usr/sbin/smptt (di cui parleremo a breve).
Aspettiamo a riavviare il demone poiché dobbiamo prima assicurarci di aver installato SNMPTT.

 

Configurare il traduttore di trap SNMPTT

Il traduttore è una parte fondamentale. E’ quel software che si occupa, una volta ricevuta la trap, di interpretarla, tradurla e scriverla da qualche parte.
La traduzione viene fatta utilizzando dei file .MIB che altro non sono che dizionari contenenti un riferimento TRAP -> MESSAGGIO.
Praticamente tutti i produttori di hardware che emettono trap SNMP forniscono i file .MIB necessari alla traduzione, e la F5 non è da meno.

Intanto installiamo il traduttore:

# apt-get install snmptt

Una volta installato, andiamo a modificare il file di configurazione /etc/snmp/snmptt.ini con i seguenti parametri:

mode = standalone          # Questo perché viene invocato da snmptrapd e non deve girare come demone
dns_enable = 0             # Evitiamo che risolva l'hostname per ogni trap che gli arriva
strip_domain = 0           # Diciamogli di non rimuovere il dominio dall'eventuale hostname
net_snmp_perl_enable = 1   # Può utilizzare il perl la traduzione
translate_value_oids = 1   # Traduce gli OID in formato testuale leggibile breve
translate_enterprise_oid_format = 1   # come sopra
translate_trap_oid_format = 1         # come sopra
translate_varname_oid_format = 1      # come sopra
log_enable = 1             # Abilita il logging delle trap
syslog_enable = 1          # Abilita il logging delle trap sul syslog
syslog_level = info        # Definisce il livello di logging per le trap su syslog

A questo punto portiamo sulla macchina i vari files .MIB relativi all’hardware che andrà a scatenare le trap e traduciamo questi file in formato comprensibile con snmptt. Nulla di più semplice:

# mkdir /etc/snmp/mibs    # In questa directory metteremo tutti i mib tradotti
# snmpttconvertmib --in=F5-BIGIP-COMMON.mib --out=F5-BIGIP-COMMON.conf
# mv F5-BIGIP-COMMON.conf /etc/snmp/mibs/

 

Lanciamo il comando per tutti i MIB che ci fornisce il produttore.
A questo punto, riapriamo il file di configurazione di snmptt (/etc/snmp/snmptt.ini) e terminiamo la configurazione aggiungendo/modificando alla fine:

snmptt_conf_files = <<END
/etc/snmp/snmptt.conf
/etc/snmp/mibs/F5-BIGIP-COMMON.conf
END

Riga per riga, andiamo a mettere tutti i file .conf che abbiamo generato con smpttconvertmib. A questo punto possiamo restartare il demone SNMPD (così da far partire il gestore di trap) e verificare che sia effettivamente partito:

# /etc/init.d/snmpd restart
# cat /var/run/snmptrapd.pid
7464

Perfetto, mettiamoci in tali sul file del syslog (per default il /var/log/messages) e dovremmo iniziare a veder passare le trap:

# tail -f /var/log/messages
Sep 20 11:23:40 nagios-mi snmptt[111]: .1.3.6.1.4.1.3375.2.4.0.29 Normal "Status Events" 192.168.0.1 - The system is in an unusable situation. AUDIT - user admin - RAW: httpd(mod_auth_pam): user=admin(admin) partition=[All] level=Administrator tty=1 host=10.10.0.1 attempts=1 start=\"Tue Sep 20 11:03:00 2011\" end=\"Tue Sep 20 11:23:30 2011\".

Ottimo, riceviamo le trap, ora dobbiamo trovare il modo di dire a Nagios che questa trap ha un significato, dirgli quale, e di scatenare un evento… procediamo 😀

 

Catturare le trap

Ci viene in aiuto un’ottimo tool di nome SEC. Questo tool, in maniera generale, permette di analizzare live il contenuto di un file (quindi resta in ascolto ed analizza i nuovi contenuti) e di eseguire determinate operazioni a verificarsi di particolari eventi.
Nel nostro caso, lo metteremo in ascolto sul file in cui vengono slogate le trap /var/log/messages e, con il match su di una particolare RegExp, viene lanciato uno script con determinati parametri.
SEC è uno script in perl, ma ne esiste comunque una versione pacchettizzata per debian, dunque:

# apt-get install sec

Una volta installato, andiamo a modificare il file di configurazione /etc/sec.conf, inserendo i seguenti parametri:

type=Single
ptype=RegExp
pattern=.*(Normal|INFORMATIONAL|MINOR|WARNING|SEVERE|MAJOR|CRITICAL)\ \"Status Events\"\ (\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b)\ \-\ (A service is detected (UP|DOWN)\.\ Pool\ member\ (\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b)(.*)|(.*))
desc=snmptrap received from $2
action=shellcmd /usr/lib/nagios/eventhandlers/snmptraphandling.sh $2 $1 "$3" $4 $5

In pratica viene detto a SEC di eseguire la “action” quando un testo fa match con la regular expression definita in pattern. Senza stare li a parlare di regular expression (potremmo andare avanti per giorni e giorni), se arriva una trap SNMP con il seguente testo:

Sep 20 11:23:40 nagios-mi snmptt[111]: .1.3.6.1.4.1.3375.2.4.0.29 Normal "Status Events" 192.168.0.1 - The system is in an unusable situation. AUDIT - user admin - RAW: httpd(mod_auth_pam): user=admin(admin) partition=[All] level=Administrator tty=1 host=10.10.0.1 attempts=1 start=\"Tue Sep 20 11:03:00 2011\" end=\"Tue Sep 20 11:23:30 2011\".

otteniamo in output le seguenti variabili:

$1 = Normal
$2 = 192.168.0.1
$3 = The system is in an unusable situation. AUDIT - user admin - RAW: httpd(mod_auth_pam): user=admin(admin) partition=[All] level=Administrator tty=1 host=10.10.0.1 attempts=1 start=\"Tue Sep 20 11:03:00 2011\" end=\"Tue Sep 20 11:23:30
$4 =
$5 =

Come vediamo le ultime due variabili sono vuote. Nel caso, invece, ci arrivi una trap formata in quest’altra maniera (che indica lo stato UP/DOWN di un server fisico controllato dal bilanciatore):

Sep 20 11:47:33 nagios-mi snmptt[111]: .1.3.6.1.4.1.3375.2.4.0.10 Normal "Status Events" 192.168.0.1 - A service is detected DOWN. Pool member 192.168.0.100:18009 monitor status down. 192.168.0.100 18009

otteniamo, invece, in output le seguenti variabili:

$1 = Normal
$2 = 192.168.0.1
$3 = A service is detected DOWN. Pool member
$4 = DOWN
$5 = 192.168.0.100

In quest’altro caso le ultime due variabili sono valorizzate ed identificano, rispettivamente, lo stato del reale (UP o DOWN) ed il reale in question (192.168.0.100).

Ovviamente, questa RegExp è stata costruita in funzione di come SNMPTT, con i MIB forniti da F5, traduce le trap. Hardware differente, con MIB differenti, tradurranno le trap in maniera differente, e sarà quindi necessario andare a trovare una RegExp funzionante per quella casistica.

Ne approfitto per segnalare il link http://gskinner.com/RegExr/ veramente molto comodo per scrivere e testare le RegExp.

Quindi, abbiamo intercettato le trap con SEC, ed eseguiamo questo script /usr/lib/nagios/eventhandlers/snmptraphandling.sh passandogli le 5 variabili ottenute dalla RegExp, siano esse valorizzate o meno. Ma cosa fa questo script?

 

snmptraphandling.sh

Ho scritto personalmente questo script, basandomi su un’idea di Francois Meehan, autore di uno script python simile ma meno specializzato.

Potete scaricarlo da qui: snmptraphandling.zip

Questa versione in bash accetta in ingresso le seguenti variabili (nel seguente ordine):

HOST: Obbligatoria, identifica l’host che ha inviato la trap
SEVERITY: Obbligatoria, identifica il “peso” della trap (Normal, critical, etc.) così come viene definita da F5
“DATA”: Obbligatoria dentro i doppi apici. Contiene un testo che identifica meglio la trap, una descrizione
UP|DOWN: Opzionale, identifica lo stato di un reale
ALARMEDHOST: Opzionale, identifica l’host al quale viene applicata la variabile precedente.

Intanto lo script definisce, a seconda della SEVERITY, che valori applicare al Nagios.
Inoltre, nel caso vengano specificate anche le ultime due variabili, esegue operazioni differenti per scatenare allarmi specifici.

Ma come dialoga con Nagios? Semplicissimo, costruisce un comando ad-hoc interpretabile da Nagios, e lo inetta nel file

/var/lib/nagios3/rw/nagios.cmd

Questo file è specializzato per inviare segnali a Nagios e fargli eseguire operazioni particolari.

In pratica, all’arrivo di una trap viene scatenato un evento indirizzato all’host $HOST, per un servizio chiamato:

snmp_trap_handling_$HOST-…. Nel caso in cui non siano specificate le ultime 2 variabili
snmp_trap_handling_$ALARMED_HOST Nel caso in cui siano specificate le ultime 2 variabili.

Ma prendiamo in mano un’esempio completo, così da essere più chiari.
Ci arriva dal bilanciatore, per esempio, una trap SNMP che ci identifica che un’host è andato giù; all’interno del file
/var/log/messages verrà scritto (da SNMPTT) il seguente messaggio:

Sep 20 11:47:33 nagios-mi snmptt[111]: .1.3.6.1.4.1.3375.2.4.0.10 Normal "Status Events" 192.168.0.1 - A service is detected DOWN. Pool member 192.168.0.100:18009 monitor status down. 192.168.0.100 18009

SEC vedrà che questo testo fa match con la RegExp che gli abbiamo applicato, e lancerà questo comando:

/usr/lib/nagios/eventhandlers/snmptraphandling.sh 192.168.0.1 Normal \
"A service is detected DOWN. Pool member" DOWN 192.168.0.100

Lo script prenderà questi valori, li andrà ad elaborare (per esempio, cercando nelle configurazioni di nagios, andrà a tradurre 192.168.0.1 con bil-f5, che altro non è che il nome dell’host specificato in nagios) ed inietterà il seguente testo nel file
/var/lib/nagios3/rw/nagios.cmd:

[1316513822] PROCESS_SERVICE_CHECK_RESULT;bil-f5;snmp_trap_handling_192.168.0.100;2;A service is detected DOWN. Pool member 192.168.0.100:18009 monitor status down. 192.168.0.100

Questo testo fa si che il servizio “snmp_trap_handling_192.168.0.100” venga applicato lo stato 2, ovvero il CRITICAL per Nagios.

Configurare Nagios

Per configurare il Nagios, andremo a creare 3 strutture nuove: la prima è un servizio template che funziona in passivo e che viene usato per creare qualsiasi servizio relativo alle trap snmp; la seconda è l’host che identifica il bilanciatore; la terza è il servizio vero e proprio che verrà messo in critical o meno all’arrivo della trap.
Quindi:

define service {
name generic-snmptrap
active_checks_enabled 1
passive_checks_enabled 1 ; Passive service checks are enabled
is_volatile 1
initial_state o
check_period never
notification_interval 120
notification_options w,u,c,r
notification_period 24x7
check_command return-ok
max_check_attempts 1
check_freshness 0
stalking_options o,w,u,c
register 0 ; Not register. Its just a template
}

Notiamo alcune configurazioni particolari:

passive_checks_enabled 1 Determina che il servizio risponde a check passivi

active_checks_enabled 1 Attiva anche i check attivi. Questo è stato fatto solo perché personalmente trovo che
Nagios debba sempre mostrare uno stato completamente verde. Disattivando i
check attivi, nel TacticalOverview di Nagios avremmo un host segnalato in rosso.

check_period never Non vengono mai schedati check per questo servizio (questo perché il servizio
risponde a delle trap e non esegue direttamente i check)

check_command return-ok Attivando i check attivi, è necessario definite un check_command. Ho usato
return-ok che è un check standard di Nagios che ritorna sempre un stato OK

stalking_options o,w,u,c Questo serve per evitare che mille trap dello stesso tipo vadano a saturare il
Nagios

A questo punto definiamo l’host:

define host{
use generic-host
host_name bil-f5
alias bil-f5
address 192.168.0.1
}

ed infine il servizio:

define service{
use generic-snmptrap
host_name bil-f5
service_description snmp_trap_handling_192.168.0.100
}

Vediamo quindi che, il match che esegue il Nagios, è sulla descrizione del servizio.

 

Conclusioni

Abbiamo infine visto il giro del fumo. Sembrano tante parole ed il tutto molto complicato, ma vi assicuro che, una volta implementato, va tutto liscio come l’olio.

Buon lavoro 🙂

Utente Linux/Unix da più di 20 anni, cerco sempre di condividere il mio know-how; occasionalmente, litigo con lo sviluppatore di Postfix e risolvo piccoli bug in GNOME. Adoro tutto ciò che può essere automatizzato e reso dinamico, l’HA e l’universo container. Autore dal 2011, provo a condividere quei piccoli tips&tricks che migliorano il lavoro e la giornata.