Archivi categoria: Networking

CentOS 6: configurare Nagios per la ricezione delle trap SNMP

In questo post abbiamo visto come configurare Nagios per la ricezione dei check passivi. In quest’altro post, invece, ho spiegato come configurare snmptrapd per la ricezione delle trap SNMP provenienti dai dispositivi monitorati. Adesso vedremo come ricevere su Nagios le suddette trap.

Ingredienti

Oltre a Nagios ed al demone che si occupa della ricezione delle trap (ovvero snmptrapd), è necessario installare sulla macchina che funge da NMS un demone in grado di tradurre le informazioni ricevute in qualcosa di più umanemente comprensibile. Infatti, la difficile interpretazione dei dati riportati dalle trap SNMP rappresenta, sicuramente, uno dei maggiori ostacoli che un sysadmin deve affrontare. Il demone che svolge tale mansione prende il nome di snmptt.

Logica di funzionamento

A grandi linee, il giro del fumo si può riassumere come segue: il dispositivo monitorato genera, di sua sponte, una trap SNMP per segnalare un qualche tipo di anomalia. Essa verrà, successivamente, inoltrata all’NMS, sul quale è attivo il demone snmptrapd (in ascolto sulla porta UDP/162), il quale si occuperà di “passare” tali informazioni ad snmptt. A questo punto, snmptt “tradurrà” i dati che gli sono stati inviati, provvedendo anche inoltrare il relativo output ad uno scrip Nagios (submit_check_result, che potete scaricare da qui) in grado di carpirne il contenuto ed utilizzare quest’ultimo per aggiornare lo stato del servizio dotato di check passivo. Quanto detto fin’ora è riportato (in modo schematico) nell’immagine sottostante.

snmptt

Configurazione di Nagios

Come al solito, il primo step per la realizzazione del nostro ambiente, consiste nella configurazione dell’NMS. Il servizio di monitoraggio delle trap potrà essere simile al seguente:

 define service{
        use                   local-service
        host_name             localhost
        service_descripion   SNMP TRAP Interceptor
        check_command         check_passive
        passive_checks_enabled  1
        active_checks_enabled   0
        is_volatile             1
        check_freshness         1
        freshness_threshold     600
        flap_detection_enabled  0
        }

mentre il comando check_passive presenterà la seguente struttura:

# 'check_passive' command definition
define command{
        command_name check_passive
        command_line $USER1$/check_dummy 2 "No alerts received in 600 seconds"
}

Configurazione di snmptrapd

Rispetto alla configurazione vista qui, l’unica variazione consiste nell’aggiunta delle seguente direttiva:

traphandle default /usr/sbin/snmptt

e la configurazione in todo dovrà essere simile alla seguente:

traphandle default /usr/sbin/snmptt

authCommunity log,execute,net keypublic
format1 %l-%m-%y %h:%j:%k from %A: %b %P %N %W %v\n
format2 %l-%m-%y %h:%j:%k from %A: %b %P %N %W %v\n

Installazione e configurazione di snmptt

Per installare il software in questione è sufficiente utilizzare yum:

[root@NMS ~]# yum install snmptt net-snmp-perl

Una volta installato, si può procedere con la sua configurazione mediante l’editing del file /etc/snmp/snmptt.ini. Ecco le modifiche da me apportate:

net_snmp_perl_enable = 1
log_system_enable = 1
log_system_file = /var/log/snmptt/snmpttsystem.log

A questo punto occorrerà procedere con la “traduzione” delle MIB SNMP. Le si può pensare come una sorta di DB testuale, in cui è presente una descrizione “human friendly” di alcuni OID, anche per ciò che concerne le trap.

Il software che svolge tale mansione prende il nome di snmpttconvertmib e si potranno convertire trap presenti nelle MIB lanciando il seguente comando:

[root@NMS ~]# for i in *MIB*;do snmpttconvertmib --in=/usr/share/snmp/mibs/$i --out=/etc/snmp/snmptt.conf  --exec='/usr/lib64/nagios/plugins/eventhandlers/submit_check_result $r "SNMP TRAP Interceptor" 1';done

dove i parametri passati a submit_check_result sono:

1) $r, ovvero l’hostname del dispositivo che ha generato la trap;

2) SNMP TRAP Interceptor, ovvero il nome del servizio di Nagios che deve essere aggiornato mediante check passivo;

3) 1, evvero l’exit code da girare all’NMS (che, in tal caso, corrisponderà a WARNING).

Le trap “tradotte” andranno a popolare il file /etc/snmp/snmptt.conf, le cui entry saranno simili alle seguenti:

EVENT ucdShutdown .1.3.6.1.4.1.2021.251.2 "Status Events" Normal
FORMAT This trap is sent when the agent terminates $*
EXEC /usr/lib64/nagios/plugins/eventhandlers/submit_check_result $r TRAP 1 "This trap is sent when the agent terminates $*"
SDESC
This trap is sent when the agent terminates
Variables:
EDESC

Prima di continuare, una piccola nota a margine: per ciò che concerne i dispositivi Cisco, vi consiglio di consultare questo sito (per l’indentificazione ed il download delle MIB) e quest’altro (per la traduzione degli OID).

Inoltre, affinchè lo scrip submit_check_result sia in grado di scrivere all’interno del file nagios.cmd (dove vengono inoltrati tutti i comandi esterni), è necessario sostituire la stringa:

CommandFile="/usr/local/nagios/var/rw/nagios.cmd"

con:

CommandFile="/var/spool/nagios/cmd/nagios.cmd"

A configurazione di snmptt ultimata, possiamo fare in modo che il demone in questione venga eseguito automaticamente al boot:

[root@NMS ~]# chkconfig snmptt on

ed avviarlo:

[root@NMS ~]# service snmptt start

Inoltre, riavviamo snmptrapd per rendere effettive le modifiche apportate in precedenza:

[root@NMS ~]# service snmptrapd restart

e ricarichiamo la configurazione di Nagios:

[root@NMS ~]# service nagios reload

 Test e troubleshooting

La prima cosa da fare per capire se snmptt stia funzionando correttamente consiste nell’abilitazione delle opzioni di debug (presenti all’interno di snmptt.ini). Le direttive coinvolte sono le seguenti:

DEBUGGING = 0
DEBUGGING_FILE = /var/log/snmptt/snmptt.debug

Inoltre, è possibile (e opportuno) inviare al nostro handler una trap di test, recante il seguente formato:

[root@NMS ~]# snmptrap -v 1 -c keypublic 127.0.0.1 '.1.3.6.1.6.3.1.1.5.3' '0.0.0.0' 6 33 '55' .1.3.6.1.6.3.1.1.5.3 s “teststring000”

Se la suddetta trap verrà opportunamente gestita da snmptt e dell’event handler di Nagios (submit_check_result), con il successivo aggiornamento del servizio lato NMS, vorrà dire che il nostro sistema sta funzionando come dovrebbe.

Per ora è tutto. Alla prossima.

CentOS 6: configurare Nagios per la ricezione dei security alert

In questo post abbiamo visto come configurare e gestire i check passivi su Nagios. Ora vedremo come utilizzare tale configurazione per ricevere i security alert relativi agli host monitorati.

nagiosIngredienti

Ovviamente il primo ingrediente è l‘NMS (Nagios), integrato ad NRDP Server. Sulle macchine monitorate è installato NRDP Client, il quale dovrà interagire con un log analyzer in tempo reale (swatch).

Scenario

La topologia utilizzata nell’ambito di questa guida è abbastanza minimale e prevede un server su cui è installato Nagios ed un altro server (da monitorare) che funge da antispam. Si vuole fare in modo che i security alert generati da quest’ultimo vengano inoltrati all’NMS, il quale dovrà successivamente aggiornare lo stato dei check passivi di riferimento, inviando opportune notifiche ai sysadmin.

Configurazione di Nagios

La configurazione dell’NMS è del tutto simile a quella vista qui, ma la riporto per completezza:

define service{
        use                             local-service
        host_name                       server-antispam
        service_description             Antispam Access Denied
        check_command                   check_passive
        passive_checks_enabled          1
        active_checks_enabled           0
        max_check_attempts              1
        is_volatile                     1
        check_freshness                 1
        freshness_threshold             600
        flap_detection_enabled          0
        }

define service{
        use                             local-service
        host_name                       server-antispam
        service_description             Antispam Domain Not Found
        check_command                   check_passive
        passive_checks_enabled          1
        active_checks_enabled           0
        max_check_attempts              1
        is_volatile                     1
        check_freshness                 1
        freshness_threshold             600
        flap_detection_enabled          0
        }

define service{
        use                             local-service
        host_name                       server-antispam
        service_description             Antispam Cannot Find Your Reverse Hostname
        check_command                   check_passive
        passive_checks_enabled          1
        active_checks_enabled           0
        max_check_attempts              1
        is_volatile                     1
        check_freshness                 1
        freshness_threshold             600
        flap_detection_enabled          0
        }

define service{
        use                             local-service
        host_name                       server-antispam
        service_description             Antispam SPF Reject
        check_command                   check_passive
        passive_checks_enabled          1
        active_checks_enabled           0
        max_check_attempts              1
        is_volatile                     1
        check_freshness                 1
        freshness_threshold             600
        flap_detection_enabled          0
        }

define service{
        use                             local-service
        host_name                       server-antispam
        service_description             Antispam Relay Access Denied
        check_command                   check_passive
        passive_checks_enabled          1
        active_checks_enabled           0
        max_check_attempts              1
        is_volatile                     1
        check_freshness                 1
        freshness_threshold             600
        flap_detection_enabled          0
        }

define service{
        use                             local-service
        host_name                       server-antispam
        service_description             Antispam Amavis Blocked
        check_command                   check_passive
        passive_checks_enabled          1
        active_checks_enabled           0
        max_check_attempts              1
        is_volatile                     1
        check_freshness                 1
        freshness_threshold             600
        flap_detection_enabled          0
        }

define service{
        use                             local-service
        host_name                       server-antispam
        service_description             Antispam Spam
        check_command                   check_passive
        passive_checks_enabled          1
        active_checks_enabled           0
        max_check_attempts              1
        is_volatile                     1
        check_freshness                 1
        freshness_threshold             600
        flap_detection_enabled          0
        }

define service{
        use                             local-service
        host_name                       server-antispam
        service_description             Antispam Spammy
        check_command                   check_passive
        passive_checks_enabled          1
        active_checks_enabled           0
        max_check_attempts              1
        is_volatile                     1
        check_freshness                 1
        freshness_threshold             600
        flap_detection_enabled          0
        }

Il comando check_passive, invece, è così definito:

# 'check_passive' command definition
define command{
        command_name check_passive
        command_line $USER1$/check_dummy 0 "No Security Alert"
}

La logica di funzionamento è banale: se un security alert non viene ricevuto entro 600 secondi significa che non vi sono eventi rilevanti e, di conseguenza, lo stato del check passivo tornerà ad essere OK. Inoltre, poichè l’alert deve generare immediatamente una notifica (HARD STATE), è necessario settare il campo max_check_attempts a 1 (anzichè 4 che è il valore di default).

Come ultimo step ricarichiamo la configurazione di Nagios:

[root@NMS ~]# service nagios reload

Configurazione del server antispam

Una volta configurato l’NMS possiamo dedicarci alla configurazione del server da monitorare. In questo caso il lavoro sporco verrà svolto da swatch, il cui compito è quello di analizzare in tempo reale (tail -f) il contenuto del file di log relativo al servizio di antispam (/var/log/maillog), alla ricerca di determinati error code. Ad ogni error code corrisponderà un security alert specifico, e, una volta identificato, verrà richiamato NRDP Client per l’invio dell’evento a Nagios.

Ma bando alle ciance ed ecco la configurazione di swatch:

#SMTP Domain not found
watchfor  /Domain not found/
     echo
     exec "/usr/bin/php /usr/lib/nagios/plugins/send_nrdp.php --url\=http://IPNMS/nrdp --token\=vostrotoken --host\=server-antispam --state\=1 --service\='Antispam Domain Not Found' --output\='$_'"

#SMTP Sender address rejected
watchfor  /Access denied/
     echo
     exec "/usr/bin/php /usr/lib/nagios/plugins/send_nrdp.php --url\=http://IPNMS/nrdp --token\=vostrotoken --host\=server-antispam --state\=1 --service\='Antispam Access Denied' --output\='$_'"

#SMTP Cannot find your reverse hostname
watchfor  /cannot find your reverse hostname/
     echo
     exec "/usr/bin/php /usr/lib/nagios/plugins/send_nrdp.php --url\=http://IPNMS/nrdp --token\=vostrotoken --host\=server-antispam --state\=1 --service\='Antispam Cannot Find Your Reverse Hostname' --output\='$_'"

#SMTP SPF reject
watchfor  /openspf/
     echo
     exec "/usr/bin/php /usr/lib/nagios/plugins/send_nrdp.php --url\=http://IPNMS/nrdp --token\=vostrotoken --host\=server-antispam --state\=1 --service\='Antispam SPF Reject' --output\='$_'"

#SMTP Relay access denied/
watchfor /Relay access denied/
     echo
     exec "/usr/bin/php /usr/lib/nagios/plugins/send_nrdp.php --url\=http://IPNMS/nrdp --token\=vostrotoken --host\=server-antispam --state\=1 --service\='Antispam Relay Access Denied' --output\='$_'"

#SMTP Amavis blocked
watchfor /Blocked/
     echo
     exec "/usr/bin/php /usr/lib/nagios/plugins/send_nrdp.php --url\=http://IPNMS/nrdp --token\=vostrotoken --host\=server-antispam --state\=1 --service\='Antispam Amavis Blocked' --output\='$_'"

#SMTP Spam
watchfor /SPAM/
     echo
     exec "/usr/bin/php /usr/lib/nagios/plugins/send_nrdp.php --url\=http://IPNMS/nrdp --token\=vostrotoken --host\=server-antispam --state\=1 --service\='Antispam Spam' --output\='$_'"

watchfor /SPAMMY/
     echo
     exec "/usr/bin/php /usr/lib/nagios/plugins/send_nrdp.php --url\=http://IPNMS/nrdp --token\=vostrotoken --host\=server-antispam --state\=1 --service\='Antispam Spammy' --output\='$_'"

Nella fattispecie, NRDP Client viene richiamato mediante la direttiva exec, facendo attenzione al carattere = (utilizzato per specificare i dati da inviare a Nagios), poichè trattasi di un carattere speciale per swatch (che quindi dovrà essere munito di escape \).

A questo punto lanciamo il comando:

[root@server-antispam ~]# swatch -c /etc/swatch.conf -t /var/log/maillog --daemon

ed inseriamolo all’interno del file /etc/rc.local (per automatizzare l’esecuzione del suddetto applicativo dopo ogni riavvio).

Test

Per testare il corretto funzionamento della configurazione appena riportata, possiamo, ad esempio, generare un error code 450 (cannot find your reverse hostname).
Lanciamo dunque il comando:

[root@client ~]# telnet server-antispam.vostrodominio.com 25

ed inviamo al server antispam le seguenti direttive:

helo server-antispam.vostrodominio.com
250 server-antispam
mail from:<n.latella@ciao.it>
250 2.1.0 Ok
rcpt to:<n.latella@ciao.ot>
450 4.7.1 Client host rejected: cannot find your reverse hostname, [5.170.*.*]

A questo punto il servizio Antispam Cannot Find Your Reverse Hostname dovrebbe generare un WARNING, segnalando quanto avvenuto mediante email.

Nei prossimi post vedremo come configurare Nagios per la ricezione delle trap SNMP.

Alla prossima.

CentOS 6: configurare Nagios/NRDP per la ricezione dei check passivi

In questo blog ho ampiamente discusso del mio MNS preferito (Nagios), mostrandone le diverse modalità di utilizzo e pubblicando, con una certa frequenza, alcuni plugin (da me realizzati) in grado di tenere sotto controllo un determinato servizio attivo su uno o più dispositivi.

Occorre precisare, però, che fin’ora ho discusso solo ed esclusivamente dei cosiddetti check attivi, ovvero quelli che vengono inizializzati dall’NMS ad intervalli di tempo specifici (di default ogni 5 minuti). Tale configurazione è più che sufficiente nella stragrande maggioranza dei casi, ma ovviamente esistono delle ecezioni.

nagiosUna di queste riguarda, ad esempio, la presenza di un firewall tra Nagios ed il server da tenere sotto controllo, il quale potrebbe bloccare i tentativi di connessione diretti verso quest’ultimo. Un’altra, invece, potrebbe riguardare l’individuazione di eventi totalmente asincroni (ad esempio le trap SNMP oppure i security alert), i quali, per loro natura, non possono essere collezionati mediante del semplice polling.

Per configurare in modo corretto i check passivi, occorre utilizzare alcuni elementi indispensabili:

1) Un tool da integrare a Nagios (NRDP Server) in grado di riconoscere gli eventi generati dai dispositivi monitorati e di girarli all’NMS;

2) Un client (NRDP Client per i sistemi *nix oppure NSCA Client per i sistemi Windows), il cui compito è quello di inviare gli eventi all’NMS.

Logica di funzionamento

NRDP Server è una Web applicaiton sviluppata in PHP, contattabile utilizzando il protocollo HTTP (o, in alternativa, HTTPS). Essa rimane in ascolto su una specifica porta (solitamente la TCP 80, ma dipende dalla configurazione dei Web server), in attesa degli eventi generati dai client NRDP. Nella fattispecie, anche in quest’ultimo caso, parliamo di uno scrip PHP il cui scopo è quello di generare un codice XML (in base ai parametri che gli vengono dati in pasto), da inoltrare al server. A questo punto, dopo aver ricevuto l’evento, il server NRDP popolerà il file nagios.cmd con una stringa che reca il seguente formato:

PROCESS_SERVICE_CHECK_RESULT;host;servicedescription;checkresult;output

ad esempio:

PROCESS_SERVICE_CHECK_RESULT;mysql-server1;test;1;questo è un evento di test

In seguitò verrà generato un file temporaneo all’interno della directory /var/log/nagios/spool/checkresults, il quale verrà poi processato da Nagios per l’aggiornamento dello status del servizio interessato.

Installazione e configurazione di NRDP Server

Per prima cosa scarichiamo il suddetto applicativo e scompattiamo l’archivio:

[root@linuxbox ~]# cd /usr/local

[root@linuxbox ~]# wget https://assets.nagios.com/downloads/nrdp/nrdp.zip

[root@linuxbox local]# unzip nrdp.zip

[root@linuxbox local]# chown -R nagios:nagios /usr/local/nrdp

Creiamo quindi la directory in cui Nagios dovrà salvare i file temporanei (/var/log/nagios/spool/tmp):

[root@linuxbox local]# mkdir /var/log/nagios/spool/tmp

[root@linuxbox local]# chown apache:nagios /var/log/nagios/spool/tmp

[root@linuxbox local]# chmod 770 /var/log/nagios/spool/tmp

Inoltre, poichè NRDP Server gira grazie ad un Web server opportuno (ad esempio Apache), è necessario fare in modo che nella directory /var/log/nagios/spool/checkresults/ (in cui Nagios salverà i risultati dei check attivi e passivi utilizzando dei file temporanei), Apache abbia i diritti di lettura e scrittura:

[root@linuxbox local]# chown apache:nagios /var/log/nagios/spool/checkresults

[root@linuxbox local]# chmod 770 /var/log/nagios/spool/checkresults

A questo punto possiamo dedicarci alla configurazione vera e propria di NRDP Server, editando il file /usr/local/nrdp/server/config.inc.php.

Di seguito riporto quella da me utilizzata:

$cfg['authorized_tokens'] = array(
"vostrotoken",
);
$cfg["nagios_command_group"]="nagios";
// full path to Nagios external command file
$cfg["command_file"]="/var/spool/nagios/cmd/nagios.cmd";
// full path to check results spool directory
$cfg["check_results_dir"]="/var/log/nagios/spool/checkresults";
// full path to directory where temp scratch files can be written
// NOTE: the Apache user need to be able create files here, and the Nagios user needs to read/delete those same files, so the /tmp system directory won't work (it has a sticky bit on it)
$cfg["tmp_dir"]="var/log/nagios/spool/tmp";

Passiamo ora alla configurazione di Apache, creando un file opportuno (nrdp.conf) all’interno della directory /etc/httpd/conf.d, il cui contenuto dovrebbe essere simile al seguente:

Alias /nrdp "/usr/local/nrdp/server"

<Directory "/usr/local/nrdp">
   Options None
   AllowOverride None
   Order allow,deny
   Allow from all
   Order deny,allow
   Deny from all
   Allow from <IP1>
   Allow from <IP2>
   Allow from <IP3>
</Directory>

Come si può notare, ho consentito l’accesso alla suddetta pagina Web solo a determinati indirizzi IP (quelli di management e quelli dei server che devono inviare i check a Nagios/NRDP).

Ricarichiamo la configurazione di Apache per rendere effettive le suddette modifiche:

[root@linuxbox local]# service httpd reload

e finalmente NRDP Server dovrebbe essere attivo e funzionante. Per esserne sicuri al 100% conviene contattare la seguente URL:

http://IPNAGIOS/nrdp

e popolare il campo Token: con quello da noi inserito nella configurazione del server (config.inc.php), lasciando il campo Check Data: inalterato. Se entrambi i check vegnono processati correttamente da NRDP Server significa che il suddetto applicativo sta funzionando come dovrebbe.

Un consiglio: verificate che anche l’invio dei comandi via NRDP Server vada a buon fine (attraverso la sezione Submit Nagios Command:), in modo da scongiurare eventuali blocchi perpetrati da SElinux.

Installazione e configurazione di NRDP Client

Il primo step per mettere in funzione il suddetto client consiste nel copiarlo sui server da monitorare:

[root@linuxbox ~]# scp /usr/local/nrdp/client/send_nrdp.php root@serverdamonitorare:/usr/lib64/nagios/plugins

Una volta fatto ciò si può procedere con l’invio di un check di prova, utilizzando, ad esempio, la seguente sintassi:

[root@linuxbox ~]# /usr/bin/php send_nrdp.php --url=http://IPNAGIOS/nrdp --token="vostrotoken" --host="mysql-server" --state="1" --service="Test" --output="Questo è un evento di test"

Per una maggiore compatibilità con il sistema ospite, consiglio di modificare lo scrip send_nrdp.php, sostituendo il tag di apertura <? con <?php. Inoltre, se si vuole fare un pò di troubleshooting, conviene decommentare alcune parti di codice, ad esempio:

 echo "XML=\n$xml\n";

linea 162;

echo "URL=$theurl\n";

linea 168;

echo "RESULT=\n";
print_r($result);

linee 177 e 178.

Configurazione di Nagios

Come ultimo passo procediamo con la creazione del servizio in grado di ricevere i check passivi, associandolo ad un determinato host.

Ad esempio:

 define service{
        use                   local-service
        host_name             localhost
        service_description   Test
        check_command         check_passive
        passive_checks_enabled  1
        active_checks_enabled   0
        is_volatile             1
        check_freshness         1
        freshness_threshold     600
        flap_detection_enabled  0
        }

In particolare, ho abilitato le opzioni is_volatile, check_freshness e freshness_threshold. La prima serve a far generare un alert anche nel caso in cui vi sia solo una variazione dell’output restituito dal check (e non necessariamente un cambio di stato); la seconda serve a verificare che un determinato evento venga ricevuto entro un tempo limite (espresso in secondi), specificato mediante la terza direttiva, ovvero freshness_threshold.

Inoltre ho disabilitato la flap detection, poichè i check passivi possono cambiare stato molto frequentemente ed è mia intenzione tenere traccia (mediante alert) di tutti gli eventi.

Per ciò che concerne il comando check_passive (definito in /etc/nagios/objects/commands.cfg), esso presenta la seguente struttura:

# 'check_passive' command definition
define command{
        command_name check_passive
        command_line $USER1$/check_dummy 2 "No alerts received in 600 seconds"
}

dove l’applicativo check_dummy non fa altro che restituire lo stato (in questo caso 2, ovvero CRITICAL), affiancato da un’opportuna descrizione (No alerts received in 600 seconds).

Ricarichiamo la configurazione di Nagios:

[root@linuxbox local]# service nagios reload

ed abbiamo finito. Alla prossima

CentOS 6: monitorare le performance di Nagios mediante MRTG

Il compito di un NMS, si sa, è quello di monitorare le prestazioni e lo stato di salute di server, router, switch, firewall e chi più ne ha più ne metta. Nel caso in cui gli oggetti da tenere sotto osservazione siano relativamente pochi (qualche centinatio) ed il server su cui è ospitato Nagios sia abbastanza corazzato (almeno 4/8 GB di RAM), il nostro NMS dovrebbe riuscire a svolgere il suo compito senza grosse difficoltà. Tutto si complica, ovviamente, se il numero degli oggetti da monitorare risulta piuttosto elevato (parliamo qualche migliaio). In tal caso è conveniente tenere sotto controllo le performance del nostro sistema di monitoring (e non solo quelle del server su cui è in esecuzione), poichè potrebbero essere presenti alcuni colli di bottiglia che ne inficiano il corretto funzionamento.

Esistono numerosi plugin sviluppati appositamente per Nagios ed in grado di restituirci dei feedback relativi allo stato di salute dell’NMS in questione, ma, per ovvie ragioni, ho deciso di demandare tale compito ad un tool esterno (leggasi Nagios indipendente): MRTG.

mrtg_logo

In questo post abbiamo visto come installarlo e come creare una configurazione valida per la misurazione della banda associata alle interfacce del nostro router. Adesso vedremo come integrarlo a Nagios in modo da ottenere (e graficizzare) le sue performance.

Di seguito riporto il contenuto del file nagios.cfg (presente all’interno della directory /etc/mrtg/), usato da MRTG per svolgere il proprio compito di monitoraggio:

WorkDir: /var/www/mrtg/nagios

# Service Latency and Execution Time
Target[nagios-a]: `/usr/bin/nagiostats --mrtg --data=AVGACTSVCLAT,AVGACTSVCEXT,PROGRUNTIME,NAGIOSVERPID`
MaxBytes[nagios-a]: 100000
Title[nagios-a]: Average Service Check Latency and Execution Time
PageTop[nagios-a]: <H1>Average Service Check Latency and Execution Time</H1>
Options[nagios-a]: growright,gauge,nopercent
YLegend[nagios-a]: Milliseconds
ShortLegend[nagios-a]: &nbsp;
LegendI[nagios-a]: &nbsp;Latency:
LegendO[nagios-a]: &nbsp;Execution Time:
Legend1[nagios-a]: Latency
Legend2[nagios-a]: Execution Time
Legend3[nagios-a]: Maximal 5 Minute Latency
Legend4[nagios-a]: Maximal 5 Minute Execution Time

# Service Percent State Change
Target[nagios-b]: `/usr/bin/nagiostats --mrtg --data=AVGACTSVCPSC,AVGPSVSVCPSC,PROGRUNTIME,NAGIOSVERPID`
MaxBytes[nagios-b]: 100
Title[nagios-b]: Average Service State Change
PageTop[nagios-b]: <H1>Average Service State Change</H1>
Options[nagios-b]: growright,gauge,nopercent
YLegend[nagios-b]: Percent
ShortLegend[nagios-b]: &nbsp;
LegendI[nagios-b]: &nbsp;Active Check % Change:
LegendO[nagios-b]: &nbsp;Passive Check % Change:
Legend1[nagios-b]: State Change
Legend2[nagios-b]: State Change
Legend3[nagios-b]: Maximal 5 Minute State Change
Legend4[nagios-b]: Maximal 5 Minute State Change

# Host Latency and Execution Time
Target[nagios-c]: `/usr/bin/nagiostats --mrtg --data=AVGACTHSTLAT,AVGACTHSTEXT,PROGRUNTIME,NAGIOSVERPID`
MaxBytes[nagios-c]: 100000
Title[nagios-c]: Average Host Check Latency and Execution Time
PageTop[nagios-c]: <H1>Average Host Check Latency and Execution Time</H1>
Options[nagios-c]: growright,gauge,nopercent
YLegend[nagios-c]: Milliseconds
ShortLegend[nagios-c]: &nbsp;
LegendI[nagios-c]: &nbsp;Latency:
LegendO[nagios-c]: &nbsp;Execution Time:
Legend1[nagios-c]: Latency
Legend2[nagios-c]: Execution Time
Legend3[nagios-c]: Maximal 5 Minute Latency
Legend4[nagios-c]: Maximal 5 Minute Execution Time

# Host Percent State Change
Target[nagios-d]: `/usr/bin/nagiostats --mrtg --data=AVGACTHSTPSC,AVGPSVHSTPSC,PROGRUNTIME,NAGIOSVERPID`
MaxBytes[nagios-d]: 100
Title[nagios-d]: Average Host State Change
PageTop[nagios-d]: <H1>Average Host State Change</H1>
Options[nagios-d]: growright,gauge,nopercent
YLegend[nagios-d]: Percent
ShortLegend[nagios-d]: &nbsp;
LegendI[nagios-d]: &nbsp;Active Check % Change:
LegendO[nagios-d]: &nbsp;Passive Check % Change:
Legend1[nagios-d]: State Change
Legend2[nagios-d]: State Change
Legend3[nagios-d]: Maximal 5 Minute State Change
Legend4[nagios-d]: Maximal 5 Minute State Change

# Hosts/Services Actively Checked
Target[nagios-e]: `/usr/bin/nagiostats --mrtg --data=NUMHSTACTCHK5M,NUMSVCACTCHK5M,PROGRUNTIME,NAGIOSVERPID`
MaxBytes[nagios-e]: 7000
Title[nagios-e]: Hosts/Services Actively Checked
PageTop[nagios-e]: <H1>Hosts/Services Actively Checked</H1>
Options[nagios-e]: growright,gauge,nopercent
YLegend[nagios-e]: Total
ShortLegend[nagios-e]: &nbsp;
LegendI[nagios-e]: &nbsp;Hosts:
LegendO[nagios-e]: &nbsp;Services:

# Hosts/Services Passively Checked
Target[nagios-f]: `/usr/bin/nagiostats --mrtg --data=NUMHSTPSVCHK5M,NUMSVCPSVCHK5M,PROGRUNTIME,NAGIOSVERPID`
MaxBytes[nagios-f]: 7000
Title[nagios-f]: Hosts/Services Passively Checked
PageTop[nagios-f]: <H1>Hosts/Services Passively Checked</H1>
Options[nagios-f]: growright,gauge,nopercent
YLegend[nagios-f]: Total
ShortLegend[nagios-f]: &nbsp;
LegendI[nagios-f]: &nbsp;Hosts:
LegendO[nagios-f]: &nbsp;Services:

# Used/Avail External Command Buffers
Target[nagios-g]: `/usr/bin/nagiostats --mrtg --data=TOTCMDBUF,USEDCMDBUF,PROGRUNTIME,NAGIOSVERPID`
MaxBytes[nagios-g]: 7000
Title[nagios-g]: External Command Buffers
PageTop[nagios-g]: <H1>External Command Buffers</H1>
Options[nagios-g]: growright,gauge,nopercent
YLegend[nagios-g]: Buffers
ShortLegend[nagios-g]: &nbsp;
LegendI[nagios-g]: &nbsp;Total:
LegendO[nagios-g]: &nbsp;Used:

# Active Host Checks
Target[nagios-i]: `/usr/bin/nagiostats --mrtg --data=NUMSACTHSTCHECKS5M,NUMOACTHSTCHECKS5M,PROGRUNTIME,NAGIOSVERPID`
MaxBytes[nagios-i]: 7000
Title[nagios-i]: Active Host Checks
PageTop[nagios-i]: <H1>Active Host Checks</H1>
Options[nagios-i]: growright,gauge,nopercent
YLegend[nagios-i]: Checks
ShortLegend[nagios-i]: &nbsp;
LegendI[nagios-i]: &nbsp;Scheduled Checks:
LegendO[nagios-i]: &nbsp;On-Demand Checks:

# Active Service Checks
Target[nagios-j]: `/usr/bin/nagiostats --mrtg --data=NUMSACTSVCCHECKS5M,NUMOACTSVCCHECKS5M,PROGRUNTIME,NAGIOSVERPID`
MaxBytes[nagios-j]: 7000
Title[nagios-j]: Active Service Checks
PageTop[nagios-j]: <H1>Active Service Checks</H1>
Options[nagios-j]: growright,gauge,nopercent
YLegend[nagios-j]: Checks
ShortLegend[nagios-j]: &nbsp;
LegendI[nagios-j]: &nbsp;Scheduled Checks:
LegendO[nagios-j]: &nbsp;On-Demand Checks:

# Passive Host/Service Checks
Target[nagios-k]: `/usr/bin/nagiostats --mrtg --data=NUMPSVHSTCHECKS5M,NUMPSVSVCCHECKS5M,PROGRUNTIME,NAGIOSVERPID`
MaxBytes[nagios-k]: 7000
Title[nagios-k]: Passive Host/Service Checks
PageTop[nagios-k]: <H1>Passive Host/Service Checks</H1>
Options[nagios-k]: growright,gauge,nopercent
YLegend[nagios-k]: Checks
ShortLegend[nagios-k]: &nbsp;
LegendI[nagios-k]: &nbsp;Host Checks:
LegendO[nagios-k]: &nbsp;Service Checks:

# Cached Host/Service Checks
Target[nagios-l]: `/usr/bin/nagiostats --mrtg --data=NUMCACHEDHSTCHECKS5M,NUMCACHEDSVCCHECKS5M,PROGRUNTIME,NAGIOSVERPID`
MaxBytes[nagios-l]: 7000
Title[nagios-l]: Cached Host/Service Checks
PageTop[nagios-l]: <H1>Cached Host/Service Checks</H1>
Options[nagios-l]: growright,gauge,nopercent
YLegend[nagios-l]: Checks
ShortLegend[nagios-l]: &nbsp;
LegendI[nagios-l]: &nbsp;Host Checks:
LegendO[nagios-l]: &nbsp;Service Checks:

# External Commands
Target[nagios-m]: `/usr/bin/nagiostats --mrtg --data=NUMEXTCMDS5M,0,PROGRUNTIME,NAGIOSVERPID`
MaxBytes[nagios-m]: 7000
Title[nagios-m]: External Commands
PageTop[nagios-m]: <H1>External Commands</H1>
Options[nagios-m]: growright,gauge,nopercent
YLegend[nagios-m]: Commands
ShortLegend[nagios-m]: &nbsp;
LegendI[nagios-m]: &nbsp;Commands:
LegendO[nagios-m]: &nbsp;

# Parallel/Service Host Checks
Target[nagios-n]: `/usr/bin/nagiostats --mrtg --data=NUMPARHSTCHECKS5M,NUMSERHSTCHECKS5M,PROGRUNTIME,NAGIOSVERPID`
MaxBytes[nagios-n]: 7000
Title[nagios-n]: Parallel/Serial Host Checks
PageTop[nagios-n]: <H1>Parallel/Serial Host Checks</H1>
Options[nagios-n]: growright,gauge,nopercent
YLegend[nagios-n]: Checks
ShortLegend[nagios-n]: &nbsp;
LegendI[nagios-n]: &nbsp;Parallel Checks:
LegendO[nagios-n]: &nbsp;Serial Checks:

Il giro del fumo può banalmente essere riassunto in questo modo: viene lanciato l’applicativo nagiostats, al quale vengono affiancate alcune flag come –mrtg e –data (quest’ultima serve a specificare i parametri da monitorare, ad esempio NUMPSVHSTCHECKS5M,NUMPSVSVCCHECKS5M,PROGRUNTIME,NAGIOSVERPID).

Occorre precisare, inoltre,  che nagiostats viene eseguito direttamente dal crontab che richiama MRTG, ragion per cui è indispensabile configurare SElinux in modo da consentire tale operazione.

Creiamo la directory che ospiterà la pagina Web contenente le i grafici associati alle prestazioni di Nagios:

[root@linuxbox ~]# mkdir -p /var/www/mrtg/nagios

e successivamente passiamo alla creazione della pagina index.html:

[root@linuxbox ~]# indexmaker --output=/var/www/mrtg/nagios/index.html /etc/mrtg/nagios.cfg

Infine, modifichiamo il contenuto del file /etc/cron.d/mrtg, aggiungendo la stringa:

*/5 * * * * root LANG=C LC_ALL=C /usr/bin/mrtg /etc/mrtg/nagios.cfg --lock-file /var/lock/mrtg/nagios_l --confcache-file /var/lib/mrtg/nagios.ok

Come ultimo step creiamo la configurazione di Apache per l’accesso alla pagina Web in cui sono presenti i grafici generati da MRTG:

[root@linuxbox ~]# nano /etc/httpd/conf.d/mrtg.conf

Il cui contenuto dovrà essere simile al seguente:

Alias /mrtg /var/www/mrtg

<Location /mrtg>
    Order deny,allow
    Allow from all
    AuthName "MRTG Access"
    AuthType Basic
    AuthUserFile /etc/mrtg/passwd
    Require valid-user
</Location>

Infine, creiamo il file contenente user e pass per l’accesso alla suddetta pagina Web:

[root@linuxbox ~]# htpasswd -c /etc/mrtg/passwd <vostrouser>

Ricarichiamo la configurazione di Apache:

[root@linuxbox ~]# service apache reload

ed abbiamo finito:

mrtg-nagios

Alla prossima.

check_noise_margin e check_attenuation: script Nagios per verificare la qualità della nostra linea ADSL

Premessa

Vi sono numerosi fattori che possono influenzare negativamente o positivamente la qualità della nostra linea ADSL, ma i più importanti sono sicuramente il rapporto segnale rumore (SNR o noise margin) e l’attenuazione.

In particolare, nel primo caso un valore elevato indica una qualità migliore; viceversa, nel secondo caso, un valore elevato indica una qualità peggiore. Inoltre, i valori di attenuazione sono molto influenzati dalla distanza che intercorre tra la nostra abitazione e la centrale di zona dell’ISP (va da se che maggiore sarà questa distanza, maggiore sarà l’attenuazione).

Esistono comunque dei valori di massima (sia per l’SNR che per l’attenuazione) sui quali ci si può basare per fare una stima qualitativa del nostro collegamento ADSL. Li riporto di seguito:

SNR

1) <= 6dB : pessimo, numerosi errori si sincronizzazione con la portante;
2) tra i 7dB ed i 10dB: scarso;
3) tra gli 11dB ed i 20dB: buono;
4) tra i 20dB ed i 28dB: eccellente;
5) >= 29dB: eccezionale.

 Attenuazione

1) < = 20dB: eccezionale;
2) tra i 20dB ed i 30dB: eccellente:
3) tra i 30dB ed i 40dB: molto buona;
4) tra i 40dB ed i 50dB: buona;
5) tra i 50dB ed i 60dB: scarsa, con diversi errori di connessione.
6) >= 60dB: pessima, con numerosi errori di connessione.

Tenendo conto dei suddetti valori, ho deciso di realizzare 2 scrip bash (da integrare a Nagios), in modo da tenere traccia dei valori di SNR ed attenuazione relativi alla mia linea ADSL. Il router di riferimento è un Cisco 877.

Entrambi gli scrip in questione (check_noise_margin e check_attenuation), si basano su un ulteriore scrip expect (get_dsl_info) che esegue la query sul router, lanciando il comando sh dsl int atm0.

Il contenuto di tale scrip è il seguente:

#!/usr/bin/expect

set ip [lindex $argv 0]
set password1 [lindex $argv 1]
set password2 [lindex $argv 2]

spawn ssh -l nightfly "$ip"
expect "*?assword:*"
send "$password1\r"
expect ">"
send "ena\r"
expect "Password:"
send "$password2\r"
expect "#"
send "sh dsl int atm0\r"
send " "
expect "#"
send "exit\r"
expect eof

L’output da esso generato verrà quindi dato in pasto ed elaborato da check_noise_margin e da check_attenuation. Il loro contenuto è molto simile ed è (rispettivamente):

#!/bin/bash

host=$1
password1=$2
password2=$3
warning=$4
critical=$5

usage="check_noise_margin <host> <password1> <password2> <warning> <critical>"

if [ -n "$host" ]; then

        if [ -n "$password1" ];then

                if [ -n "$password2" ];then

                        if [ -n "$warning" ];then

                                if [ -n "$critical" ];then

                                        if [ "$critical" -gt "$warning" ];then

                                                echo "UNKNOWN: critical has to be less than warning"
                                                exit 3;

                                        else

                                                output=`/usr/lib64/nagios/plugins/get_dsl_info $1 $2 $3 | grep "Noise"  | awk -F " " '{print $3,$5}'`
                                                output1=`echo $output | awk '{print $1}'`
                                                output2=`echo $output | awk '{print $2}'`
                                                unit="db"
                                        fi

                                        if [ -n "$output" ];then

                                                if [ $(echo "$output1 < $critical" | bc) -eq 1 -o $(echo "$output2 < $critical" | bc) -eq 1 ];then

                                                        echo "CRITICAL: downstream noise margin is $output1 db, upstream noise margin is $output2 db | downstream_noise_margin=$output1$unit;$warning;$critical upstream_noise_margin=$output2$unit;$warning;$critical";
                                                        exit 2;

                                                elif [ $(echo "$output1 > $critical" | bc) -eq 1 -a  $(echo "$output1 < $warning" | bc) -eq 1 -o $(echo "$output2 > $critical" | bc) -eq 1 -a $(echo "$output2 < $warning"  |bc) -eq 1 ];then

                                                        echo "WARNING: downstream noise margin is $output1 db, upstream noise margin is $output2 db| downstream_noise_margin=$output1$unit;$warning;$critical upstream_noise_margin=$output2$unit;$warning;$critical" ;
                                                        exit 1;

                                                else

                                                        echo "OK: downstream noise margin is $output1 db, upstream noise margin is $output2 db | downstream_noise_margin=$output1$unit;$warning;$critical upstream_noise_margin=$output2$unit;$warning;$critical";
                                                        exit 0;

                                                fi
                                        else

                                                echo "UNKNOWN: output is null"
                                                exit 3;

                                        fi

                                else

                                        echo "$usage"
                                        exit 3;
                                fi

                        else

                                echo "$usage"
                                exit 3;
                        fi

                else

                        echo "$usage"
                        exit 3;
                fi
        else

                echo "$usage"
                exit 3;
        fi

else

        echo "$usage"
        exit 3;

fi

per check_noise_margin, e:

#!/bin/bash

host=$1
password1=$2
password2=$3
warning=$4
critical=$5

usage="check_attenuation <host> <password1> <password2> <warning> <critical>"

if [ -n "$host" ]; then

        if [ -n "$password1" ];then

                if [ -n "$password2" ];then

                        if [ -n "$warning" ];then

                                if [ -n "$critical" ];then

                                        if [ "$critical" -lt "$warning" ];then

                                                echo "UNKNOWN: critical has to be greater than warning"
                                                exit 3;

                                        else

                                                output=`/usr/lib64/nagios/plugins/get_dsl_info $1 $2 $3 | grep "Attenuation"  | awk -F " " '{print $2, $4}'`

                                                output1=`echo $output | awk '{print $1}'`
                                                output2=`echo $output | awk '{print $2}'`
                                                unit="db"
                                        fi

                                        if [ -n "$output" ];then

                                                if [ $(echo "$output1 > $critical" | bc) -eq 1 -o $(echo "$output2 > $critical" | bc) -eq 1 ];then

                                                        echo "CRITICAL: downstream attenuation is $output1 db, upstream attenuation is $output2 db | downstream_attenuation=$output1$unit;$warning;$critical upstream_attenuation=$output2$unit;warning;$critical";
                                                        exit 2;

                                                elif [ $(echo "$output1 < $critical" | bc) -eq 1 -a  $(echo "$output1 > $warning" | bc) -eq 1 -o $(echo "$output2 < $critical" | bc) -eq 1 -a  $(echo "$output2 > $warning" | bc) -eq 1 ];then

                                                        echo "WARNING: downstream attenuation is $output1 db, upstream attenuation is $output2 db | downstream_attenuation=$output1$unit;$warning;$critical upstream_attenuation=$output2$unit;$warning;$critical";
                                                        exit 1;

                                                else

                                                        echo "OK: downstream attenuation is $output1 db, upstream attenuation is $output2 db | downstream_attenuation=$output1$unit;$warning;$critical upstream_attenuation=$output2$unit;$warning;$critical";
                                                        exit 0;

                                                fi
                                        else

                                                echo "UNKNOWN: output is null"
                                                exit 3;

                                        fi

                                else

                                        echo "$usage"
                                        exit 3;
                                fi

                        else

                                echo "$usage"
                                exit 3;
                        fi

                else

                        echo "$usage"
                        exit 3;
                fi
        else

                echo "$usage"
                exit 3;
        fi

else

        echo "$usage"
        exit 3;

fi

per check_attenuation.

Da notare che in entrambi i casi ho aggiunto le perfdata da dare in pasto a pnp4nagios. Inoltre, poichè i valori restituiti possono contenere dei decimali, ho dovuto utilizzare il comando bc per i calcoli aritmetici. Ciò si è reso necessario poichè bash tratta nativamente le variabili come stringhe.

Una volta fatto ciò, ho semplicemente creato i comandi per Nagios:

# 'check_noise_margin' command definition
 define command{
 command_name    check_noise_margin
 command_line    $USER1$/check_noise_margin $HOSTADDRESS$ $ARG1$ $ARG2$ $ARG3$ $ARG4$
 }
# 'check_attenuation' command definition
 define command{
 command_name    check_attenuation
 command_line    $USER1$/check_attenuation $HOSTADDRESS$ $ARG1$ $ARG2$ $ARG3$ $ARG4$
 }

collegandoli, successivamente, ai servizi del router Cisco:

define service{
 use                             local-service         ; Name of service template to use
 host_name                       router
 service_descripion             Noise Margin
 check_command                   check_noise_margin!pass1!pass2!10!6
 }
define service{
 use                             local-service         ; Name of service template to use
 host_name                       router
 service_descripion             Attenuation
 check_command                   check_attenuation!pass1!pass2!51!61
 }

Infine, ho lanciato un reload del servizio:

[root@nightbox objects]# service nagios reload

e finalmente la qualità della mia linea ADSL è sotto monitoraggio.

Alla prossima.

PS: per chi le preferisse, ecco le varianti in Perl dei suddetti scrip:

#!/usr/bin/perl

use strict;
use warnings;

my $host=$ARGV[0];
my $password1=$ARGV[1];
my $password2=$ARGV[2];
my $warning=$ARGV[3];
my $critical=$ARGV[4];

my $usage="check_noise_margin.pl <host> <password1> <password2> <warning> <critical>";

if ($host ne "") {
        if ($password1 ne "")
        {
                if ($password2 ne "")
                {
                        if ($warning ne "")
                        {
                                if ($critical ne "")
                                {
                                        if ($critical > $warning)
                                        {
                                                print "UNKNOWN: critical has to be less than warning";
                                                exit 3;
                                        }
                                        else
                                        {
                                                my $output=`/usr/lib64/nagios/plugins/get_dsl_info $host $password1 $password2 | /bin/grep "Noise"`;

                                                if($output ne "")
                                                {

                                                        my @columns = split /\s+/, $output;
                                                        my $downstream = $columns[2];
                                                        my $upstream = $columns[4];
                                                        my $unit = "db";

                                                        if ($downstream < $critical || $upstream < $critical)
                                                        {
                                                                print "CRITICAL: downstream noise margin is $downstream db; upstream noise margin is $upstream db | downstream_noise_margin=$downstream$unit;$warning;$critical upstream_noise_margin=$upstream$unit;$warning;$critical\n";
                                                                exit 2;
                                                        }
                                                        elsif ($downstream > $critical && $downstream < $warning || $upstream > $critical && $upstream < $warning)
                                                        {
                                                                print "WARNING: downstream noise margin is $downstream db; upstream noise margin is $upstream db | downstream_noise_margin=$downstream$unit;$warning;$critical upstream_noise_margin=$upstream$unit;$warning;$critical\n";
                                                                exit 1;
                                                        }
                                                        else
                                                        {
                                                                print "OK: downstream noise margin is $downstream db, upstream noise margin is $upstream db | downstream_noise_margin=$downstream$unit;$warning;$critical upstream_noise_margin=$upstream$unit;$warning;$critical\n";
                                                                exit 0;
                                                        }
                                                }
                                                else
                                                {
                                                                print "UNKNOWN: output is null";
                                                                exit 3;
                                                }
                                        }
                                }
                                else
                                {
                                        print "$usage";
                                        exit 3;
                                }
                        }
                        else
                        {
                                print "$usage";
                                exit 3;
                        }
                }
                else
                {
                        print "$usage";
                        exit 3;
                }
        }
        else
        {
                print "$usage";
                exit 3;
        }
}
else
{
        print "$usage";
        exit 3;
}

e

#!/usr/bin/perl

use strict;
use warnings;

my $host=$ARGV[0];
my $password1=$ARGV[1];
my $password2=$ARGV[2];
my $warning=$ARGV[3];
my $critical=$ARGV[4];

my $usage="check_attenuation.pl <host> <password1> <password2> <warning> <critical>";

if ($host ne "") {
        if ($password1 ne "")
        {
                if ($password2 ne "")
                {
                        if ($warning ne "")
                        {
                                if ($critical ne "")
                                {
                                        if ($critical < $warning)
                                        {
                                                print "UNKNOWN: critical has to be more than warning";
                                                exit 3;
                                        }
                                        else
                                        {
                                                my $output=`/usr/lib64/nagios/plugins/get_dsl_info $host $password1 $password2 | /bin/grep "Attenuation"`;

                                                if($output ne "")
                                                {

                                                        my @columns = split /\s+/, $output;
                                                        my $downstream = $columns[1];
                                                        my $upstream = $columns[3];
                                                        my $unit = "db";

                                                        if ($downstream > $critical || $upstream > $critical)
                                                        {
                                                                print "CRITICAL: downstream attenuation is $downstream db; upstream attenuation is $upstream db | downstream_attenuation=$downstream$unit;$warning;$critical upstream_attenuation=$upstream$unit;$warning;$critical\n";
                                                                exit 2;
                                                        }
                                                        elsif ($downstream < $critical && $downstream > $warning || $upstream < $critical && $upstream > $warning)
                                                        {
                                                                print "WARNING: downstream attenuation is $downstream db; upstream attenuation is $upstream db | downstream_attenuation=$downstream$unit;$warning;$critical upstream_attenuation=$upstream$unit;$warning;$critical\n";
                                                                exit 1;
                                                        }
                                                        else
                                                        {
                                                                print "OK: downstream attenuation is $downstream db, upstream attenuation is $upstream db | downstream_attenuation=$downstream$unit;$warning;$critical upstream_attenuation=$upstream$unit;$warning;$critical\n";
                                                                exit 0;
                                                        }
                                                }
                                                else
                                                {
                                                                print "UNKNOWN: output is null";
                                                                exit 3;
                                                }
                                        }
                                }
                                else
                                {
                                        print "$usage";
                                        exit 3;
                                }
                        }
                        else
                        {
                                print "$usage";
                                exit 3;
                        }
                }
                else
                {
                        print "$usage";
                        exit 3;
                }
        }
        else
        {
                print "$usage";
                exit 3;
        }
}
else
{
        print "$usage";
        exit 3;
}

PPS: se sul vostro router è stato abilitato il protocollo SNMP, gli OID che consentono di monitorare SNR ed attenuazione sono i seguenti:

.1.3.6.1.2.1.10.94.1.1.3.1.5.11 = downstream attenuation 
.1.3.6.1.2.1.10.94.1.1.2.1.5.11 = upstream attenuation 
.1.3.6.1.2.1.10.94.1.1.3.1.4.11 = downstream noise margin
.1.3.6.1.2.1.10.94.1.1.2.1.4.11 = upstream noise margin

In particolare, l’ultima parte dell’OID (.11) si riferisce all’Interface Index della Dialer (nel mio caso si tratta della Dialer0).

LVS in modalità Direct Routing: stato delle connessioni

Recentemente ho dovuto far fronte a tutta una serie di allarmi generati da Nagios (NMS), relativi ad un numero troppo elevato di connessioni (sia attive che inattive) gestite da LVS (load balancer).

load balancing

In particolare, gli allarmi riportavano delle informazioni del tipo:

***** Nagios *****

Notification Type: PROBLEM

Service: IPVS HTTP Status
Host: lbprod.domain.com
Address: 
State: CRITICAL

Date/Time: Sat Aug 22 14:37:38 CET 2015

Additional Info:

CRITCAL total active=9096:8400:9000:0: total inactive=26650:50000:55000:0: 192.168.3.1:80 active=1305:1200:1300:0: 192.168.3.1:80 inactive=3925:7000:8000:0: 192.168.3.11:80 active=1304:1200:1300:0: 192.168.3.11:80 inactive=3781:7000:8000:0: 192.168.3.12:80 active=1296:1200:1300:0: 192.168.3.12:80 inactive=3952:7000:8000:0: 192.168.3.13:80 active=1287:1200:1300:0: 192.168.3.13:80 inactive=3744:7000:8000:0: 192.168.3.36:80 active=1309:1200:1300:0: 192.168.3.36:80 inactive=3653:7000:8000:0: 192.168.3.37:80 active=1299:1200:1300:0: 192.168.3.37:80 inactive=3748:7000:8000:0: 192.168.3.38:80 active=1296:1200:1300:0: 192.168.3.38:80 inactive=3847:7000:8000:0:

A primo acchito, analizzando il suddetto output, ho individuato 2 anomalie, ovvero l’elevato numero di connessioni totali attive (9096, superiore alla soglia critica 9000) ed inattive (26650).

Collegandomi dapprima al bilanciatore e lanciando il comando:

[root@nightbox ~]# watch ipvsadm

ho appurato che l’allarme generato da Nagios fosse veritiero (poichè i valori restituiti erano totalmente in linea con quelli indicati dall’allarme).

Successivamente, mi sono connesso ai vari frontend ed ho lanciato il comando:

[root@lbprod ~]# netstat -anp | grep ":80" | grep ESTABLISHED | wc -l

in modo da conteggiare il numero di connessioni attive (ESTABLISHED) presenti su ciascuno di essi. Secondo il mio ragionamento, la somma delle suddette connessioni attive doveva restituirmi un numero prossimo a quello segnalato da Nagios ed ipvsadm, ma così non è stato. Lo stesso dicasi per le connessioni inattive (diverse da ESTABLISHED), identificate mediante il comando:

[root@lbprod ~]# netstat -anp | grep ":80" | grep -v ESTABLISHED | wc -l

A questo punto ho consulato questa pagina (la documentazione ufficiale di ipvsadm, ovvero il tool di gestione di LVS tramite CLI) e mi sono soffermato sulla sezione 4.11.5, il cui titolo è abbastanza esplicativo – ActiveConn is a guess for LVS-DR ed il cui contenuto è il seguente:

For LVS-DR, the director doesn’t see the return packets and uses tables of timeouts to guess a likely state of the service at the realserver. For the same reason you can’t do stateful filtering on the director for LVS-DR controlled packets.

In soldoni, ciò significa che LVS configurato in modalità Direct Routing (DR) vede solo ed esclusivamente le connessioni in ingresso (e dirette ai frontend) ma non vede il traffico di ritorno (poichè non passa dal bilanciatore ma si sviluppa interamente tra frontend e client). Proprio per questo motivo, ipvsadm identificherà come attiva una connessione fin quando non scadrà il timeout ad essa associato.

Per visualizzare i valori di timeout per le connessioni TCP, TCP-FIN ed UDP ho utilizzando il comando:

[root@lb1 ~]# ipvsadm -l --timeout

il cui output era il seguente:

Timeout (tcp tcpfin udp): 900 60 300

con i valori di timeout espressi in secondi (per modificarli basta lanciare il comando ipvsadm –set).

Svelato dunque l’arcano, ho dapprima modificato i valori di timeout per le connessioni TCP (portandoli di poco al di sopra di quelli definiti sui frontend) ed ho innalzato le soglie di WARNING e CRITICAL per il servizio di Nagios.

Alla prossima.

Cisco 2811: utilizzare le route-map per creare delle regole di destination NAT basate su IP sorgente

Scenario

Supponiamo che si abbia a che fare con un ufficio centrale (main office) a cui sono collegati N uffici periferici (branch office) tramite dei tunnel VPN IPsec Site-to-Site dedicati (che concorrono a formare la classica topologia a stella). Supponiamo, inoltre, che i suddetti uffici periferici, per questioni di failover, debbano essere in grado di raggiungere i servizi presenti nell’ufficio centrale anche nel caso in cui i tunnel VPN non siano disponibili (passando quindi  direttamente per Internet).

vpn-ipsec1Utilizzando delle regole di destination NAT classiche, del tipo:

ip nat inside source static tcp 192.168.2.4 80 interface fastethernet0/0 80

(dove 192.168.4.2 è l’IP locale del server Web esposto su Internet), i branch office non saranno in grado di raggiungere il server in questione tramite il tunnel VPN (utilizzando il protocollo HTTP).

Ergo, il fatto che un determinato servizio sia pubblicato su Internet, implica automaticamente l’impossibilità di raggiungerlo anche tramite il tunnel VPN.

Per ovviare a tale problematica esistono 2 soluzioni: la prima, meno impegnativa (ma che richiede la modifica della URL lato client in caso di failover), consiste nel modificare la configurazione del server in modo tale che rimanga in ascolto su 2 porte distinte, ad esempio la TCP 80 per Internet e la TCP 81 per la VPN;  la seconda, più impegnativa (ma anche molto più scalabile), consiste nel creare sul nostro router Cisco 2811 (main office) delle route-map (che si avvalgono di opportune ACL) in grado di filtrare gli indirizzi IP sorgenti dei client che vogliono collegarsi al server Web. In questo modo, se la richiesta di connessione proviene da un determinato IP privato tipico di una VPN Site-to-Site (ad esempio 192.168.3.1), per essa non viene applicato il destination NAT; viceversa, nel caso in cui la richiesta di connessione provenga da Internet, verrà applicato il destination NAT come di consueto.

Ho definito la seconda soluzione come la più scalabile delle 2 per un semplice motivo: impostando la route-map sul router del main office e modificando sul nameserver locale il record di tipo A che punta all’IP del server Web, si può fare in modo che quest’ultimo possa essere contattato tramite tunnel VPN o tramite Internet a seconda dei casi senza dover modificare la URL lato browser (passando, ad esempio, da http://www.vostrodominio.com a http://www.vostrodominio.com:81).

Vediamo adesso come mettere in pratica la soluzione #2.

Configurazione del router Cisco 2811 (main office)

Per prima cosa occorre creare l’ACL in grado di “riconoscere” gli IP locali e di negare il destination NAT:

Router(config)# access-list 150 deny ip host 192.168.2.4 192.168.3.0 0.0.0.255
Router(config)# access-list 150 deny ip host 192.168.2.4 192.168.4.0 0.0.0.255
Router(config)# access-list 150 deny ip host 192.168.2.4 192.168.5.0 0.0.0.255
Router(config)# access-list 150 deny ip host 192.168.2.4 192.168.6.0 0.0.0.255
Router(config)# access-list 150 permit ip host 192.168.2.4 any

Successivamente creiamo la route-map vera e propria:

Router(config)# route-map nonat
Router(config-route-map)# match ip address 150

dove 150 è il numero dell’ACL estesa precedentemente definita.

Infine, associamo la route-map appena creata alla regola di destination NAT:

Router(config)# ip nat inside source static tcp 192.168.2.4 <IP Pubblico> 80 route-map nonat extendable

Ovviamente, affinchè la suddetta soluzione sia realmente scalabile, è necessario che il vostro collegamento ad Internet sia dotato di indirizzo IP pubblico statico.

Salviamo adesso la configurazione del nostro router:

Router# copy run start

e passiamo al vaglio alcune soluzioni alternative alle route-map.

1) Utilizzo dei record DNS di tipo SRV (vedi qui per ulteriori dettagli). Essi ci consentono non solo di specificare il protocollo di comunicazione ma anche la porta su cui è in ascolto il server, definendo una priorità per ciascuna entry che li compone:

_http._tcp.vostrodominio.com. 86400 IN SRV 0 5 81 www.vostrodominio.com.
_http._tcp.vostrodominio.com. 86400 IN SRV 1 5 80 www1.vostrodominio.com.

dove 0 e 1 sono le priorità, 81 e 80 le porte su cui è in ascolto il server. In caso di timeout sulla porta 81 e l’IP di www (raggiungibile via VPN) il browser “dovrebbe” switchtare automaticamente sulla 80 e l’IP di www1. Ho utilizzato il condizionale poichè non tutti i broswer supportano tale meccanismo ed un workaround (applicato però solo da alcuni di essi), consiste nel definire record A con il medesimo hostname ma indirizzi IP differenti: nel caso in cui la connessione al primo IP della lista vada in timeout, il broswer tenterà automaticamente di connettersi al secondo IP (e così via).

2) Utilizzo di un firewall interno per filtrare le connessioni in uscita (outbound). ln questo caso, grazie ad esso, potremmo creare delle regole ad hoc (source NAT) per il mapping delle porte di destinazione, ad esempio (utilizzando iptables):

[root@firewall ~]# iptables -t nat -A OUTPUT -p tcp -d www.vostrodominio.com --dport 80 -j DNAT --to-destination www.vostrodominio.com:81

Anche in questo caso, prima di applicare la suddetta regola di firewalling, sarà necessario modificare sul nameserver il record A per l’hostname www.

E’ tutto. Alla prossima.

PIX 501: configurazione del protocollo TACACS+

Premessa

Più volte, nell’ambito dei miei ultimi post, ho discusso della configurazione del protocollo TACACS+ per i Router/Switch di casa Cisco.

Adesso vedremo come configurare il suddetto protocollo su un Cisco PIX 501.

pixPrima di iniziare, occorre precisare che le uniche feature che abiliteremo saranno l’autenticazione e l’accounting (tralasciando quindi la parte di autorizzazione).

Configurazione generale

Dopo aver effettuato il login sul firewall in questione, entriamo in modalità enable e digitiamo il comando:

PIX# conf t

per poi creare una nuova istanza TACACS+:

PIX(config)# aaa-server AuthInbound protocol tacacs+

A questo punto possiamo specificare l’IP del server AAA, l’interfaccia attraverso cui è possibile raggiungerlo, la chiave TACACS+ ed il timeout:

PIX(config)# aaa-server AuthInbound (inside) host <IP> <key> timeout <secondi>

Authentication

Ora possiamo definire i protocolli che dovranno interfacciarsi col server per l’autenticazione dell’utente:

PIX(config)# aaa authentication telnet console AuthInbound LOCAL

Accounting

Infine, facciamo in modo che tutte le sessioni provenienti dall’esterno (Internet) vengano loggate dal nostro server:

PIX(config)# aaa accounting any inbound 0.0.0.0 0.0.0.0 0.0.0.0 0.0.0.0 AuthInbound

Creazione delle utenze locali

Per una questione di fallback, prima di salvare la suddetta configurazione, conviene creare delle utenze locali utilizzando il comando:

PIX(config)# username <user> password <pass>

ed abbiamo finito.

Alla prossima.

Nginx e CentOS: creare un load balancer per i Websocket di nodejs

In questo post ho riportato il codice bash (di mia stesura) necessario per eseguire l’applicativo nodejs come demone (senza avvelersi quindi di tool esterni quali nohup o screen). In soldoni, esso non fa altro che tirare su (o stoppare/riavviare) 8 istanze di nodejs (ciascuna delle quali è in ascolto su una porta TCP dedicata, dalla 9001 alla 9008), il cui compito è quello di gestire le connessioni Websocket in ingresso (tramite la libreria socket.io ed il metodo HTTP Upgrade).

Nel caso in cui vi fosse la necessità di distribuire le istanze di nodejs su più macchine (per questioni di ridondanza e di suddivisione del carico), è indispensabile avvalersi di un bilanciatore in grado di gestire la suddetta tipologia di traffico (Websocket).

A tal proposito, se si vuole optare per una soluzione “software”, non si hanno tantissime alternative e le più gettonate sono sicuramente HAProxy e Nginx. Il primo è un bilanciatore a tutti gli effetti, mentre il secondo è un server Web (a detta di molti più performante e malleabile di Apache), che però può essere configurato a mo’ di load balancer.

La scelta è ricaduta proprio su Nginx perchè si è rivelato essere molto più stabile rispetto ad HAProxy (quest’ultimo crashava inesorabilmente se le richieste di connessione provenivano dal browser Safari).

Di seguito riporto la configurazione di Nignx, supponendo che vi siano 3 frontend da bilanciare, ciascuno dei quali dotato di 8 istanze nodejs:

upstream node_app {
    ip_hash;
    server node1.domain.com:9001;
    server node1.domain.com:9002;
    server node1.domain.com:9003;
    server node1.domain.com:9004;
    server node1.domain.com:9005;
    server node1.domain.com:9006;
    server node1.domain.com:9007;
    server node1.domain.com:9008;
    server node2.domain.com:9001;
    server node2.domain.com:9002;
    server node2.domain.com:9003;
    server node2.domain.com:9004;
    server node2.domain.com:9005;
    server node2.domain.com:9006;
    server node2.domain.com:9007;
    server node2.domain.com:9008;
    server node3.domain.com:9001;
    server node3.domain.com:9002;
    server node3.domain.com:9003;
    server node3.domain.com:9004;
    server node3.domain.com:9005;
    server node3.domain.com:9006;
    server node3.domain.com:9007;
    server node3.domain.com:9008;
}

server {
    server_name lblive.domain.com;
    listen 80;
    location / {
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_http_version 1.1;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_pass http://node_app;
    }
}

La configurazione è abbastanza intuitiva: nella prima parte viene definito l’elenco dei frontend e la politica di bilanciamento (stickyip_hash), mentre nella seconda parte vengono definite le regole per la gestione del traffico (soprattutto per ciò che concerne gli header HTTP).

A configurazione completata avviamo Nginx:

[root@loadbalancer ~]# service nginx start

e facciamo in modo che venga eseguito automaticemente dopo ogni riavvio:

[root@loadbalancer ~]# chkconfig nginx on

E’ tutto. Alla prossima.

RANCID e CentOS: creare un sistema centralizzato di controllo e backup per le configurazioni dei dispositivi di rete

Avere a disposizione uno o più backup della configurazione dei dispositivi di rete è indispensabile, soprattutto nell’ottica di un eventuale disaster recovery. Inoltre, tenere traccia (mediante versioning) delle modifiche apportate alle suddette configurazioni ci può certamente aiutare a tracciare le operazioni svolte dai vari sistemisti di rete (oppure ad identificare eventuali modifiche “malevoli” effettuate dagli hacker/cracker di turno).

Il software (open source) che fa al caso nostro prende il nome di RANCID ed in questo post vedremo come installarlo e configurarlo su una macchina CentOS 6.5.

router_ciscoInstallazione

Prima di eseguire l’installazione vera e propria occorre fare una premessa: tale applicativo verrà installato mediante repository yum e non mediante compilazione dei sorgenti, in modo da risparmiarci tutta una trafila di configurazioni aggiuntive che introdurrebbero solo entropia alla nostra attività.

Per prima cosa, quindi, è necessario installare il repository EPEL da cui attingere per ottenere il suddetto software. Una volta fatto ciò possiamo passare all’installazione vera e prorpia dell’applicativo, digitando:

[root@linuxbox opt]# yum install rancid

Configurazione

Editiamo il file di configurazione /etc/rancid/rancid.conf, apportando le seguenti modifiche:

FILTER_PWDS=YES; export FILTER_PWDS
NOCOMMSTR=YES; export NOCOMMSTR
LIST_OF_GROUPS="main-office branch-office"
MAILHEADERS=""; export MAILHEADERS

Da notare che tali opzioni ci consentono, nell’ordine, di:

1) filtrare le password dalla configurazione backuppata. Ad esempio, per i dispositivi di casa Cisco, la secret è in formato digest MD5 mentre le altre password (se il comando service password-encryption è stato abilitato) sono in formato “digest” proprietario, che è assolutamente reversibile, quindi insicuro;

2) filtrare le community string utilizzate dal protocollo SNMP. Certo, nel caso in cui si stia utilizzando il suddetto protocollo nella versione 1 o 2 tale informazione può essere facilmente ricavata sniffando il traffico in oggetto, ma questa operazione è comunque più complicata (sia dal punto di vista logistico che da quello tecnico) rispetto alla lettura di un file di configurazione in cui le community string sono riportate in chiaro;

3) definire i gruppi di dispositivi da monitorare. Nel mio caso ho identificato solo 2 gruppi, ovvero branch-office (uffici periferici) e main-office (ufficio centrale). Entrambi utilizzano dei dispositivi di rete marchiati Cisco (router e switch);

4) non customizzare l’header delle email di notifica inviate da RANCID.

Controlliamo che sia presente il cron job in grado di lanciare la verifica delle configurazioni in modo automatico ad ogni ora:

[root@linuxbox opt]# cat /etc/cron.d/rancid

il cui contenuto dovrà essere:

SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/var/rancid
# Run config differ hourly
1 * * * * rancid /usr/libexec/rancid/rancid-run

Ora verifichiamo che sia presente il file di configurazione relativo a logrotate, il cui scopo è quello di ruotare ad intervalli regolari i file di log generati da RANCID:

[root@linuxbox rancid]# cat /etc/logrotate.d/rancid

il cui contenuto dovrà essere:

/var/log/rancid/* {
    weekly
    rotate 1
    notifempty
    missingok
    compress
    olddir old
}

Infine, verifichiamo che sia presente l’utente rancid (creato in automaticamente durante l’installazione dell’applicativo in questione):

[root@linuxbox rancid]# finger rancid
Login: rancid                           Name: RANCID
Directory: /var/rancid/                 Shell: /bin/bash
Never logged in.
No mail.
No Plan.

Se tutte le verifiche preliminari sono andate a buon fine possiamo dedicarci all’inizializzazione del repository CVS (versioning) di RANCID, lanciando i comandi:

[root@linuxbox opt]# su rancid
[rancid@linuxbox opt]$ /usr/bin/rancid-cvs

Posizioniamoci adesso nella home dell’utente e creiamo il file (nascosto) .cloginrc. Esso conterrà tutte le informazioni necessarie a RANCID per effettuare il login in modo automatizzato sui dispositivi di rete.

[rancid@linuxbox opt]$ cd --
[rancid@linuxbox opt]$ nano .cloginrc

Il cui contenuto dovrà avere il seguente formato:

add method <IP> <protocollo>
add user <IP> <username>
add password <IP> <password> <enable password>

ad esempio:

add method 192.168.1.1 ssh
add user 192.168.1.1 admin
add password 192.168.1.1 p4ssw0rd s3cr3t3n4bl3

Assegniamo i giusti permessi al file appena creato:

[rancid@linuxbox opt]$ chmod 700 .cloginrc

e lanciamo manualmente un login di prova, individuando dapprima dove si trova il binario clogin:

[rancid@linuxbox opt]$ locate clogin

il cui output potrebbe essere:

/usr/libexec/rancid/clogin

quindi digitiamo:

[rancid@linuxbox opt]$ /usr/libexec/rancid/clogin <IP>

Nel caso in cui volessimo testare contemporaneamente il login e l’invio di un comando specifico, possiamo utilizzare il comando:

[rancid@linuxbox opt]$ /usr/libexec/rancid/clogin -t <timeout> -c "comando1;comando2" <IP>

A questo punto occorre fare una precisazione: poichè alcuni tool messi a disposizione dal nostro applicativo fanno uso implicito di clogin, è necessario che il suo percorso venga esportato tra le variabili d’ambiente. Per fare ciò è necessario lanciare il comando:

[rancid@linuxbox opt]$ export PATH=$PATH:/usr/libexec/rancid

Adesso possiamo testare il funzionamento di RANCID per il singolo apparato, digitando:

[rancid@linuxbox opt]$ rancid -t <tipo> <IP>

dove <tipo> rappresenta, molto banalmente, il tipo di dispositivo di rete (marca e macromodello – per una panoramica dei dispositivi supportati potete consultare il file /etc/rancid/rancid.types.base).

Ora possiamo dedicarci all’editing dei gruppi. In particolare, tale attività consta di una sola operazione, ovvero l’inserimento all’interno del file router.db delle specifiche dei dispositivi di rete che intendiamo monitorare.

Però, prima di fare ciò, occorre indentificare la versione di RANCID installata, lanciando il comando:

[root@linuxbox ~]# rancid -V

Ciò è fondamentale poichè dalla versione 3.0 è stato introdotto il supporto all’IPv6, che, come sapete, utilizza abbondantemente i :. Proprio per questo motivo, il formato del contenuto del file router.db è diventato simile al seguente:

IP;marca;stato

anzichè:

IP:marca:stato

Premesso che la versione installata è la 3.1, il file router.db per il gruppo main-office avrà questo contenuto:

192.168.1.1;cisco;up
192.168.1.2;cisco;up

mentre per il gruppo branch-office avremo:

192.168.110.1;cisco;up
192.168.111.1;cisco;up
192.168.112.1;cisco;up
192.168.113.1;cisco;up
192.168.114.1;cisco;up
192.168.115.1;cisco;up

Testiamo RANCID sui gruppi:

[rancid@linuxbox rancid]$ rancid-run main-office
[rancid@linuxbox rancid]$ rancid-run branch-office

e definiamo gli indirizzi a cui dovranno essere inviate le email di allarme/notifica:

[root@linuxbox rancid]# nano /etc/aliases
rancid-main-office: vostro.indirizzo@email.it
rancid-admin-main-office: vostro.indirizzo@email.it
rancid-branch-office: vostro.indirizzo@email.it
rancid-admin-branch-office: vostro.indirizzo@email.it

In particolare, ciascun gruppo necessità di 2 indirizzi email: uno per il recapito delle informazioni “standard” e l’altro per le notifiche agli amministratori di rete.

Rendiamo effettive le modifiche apportate al file /etc/aliases:

[root@linuxbox rancid]# newaliases

e passiamo all’integrazione con tac_plus.

Integrazione tra RANCID e tac_plus

In questo post ho illustrato i vari step necessari per la creazione di un server AAA basato sul demone tac_plus (ed il protocollo made in Cisco TACACS+). Adesso faremo in modo che RANCID possa collegarsi ai vari dispositivi di rete contattando direttamente il server AAA. Nella fattispecie, è sufficiente editare il file /etc/tac_plus.conf aggiungendo le seguenti direttive:

user = rancid {

        login = des CjzxbdLRbG6sY

        service = exec {
                priv-lvl = 15
        }

        cmd = show { permit .* }
        cmd = exit { permit .* }
        cmd = dir { permit .* }
        cmd = more { permit .* }
        cmd = write { permit term }
}

dove la password (in formato DES + salt) è stata creata utilizzando l’applicativo tac_pwd. Da notare che all’utente rancid viene garantito il login in modalità enable (privilege 15 in gergo Cisco) e gli viene data la possibilità di lanciare 5 comandi (e relativi sub comandi), ovvero show, exit, dir, more e write.

Ricarichiamo la configurazione del demone tac_plus:

[root@linuxbox rancid]# service tac_plus reload

ed abbiamo finito.

Alla prossima.