Archivi tag: acl named

Nagios: script bash per monitorare lo stato dei volumi RAID

Partendo dalle considerazioni fatte in questo post, ho deciso di mettere a punto uno script bash da integrare a Nagios, in modo da monitorare lo status dei volumi RAID (e dei dischi fisici annessi) a prescindere dal metodo utilizzato per l’implementazione di tale tecnologia (hardware, fake oppure software).

nagiosDi seguito riporto il suddetto script nella sua interezza:

#!/bin/bash

type=$1

subtype=$2

element=$3

usage="check_raid <--software|--fake|--hardware> [--megaraid|--mpt] [--volume|--physical|--battery]"

if [[ ! -z "$type" && "$type" =~ "software" ]];then
        okswraid=0;
        koswraid=0;
        volumes=`cat /proc/mdstat | grep md | grep active | grep -v inactive | awk '{print $1}' | wc -l`
        if [[ ! -z $volumes ]];then
                for (( v=1; v<=$volumes; v++ ))
                do
                        volume=`cat /proc/mdstat | grep md | grep active | grep -v inactive | awk '{print $1}' | sed -n "$v p"`
                        raidtype=`cat /proc/mdstat | grep md | grep active | grep -v inactive | awk '{print $4}' | sed -n "$v p"`
                        diskno=`cat /proc/mdstat | grep '[[0-9]\/[0-9]]' | awk '{print $3}' | sed -n "$v p"`
                        disksok=`echo $diskno | sed 's/\[//g' | cut -d '/' -f1`
                        diskstotal=`echo $diskno | sed 's/\]//g' | cut -d '/' -f2`
                        if [[ "$disksok" -eq "$diskstotal" ]];then
                                echo "OK: Software RAID volume $volume configured in $raidtype is OK, with $diskno disks UP"
                                ((okswraid++))
                        elif [[ "$disksok" -lt "$diskstotal" ]];then
                                echo "CRITICAL: Software RAID volume $volume configured in $raidtype is CRITICAL, with $diskno disks UP"
                                ((koswraid++))
                        fi
                done

                if [[ $koswraid -eq 0 ]];then
                        exit 0;
                else
                        exit 2;
                fi
        else
                echo "UNKNOWN: No software RAID configured"
                exit 3;
        fi

elif [[ ! -z "$type" && "$type" =~ "fake" ]];then
        bin=`/usr/bin/which dmraid`
        if [[ ! -z $bin ]];then
                result=`$bin -s`
                disksno=`$bin -r | grep -v no | wc -l`
                disksok=`$bin -r | grep ok | wc -l`
                if [[ ! -z "$result" && "$result" =~ "ok" ]];then
                        echo "OK: RAID Status is OK, with $disksok/$disksno disks OK"
                        exit 0;
                elif [[ ! -z "$result" && "$result" =~ "no raid" ]];then
                        echo "UNKNOWN: no fake RAID configured"
                        exit 3;
                else
                        echo "CRITICAL: RAID Status is KO, with $disksok/$disksno disks OK"
                        exit 2;
                fi
        else
                echo "UNKNOWN: no dmraid binary found - please install dmraid"
                exit 3;
        fi

elif [[ ! -z "$type" && "$type" =~ "hardware" ]];then
        okraid=0;
        oksmart=0;
        koraid=0;
        kosmart=0;
        if [[ ! -z "$subtype" && "$subtype" =~ "--megaraid" ]];then
                bin=`/usr/bin/which MegaCli64`
                if [[ ! -z $bin ]];then
                        if [[ ! -z "$element" && "$element" =~ "--volume" ]];then
                                result=`$bin -LDinfo -Lall -aALL | grep State | awk '{print $3}'`
                                if [[ ! -z "$result" && $result =~ "Optimal" ]];then
                                        echo "OK: RAID Volume state is $result"
                                        exit 0;
                                else
                                        echo "CRITICAL: RAID Volume state is $result"
                                        exit 2;
                                fi
                        elif [[ ! -z "$element" && "$element" =~ "--physical" ]];then
                                diskno=`$bin -PDList -aALL | grep "S.M.A.R.T alert" | wc -l`
                                for (( d=1; d<=$diskno; d++ ))
                                do
                                        result=`$bin -PDList -aALL | grep "Firmware state" | sed -n "$d p" | awk '{print $3}' | sed 's/,//g'`
                                        if [[ ! -z "$result" && $result =~ "Online" ]];then
                                                echo "RAID Status for Physical Disk number $d is OK"
                                                ((okraid++));
                                        else
                                                echo "RAID Status for Physical Disks number $d is KO"
                                                ((koraid++));
                                        fi
                                done
                                for (( d=1; d<=$diskno; d++ ))
                                do
                                        result=`$bin -PDList -aALL | grep "S.M.A.R.T alert" | sed -n "$d p" | awk '{print $8}'`
                                        if [[ ! -z "$result" && $result =~ "No" ]];then
                                                echo "S.M.A.R.T Status for Physical Disk number $d is OK"
                                                ((oksmart++));
                                        else
                                                echo "S.M.A.R.T. Status for Physical Disks number $d is KO"
                                                ((kosmart++));
                                        fi
                                done
                                if [[ $koraid -eq 0 && $kosmart -eq 0 ]];then
                                        echo "OK: RAID and S.M.A.R.T Status for all Physical Disks is OK"
                                        exit 0;
                                elif [[ $koraid -eq 0 && $kosmart -ne 0 ]];then
                                        echo "CRITICAL: S.M.A.R.T Status for some Physical Disks is KO"
                                        exit 2;
                                elif [[ $koraid -ne 0 && "$kosmart" -eq 0 ]];then
                                        echo "CRITICAL: RAID Status for some Physical Disks is KO"
                                        exit 2;
                                elif [[ $koraid -ne 0 && $kosmart -ne 0 ]];then
                                        echo "CRITICAL: RAID and S.M.A.R.T Status for some Physical Disks is KO"
                                        exit 2;
                                fi
                        elif [[ ! -z "$element" && "$element" =~ "--battery" ]];then
                                result=`$bin -AdpBbuCmd -aAll | grep "Battery State" | awk '{print $3}'`
                                if [[ ! -z "$result" && $result =~ "OK" ]];then
                                        echo "OK: RAID Controller Battery state is OK"
                                        exit 0;
                                else
                                        echo "CRITICAL: RAID Controller Battery state is $result"
                                        exit 2;
                                fi
                        else
                                echo "UNKNOWN: please specify the element to check"
                                echo $usage;
                                exit 3;
                        fi
                else
                        echo "UNKNOWN: No MegaCli64 binary found - please install MegaCli64"
                        exit 3;
                fi

        elif [[ ! -z "$subtype" && "$subtype" =~ "mpt" ]];then
                modprobe mptctl
                bin=`/usr/bin/which mpt-status`
                bin2=`/usr/bin/which lspci`
                bin3=`/usr/bin/which daemonize`
                if [[ ! -z $bin ]];then
                        if [[ ! -z $bin2 ]];then
                                controller_status=`lspci | grep MPT`
                                if [[ ! -z $controller_status ]];then
                                        if [[ ! -z $bin3 ]];then
                                                controller=`$bin -p | grep id | awk '{print $3}' | sed 's/id=//g' | sed 's/,//g'`
                                                if [[ ! -z $controller ]];then
                                                        result=`$bin -i $controller | grep OPTIMAL`
                                                        if [[ ! -z "$result" ]];then
                                                                echo "OK: RAID Status is OPTIMAL"
                                                                exit 0;
                                                        else
                                                                echo "CRITICAL: RAID Status is DEGRADED"
                                                                exit 2;
                                                        fi
                                                else
                                                        echo "UNKNOWN: MPT Controller found but no RAID configured";
                                                        exit 3;
                                                fi
                                        else
                                                echo "UNKNOWN: No daemonize binary found - please install daemonize";
                                                exit 3;
                                        fi
                                else
                                        echo "UNKNOWN: Unable to find RAID Controller";
                                        exit 3;
                                fi
                        else
                                echo "UNKNOWN: No lspci binary found - please install lspci";
                                exit 3;
                        fi
                else
                        echo "UNKNOWN: No mpt-status binary found - please install mpt-status"
                        exit 3;
                fi

        else
                echo "UNKNOWN: please specify the RAID Controller type"
                echo $usage
                exit 3;
        fi
else
        echo "UNKNOWN: please specify the RAID type"
        echo $usage
        exit 3;
fi
exit 0

Lo usage parla chiaro: il primo argomento identifica, per l’appunto, la tecnologia RAID utilizzata sul sistema target. Il secondo ed il terzo argomento, invece, dovranno essere specificati solo nel caso in cui si abbia a che fare con un RAID di tipo hardware. Nella fattispecie, essi rappresentano, rispettivamente, la tipologia di chipset utilizzata dal controller e l’oggetto di interesse della nostra query, ovvero il volume, i dischi fisici oppure la batteria (tale parametro ha senso solo se il chipset è di tipo LSI MegaRAID).

Configurazione di Nagios

Come al solito, il primo step consiste nel definire un comando che utilizzi lo script (in gergo plugin) riportato in precedenza:

# 'check_local_raid' command definition
define command{
        command_name    check_local_raid
        command_line    $USER1$/check_raid $ARG1$ $ARG2$ $ARG3$
        }

tali direttive andranno opportunamente inserite all’interno del file /etc/nagios/objects/commands.cfg.

Successivamente si potrà procedere con la definizione del servizio che si occuperà del monitoraggio vero e proprio, da aggiungere alla configurazione dell’host target, in questo caso /etc/nagios/object/locahost.cfg:

define service{
        use                             local-service         ; Name of service template to use
        host_name                       localhost
        service_description             RAID Status
        check_command                   check_local_raid!--software
        }

A questo punto non ci rimane che ricaricare la configurazione di Nagios per rendere effettive le suddette modifiche:

[root@linuxbox ~]# service nagios reload

ed abbiamo finito.

Alla prossima.

Lavorare con le ACL Cisco

Premesso che di ACL Cisco ne esistono una miriade, le tre tipologie più utilizzate sono le seguenti:

1) standard;

2) estese;

3) nominali.

Esse si differenziano per le funzionalità che offrono e per il tipo di filtraggio che possono mettere in atto.

 

timthumb.php.png

Ad esempio, le ACL standard (il cui ID può essere compreso tra 1 e 99) consentono di filtrare il traffico relativo ad una determinata sorgente. Eccone un esempio:

access-list 1 permit 172.16.0.0 0.0.255.255

Le ACL estese (ID da 100 a 199), invece, consentono di specificare sorgente e destinazione del traffico, oltre al tipo di protocollo che deve essere filtrato. Ad esempio:

 access-list 101 deny tcp 172.16.2.0 0.0.0.255 172.16.4.0 0.0.0.255 eq 21
 access-list 101 permit ip 172.16.3.0 0.0.0.255 any

nega il traffico FTP (tcp eq 21) proveniente dalla net 172.16.2.0/24 e diretto alla net 172.16.4.0/24, permette tutto il traffico (ip) proveniente dalla net 172.16.3.0/24 e nega tutto il resto (il deny any any è implicito).

Infine, le ACL nominali offrono le stesse funzionalità delle ACL estese, ma anzichè essere caratterizzate da un ID, può essere assegnato loro un nome. Inoltre, se un’ACL nominale deve essere aggiornata, non è necessario rimuoverla completamente, ricrearla con le opportune modifiche e ricaricarla sul dispositivo Cisco, ma è sufficiente aggiungere la nuova regola in una posizione ben precisa. Ad esempio, date le seguenti regole associate all’ACL nominale chiamata inbound:

 access-list inbound line 1 permit tcp any host 192.168.1.1 eq 4662
 access-list inbound line 2 permit udp any host 192.168.1.1 eq 4666

se volessimo aggiungere una regola in posizione 2, basterebbe scrivere:

access-list inbound line 2 permit tcp any host 192.168.1.1 eq 6881

e dopo uno sh access-list inbound otterremo il seguente output:

 access-list inbound line 1 permit tcp any host 192.168.1.1 eq 4662
 access-list inbound line 2 permit tcp any host 192.168.1.1 eq 6881
 access-list inbound line 3 permit udp any host 192.168.1.1 eq 4666

La posizione delle regole è molto importante nelle ACL, in quanto esse seguono una logica top-down e si arrestano al primo hit.

Se ad esempio definissimo un’ACL del tipo:

 access-list inbound line 1 permit tcp any host 192.168.1.1 eq 4662
 access-list inbound line 2 deny tcp any host 192.168.1.1 eq 4662
 access-list inbound line 3 permit udp any host 192.168.1.1 eq 4666

il traffico tcp diretto alla porta 4662 dell’host 192.168.1.1 sarebbe consentito, e la entry immediatamente successiva verrebbe completamente ignorata.

Un’altra comodità delle ACL nominali è data dalla possibilità di cancellare solo una determinata regola. Ad esempio, mediante il comando:

no access-list inbound line 2 deny tcp any host 192.168.1.1 eq 4662

verrebbe rimossa solo la regola numero 2 e non l’intera ACL (come accadrebbe se utilizzassimo un’ACL standard o estesa).

Assegnazione dell’ACL ad un’interfaccia

Una volta creata l’ACL sarà necessario assegnarla ad un’interfaccia.

Il comando da utilizzare è il seguente:

Router(config-if)# ip access-group <ID o nome ACL> in

per filtrare il traffico in ingresso, oppure:

Router(config-if)# ip access-group <ID o nome ACL> out

per filtrare il traffico in uscita.

Esiste comunque una convenzione relativa al posizionamento delle ACL, ovvero:

1) le ACL standard devono essere posizionate il più vicino possibile alla destinazione del traffico;

2) le ACL estese devono essere posizionate il più vicino alla sorgente del traffico.

Visualizzazione delle ACL

Per avere l’intera lista delle ACL presenti sulla nostra macchina, basta digitare:

Router# sh access-list

mentre se volessimo listare le regole che costituiscono una determinata ACL, occorre lanciare il comando:

Router# sh access-list <ID o nome ACL>

Con questi comandi sarà anche possibile visualizzare il numero di pacchetti che hanno matchato l’ACL (ovvero il cosiddetto hit count, e non hitch count come ho sentito dire a qualche pseudo sistemista).

Eccone un esempio:

 Router#sh access-list 101
 Extended IP access list 101
 10 deny ip host 255.255.255.255 any log
 20 deny ip 10.0.0.0 0.255.255.255 any log (33 matches)
 30 deny ip 172.16.0.0 0.15.255.255 any log
 40 deny ip 192.168.0.0 0.0.255.255 any log (7298 matches)
 50 deny ip 224.0.0.0 15.255.255.255 any log

Logging del traffico matchato dalle ACL

Abilitare il logging delle delle regole ACL matchate è banale. Basta infatti aggiungere il suffisso log alla regola stessa:

access-list 101 deny tcp 172.16.2.0 0.0.0.255 172.16.4.0 0.0.0.255 eq 21 log

Operazioni sulle ACL

Se si lavora con le ACL standard o estese è opportuno fare molta attenzione. La prima regola consiste nel disassociare l’ACL all’interfaccia, in modo da non rischiare di perdere la connettività verso il dispositivo Cisco (se stiamo interagendo con una sessione vty).

Il comando da utilizzare è il seguente:

Router(config-if)#no ip access-group <ID o nome ACL> in

In secondo luogo, conviene copiare tutto il contenuto dell’ACL ed incollarlo in un editor di testo, in modo da avere piena visione delle regole e poterle modificare con un basso margine di errore.

Logica di creazione delle ACL

Le ACL possono essere create seguendo due logiche:

1) negare esplicitamente il traffico vietato e consentire tutto il resto;

2) negare esplicitamente il traffico vietato, consentire quello lecito e negare tutto il resto.

Inutile dire che la seconda logica è molto più sicura ma implica un maggiore numero di regole. Di seguito un esempio di ACL che nega tutto il traffico non esplicitamente consentito:

 access-list 101 deny ip host 255.255.255.255 any log
 access-list 101 deny ip 10.0.0.0 0.255.255.255 any log
 access-list 101 deny ip 172.16.0.0 0.15.255.255 any log
 access-list 101 deny ip 192.168.0.0 0.0.255.255 any log 
 access-list 101 deny ip 224.0.0.0 15.255.255.255 any log
 access-list 101 permit tcp any any eq 2283 
 access-list 101 permit tcp any any eq 443 
 access-list 101 permit tcp any any eq 3000
 access-list 101 permit tcp any any eq 6881
 access-list 101 permit tcp any any eq 6882
 access-list 101 permit tcp any any eq 4662 
 access-list 101 permit udp any any eq 4666 
 access-list 101 permit udp any any eq 20
 access-list 101 permit tcp any any eq ftp 
 access-list 101 permit tcp any any eq 123
 access-list 101 permit tcp any any eq 5002
 access-list 101 permit udp any any eq 5002
 access-list 101 permit tcp any eq www any log 
 access-list 101 permit tcp any eq 443 any log
 access-list 101 permit tcp any eq ftp any log 
 access-list 101 permit udp any eq 20 any log
 access-list 101 permit tcp any eq 22 any log 
 access-list 101 permit tcp any eq 2283 any log 
 access-list 101 permit tcp any eq telnet any log 
 access-list 101 permit tcp any eq smtp any log 
 access-list 101 permit tcp any eq 465 any log 
 access-list 101 permit tcp any eq 995 any log 
 access-list 101 permit tcp any eq 993 any log 
 access-list 101 permit tcp any eq pop3 any log 
 access-list 101 permit tcp any eq domain any log
 access-list 101 permit udp any eq domain any log 
 access-list 101 permit tcp any gt 1023 any log 
 access-list 101 permit icmp any any echo-reply log

Prima nego il traffico IP spoofing, successivamente consento il traffico da Internet verso alcuni servizi della LAN, consento anche alcuni tipi di traffico della LAN verso Internet e nego tutto il resto (come già detto, il deny any any è implicito).

CBAC ed ip inspect

Alcuni device di casa Cisco possiedono un firewall embedded che crea automaticamente delle ACL (CBAC) per consentire il traffico proveniente dalla LAN e diretto all’esterno (Internet), realizzando inoltre dei meccanismi di stateful inspection. Inutile dire che tale funzionalità è molto comoda, in quanto riduce notevolmente il numero di regole ACL da dichiarare (almeno per ciò che concerne il traffico rete interna -> Internet).

Il comando per abilitare il CBAC è ip inspect (come illustrato in questo post) e per farlo funzionare occorre associarlo all’interfaccia del router che si affaccia alla rete interna (ed esempio e0), in modo da controllare il traffico in uscita:

Router(config-if)# ip inspect <nome dell'insieme delle regole di firewalling> out

Fine del post, alla prossima.