Archivi tag: powershell

NRPE_NT e Nagios: script PowerShell per il controllo dell’uptime su Windows Server 2008 R2

Tenere sotto controllo l’uptime dei nostri server è molto importante, soprattutto se si ha a che fare con macchine in produzione. Per ciò che concerne i sistemi operativi di casa Microsoft (sia client che server), esiste un comando che può tornarci molto utile allo scopo, ovvero:

net stats srv

il quale, basandosi sul servizio Server di Windows, colleziona e fornisce tutta una serie di informazioni associate alla nostra macchina, tra cui, per l’appunto, il suo tempo di attività:

Statistics since 7/11/2016 9:21:08 AM

powershellAffinchè il suddetto task possa essere effettuato in automatico dal nostro NMS (Nagios), è necessario utilizzare uno scrip (get_uptime.ps1, creato da me allo scopo) da integrare al servizio NRPE_NT. Per ragioni di semplicità e comodità ho deciso di avvalermi di Windows PowerShell per la stesura dello stesso, il cui contenuto è il seguente:

$critical = $Args[0]
$warning = $Args[1]

if ($warning -and $critical) #both variable are defined and not empty
{
    if ($critical -lt $warning)
    {
        $os = Get-WmiObject win32_operatingsystem
        $uptime = (Get-Date) - ($os.ConvertToDateTime($os.lastbootuptime))
        $minutes_to_seconds = $Uptime.Minutes*60
        $hours_to_seconds = $Uptime.Hours*3600
        $days_to_seconds = $Uptime.Days*86400
        $uptime_in_seconds = $minutes_to_seconds + $hours_to_seconds + $days_to_seconds
        if ($uptime_in_seconds -gt $critical -and $uptime_in_seconds -gt $warning)
        {
            $Display = "OK: System Uptime is " + $Uptime.Days + " days, " + $Uptime.Hours + " hours, " + $Uptime.Minutes + " minutes"
            Write-Output $Display
            exit 0
        }
        elseif ($uptime_in_seconds -gt $critical -and $uptime_in_seconds -le $warning)
        {
            $Display = "WARNING: System Uptime is " + $Uptime.Days + " days, " + $Uptime.Hours + " hours, " + $Uptime.Minutes + " minutes"
            Write-Output $Display
            exit 1
        }
        else
        {
            $Display = "CRITICAL: System Uptime is " + $Uptime.Days + " days, " + $Uptime.Hours + " hours, " + $Uptime.Minutes + " minutes"
            Write-Output $Display
            exit 2
        }
    }
    else
    {
        $Usage = "Usage: .\get_uptime.ps1 <critical threshold in seconds> <warning threshold in seconds>"
        $Error1 = "Warning threshold must be greater then the critical one"
        Write-Output $Usage
        Write-Output $Error1
        exit 3
    }
}
else
{
    $Usage = "Usage: .\get_uptime.ps1 <critical threshold in seconds> <warning threshold in seconds>"
    $Error2 = "Warning threshold and critical threshold must be defined"
    Write-Output $Usage
    Write-Output $Error2
    exit 3
}

In soldoni, il suddetto scrip riceve due argomenti da linea di comando, ovvero la soglia critica e quella di warning, espresse entrambe in secondi. Ovviamente, trattandosi di tempo di attività, la prima deve essere strettamente minore della seconda.

Configurazione di NRPE_NT

Salviamo tale scrip all’interno della directory C:\nrpe\Plugins\V2 e successivamente editiamo il file C:\nrpe\Plugins\V2\V2_nrpe_commands.cfg, aggiungendo la seguente direttiva:

# =================================
# Windows System Uptime checks
# =================================

command[get_system_uptime]=cmd.exe /c echo C:\nrpe\Plugins\V2\get_uptime.ps1 "$ARG1$" "$ARG2$" | powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -command -

In particolare, stiamo definendo il comando get_system_uptime che si avvarrà di get_uptime.ps1 per l’individuazione del tempo di attività.

Occorre precisare che l’esecuzione dello scrip non può avvenire richiamando direttamente l’eseguibile powershell.exe, ma deve prima passare per cmd.exe (il cui output, mediante pipe, viene dato in pasto a PowerShell grazie alla direttiva -command –, dove il finale rappresenta “tutto ciò che proviene dal pipe”). Inoltre, si rende indispensabile bypassare l’executionpolicy di PowerShell, consentendo ad NRPE_NT di lanciare get_uptime.ps1 senza restrizioni.

Infine, riavviamo NRPE_NT per rendere effettive le suddette modifiche:

C:\Users\Administrator> net stop nrpe_nt
C:\Users\Administrator> net start nrpe_nt

Configurazione di Nagios

Per prima cosa è necessario creare un apposito comando all’interno del file /etc/nagios/object/commands.cfg:

# nagios-Windows-uptime check command definition

define command {
        command_name    check_Windows_uptime
        command_line    /usr/lib64/nagios/plugins/check_nrpe -H $HOSTADDRESS$ -t $ARG1$ -c get_system_uptime -a $ARG2$ $ARG3$
        }

Successivamente, all’interno del file che rappresenta l’host da monitorare, è necessario aggiungere un servizio specifico che si avvale del suddetto comando:

define service{
        use                             generic-service         ; Name of service template to use
        host_name                       Windows-Server
        service_descripion             query Windows System Uptime for Microsoft Windows Machine
        check_command                   check_Windows_uptime!30!60!900
        }

Ricarichiamo la configurazione di Nagios:

[root@linuxbox ~]# service nagios reload

ed abbiamo finito.

Alla prossima.

NRPE_NT e Nagios: tenere sotto controllo gli aggiornamenti di Windows

Installare prontamente gli aggiornamenti di Windows, soprattutto se si ha a che fare con i security update, è sempre cosa buona e giusta. Spesso, però, capita che l’amministratore di sistema debba gestire N macchine e non abbia il tempo materiale di loggarsi su ciascuna di esse e constatare l’eventuale disposnibilità di aggiornamenti. Personalmente credo che non li si debba mai scaricare nè tantomeno installare automaticamente sulla macchina ospite, soprattutto se si ha a che fare con dei sistemi in produzione.

Cosa fare dunque per automatizzare tale task di verifica della disponibilità degli aggiornamenti? Semplice, utilizzare il nostro NMS preferito, ovvero Nagios.

nagiosIngredienti

Per prima cosa è necessario che sulla macchina da monitorare sia installato (ed attivo) il servizio NRPE_NT. Inoltre, ai plugin utilizzati dal servizio in questione, occorre aggiungere uno scrip PowerShell creato appositamente. Infine,  occorre creare su Nagios un comando ed un servizio specifico, in modo che il nostro NMS sia in grado di effettuare il controllo degli aggiornamenti in modo automatico e ad intervalli di tempo regolari.

Configurazione di NRPE_NT

Poichè la verifica della disponibilità degli aggiornamenti è un’operazione che può richiedere parecchio tempo, è necessario fare in modo che il timeout di NRPE_NT venga appositamente incrementato, editando la direttiva command_timeout presente all’interno del file nrpe.cfg (nel mio caso ho impostato una soglia pari a 600 secondi):

command_timeout= 600

Per ciò che concerne lo scrip PowerShell, esso può essere scaricato da qui, per poi posizionarlo all’interno della directory Plugins di NRPE_NT. A questo punto, sempre lato NRPE_NT, è possibile creare un comando specifico che si occuperà di verificare la disponibilità degli aggiornamenti di Windows. Tale definizione va inserita all’interno del file V2_nrpe_commands.cfg e presenta la seguente struttura:

command[get_windows_updates]=cscrip.exe //nologo //T:600 c:\nrpe\plugins\v2\check_windows_updates.wsf /w:0 /c:1

Restartiamo infine il servizio NRPE_NT mediante i comandi:

net stop NRPE_NT
net start NRPE_NT

e passiamo alla configurazione di Nagios.

Configurazione di Nagios

Come già affermato in precedenza, la configurazione dell’NMS si basa su due passaggi: la creazione del comando e l’assegnazione del check che ne fa uso ad un servizio legato all’host da monitorare.

Di seguito riporto il comando (da inserire nel file commands.cfg presente in /etc/nagios/objects):

# nagios-WMI-windows-updates check command definition

define command {
        command_name    check_WMI_windows_updates
        command_line    /usr/lib64/nagios/plugins/check_nrpe -H $HOSTADDRESS$ -t $ARG1$ -c get_windows_updates
        }

Mentre il servizio è così definito:

define service{
        use                             generic-service         ; Name of service template to use
        host_name                       Windows-Machine
        service_description             query WMI Updates for Microsoft Windows Machine
        check_command                   check_WMI_windows_updates!600
        normal_check_interval           120
        }

Da notare che l’unico parametro passato al comando riguarda il numero di secondi di attesa (600) prima del timeout. Inoltre, ho fatto in modo che i check vengano eseguiti a distanza di 2 ore l’uno dall’altro (normal_check_interval 120).

A configurazione ultimata riavviamo Nagios per rendere effettive le modifiche:

[root@NMS ~]# service nagios reload

In caso di disponibilità di aggiornamenti, il cruscotto dell’NMS ci apparirà in un modo simile al seguente:

cruscotto_nagios

Alla prossima.

NRPE_NT: script powershell per la modifica della direttiva allowed_hosts in nrpe.cfg

Scenario

Sistema di monitoraggio (Nagios) connesso ad Internet mediante indirizzo IP pubblico di tipo dinamico. Esso deve tenere sotto controllo, tramite opportune query NRPE, alcuni servizi attivi su di un server remoto (Windows 2008 R2), raggiungibile mediante FQDN ed IP statico.

powershellProblema

Per evitare che eventuali client non autorizzati possanno connettersi al servizio NRPE_NT in ascolto sul server remoto (porta 5666/TCP), è possibile definire, all’interno del suo file di configurazione (nrpe.cfg), gli indirizzi IP a cui è consentito eseguire le query. Ad esempio, mediante la direttiva allowed_hosts, siamo in grado di dichiarare la seguente regola:

allowed_hosts=79.37.83.59

ed ecco, per l’appunto, dov’è il problema: essendo il suddetto indirizzo definito in modo statico, nel momento in cui, per un motivo o per un altro, Nagios dovesse cambiare il proprio IP pubblico, le query NRPE fallirebbero miseramente (check timeout).

Soluzione

A questo punto è necessario fare una premessa: esiste una soluzione più pulita di quella che sto per riportare, che consiste, fondamentalmente, nell’uso di NSClient++ abbinato ad NRPE_NT, grazie ai quali è possibile realizzare un meccanismo di autenticazione client/server mediante lo scambio di certificati X.509 (in tal caso la direttiva allowed_host sarebbe del tutto superflua poichè autenticazione e confidenzialità verrebbero garantite mediante i suddetti certificati).

Per ciò che concerne, invece, la soluzione da me individuata, essa consiste nella realizzazione di uno scrip powershell che “interroga” l’FQDN di Nagios ogni 5 minuti, verificando che il suo indirizzo IP pubblico sia diverso da quello presente nel file di configurazione di NRPE. In tal caso lo scrip modificherà l’IP definito nella direttiva allowed_hosts.

Di seguito riporto il contenuto dello scrip:

$IP = nslookup nagios.vostrodominio.com | Select-String -Pattern '\d{1,3}(\.\d{1,3}){3}' | Select-String -notmatch 'IP del server da monitorare'

$PublicIP = $IP.tostring().Split(" ")[-1]

$OldIP = (Get-Content C:\nrpe\bin\nrpe.cfg) | Select-String 'allowed_hosts=\d{1,3}(\.\d{1,3}){3}'

$OldPublicIP = $OldIP.tostring().Split("=")[-1]

$data = Get-Date;

if ($PublicIP -ne $OldPublicIP -and $PublicIP)
{

    (Get-Content C:\nrpe\bin\nrpe.cfg) -replace 'allowed_hosts=\d{1,3}(\.\d{1,3}){3}', "allowed_hosts=$(echo $PublicIP)" | Set-Content C:\nrpe\bin\nrpe.cfg

    net stop nrpe_nt

    Start-Sleep -s 5

    net start nrpe_nt

    echo "$data NRPE_NT configuration has been updated. The new authorized Public IP is $PublicIP"

    exit 0;
}
else
{
    echo "$data Nothing to do. Exiting..."

    exit 0;
}

Per prima cosa ho individuato l’indirizzo IP pubblico di Nagios mediante una query di tipo A effettuata mediante nslookup:

$IP = nslookup nagios.vostrodominio.com | Select-String -Pattern '\d{1,3}(\.\d{1,3}){3}' | Select-String -notmatch 'IP del server da monitorare'

$PublicIP = $IP.tostring().Split(" ")[-1]

Ovviamente ho dovuto formattare l’output relativo alla suddetta query, identificando, tramite espressione regolare, le stringhe che riportano gli indirizzi IP coinvolti, escludendo successivamente quella che contiene l’IP del server da monitorare. Inoltre, è stato necessario salvare (dopo opportuna conversione) l’indirizzo IP di Nagios all’interno della variabile $PublicIP.

Discorso molto simile riguarda l’individuazione dell’IP configurato all’interno di nrpe.cfg, ottenuta mediante l’applet Get-Content:

$OldIP = (Get-Content C:\nrpe\bin\nrpe.cfg) | Select-String 'allowed_hosts=\d{1,3}(\.\d{1,3}){3}'

$OldPublicIP = $OldIP.tostring().Split("=")[-1]

A questo punto è stato possibile procedere con il confronto tra l’IP attuale di Nagios e quello presente nel file di configurazione di NRPE_NT. Nel caso in cui questi differiscano (e la variabile $PublicIP non sia nè vuota, nè nulla), la direttiva allowed_hosts verrà modificata, con il conseguente riavvio del servizio in oggetto:

(Get-Content C:\nrpe\bin\nrpe.cfg) -replace 'allowed_hosts=\d{1,3}(\.\d{1,3}){3}', "allowed_hosts=$(echo $PublicIP)" | Set-Content C:\nrpe\bin\nrpe.cfg

    net stop nrpe_nt

    Start-Sleep -s 5

    net start nrpe_nt

    echo "$data NRPE_NT configuration has been updated. The new authorized Public IP is $PublicIP"

Infine, per eseguire tale scrip in modo automatico, ho creato un task mediante l’applicativo Task Scheduler di Windows, il quale si ripete giornalmente ogni 5 minuti e la cui azione è la seguente:

powershell -command "C:\Users\Administrator\Documents\scrip\nrpe_ip_update.ps1 >> C:\nrpe_ip_update.log"

Da ora in poi le query NRPE da indirizzo IP dinamico non saranno un problema.

A presto.

Modifica delle ACL NTFS mediante PowerShell

Scenario

Una macchina con a bordo Windows Server 2008 R2 che funge da Web server (IIS7). Si vuole fare in modo che gli utenti possano effettuare l’upload (mediante un form opportunamente creato) di immagini e file di vario genere.

Problema

Le ACL NTFS relative alla root directory di IIS (ovvero C:\inetpub\wwwroot) non consentono le operazioni di modifica agli utenti Web anonimi (appartenenti al gruppo IIS_IUSRS), ergo qualsiasi tentativo di upload avrà esito negativo. Inoltre, l’alberatura delle sottodirectory è abbastanza complessa ed è qualcosa del tipo /nomesubdir/immagini, in cui nomesubdir è variabile (ce ne sono circa un migliaio), mentre immagini è la dir di destinazione degli upload (sulla quale bisogna garantire i permessi di modifica).

Soluzione

La prima soluzione che viene in mente prevede per lo più tanta pazienza ed un lavoro certosino da attuare, fondamentalmente, in 2 passaggi: l’accesso manuale a ciascuna subdir e la modifica delle ACL NTFS per la directory immagini ivi contenuta.

La seconda soluzione è certamente più rapida e smart: creare uno scrip PowerShell in grado di modificare le suddette ACL per tutte le directory immagini poste all’interno delle subdir.

powershellEcco lo scrip:

$Acl = Get-Acl "C:\inetpub\wwwroot\*\immagini"
$Ar = New-Object  system.security.accesscontrol.filesystemaccessrule("IIS_IUSRS","Modify","ContainerInherit, ObjectInherit", "None","Allow")
foreach($Ac in $Acl)
{
    $Ac.SetAccessRule($Ar)
    Set-Acl "C:\inetpub\wwwroot\*\immagini" $Ac
}

Esso prevede, in soldoni, 2 fasi: la prima in cui vengono identificati i permessi relativi alla directory immagini presente in ciascuna subdir  (mediante la cmdlet Get-Acl); la seconda in vengono definiti i nuovi permessi per il gruppo IIS_IUSRS, applicandoli a tutte le  immagini (ed ai file in esse contenuti).

Rollback

Naturalmente la modifica dei permessi NTFS associati a file e cartelle è sempre un’operazione abbastanza invasiva e delicata, ergo è opportuno garantirsi la possibilità di ripristinare la situazione iniziale (ovvero quella precedente alle suddette modifiche).

Ecco lo scrip in grado di effettuare il rollback dei permessi:

$Acl = Get-Acl "C:\inetpub\wwwroot\*\immagini"
$Ar = New-Object  system.security.accesscontrol.filesystemaccessrule("IIS_IUSRS","Modify","ContainerInherit, ObjectInherit", "None","Allow")
foreach($Ac in $Acl)
{
    $Ac.RemoveAccessRuleAll($Ar)
    Set-Acl "C:\inetpub\wwwroot\*\immagini" $Ac
}

La logica è sempre la stessa, l’unica variazione riguarda la funzione RemoveAccessRuleAll($Ar) che ha sostituito la SetAccessRule($Ar) utilizzata in precedenza.

Alla prossima.

Script powershell per identificare le password di dominio “deboli”

Ogni tanto fare una sorta di security audit sulla nostra rete è cosa buona e giusta, soprattutto se in passato questo task è stato totalmente ingnorato dai sistemisti di turno.

Proprio per questo motivo, ho pensato di realizzare un scrip powershell in grado di testare la robustezza delle password utilizzate dalle varie utenze di dominio.

powershellPreparazione

Per prima cosa occorre creare una lista di password “deboli” all’interno di un file di testo (weakpasswords.txt). Tale file dovrà contenere una sola password per riga, ad esempio:

 password1
 password2
 password3

Una volta fatto ciò occorre salvare in un altro file di testo le utenze di dominio, lanciando tale comando direttamente sul domain controller:

NET USERS /DOMAIN > users.txt

Il contenuto del file users.txt sarà simile al seguente:

User accounts for \\DC
------------------------------------------------------------------ utente1                        utente2               utente3  utente4                        utente5               utente6

Affinchè lo scrip possa funzionare, però, è necessario che vi sia un solo utente per riga, ergo bisogna parsare il file users.txt e salvare il suo contenuto (opportunamente formattato) all’interno di un altro file (parsed.txt). Per farè ciò ho utilizzato awk (su una Linux box):

[root@server ~]# cat users.txt | awk '{print $1}' >> parsed.txt
[root@server ~]# cat users.txt | awk '{print $2}' >> parsed.txt
[root@server ~]# cat users.txt | awk '{print $3}' >> parsed.txt

Contenuto dello script

Adesso il file parsed.txt può essere spostato sul DC e possiamo creare il nostro scrip (che chiameremo testauth.ps1) il cui contenuto dovrà essere:

Function Test-ADAuthentication {
    param($username,$password)
    (new-object directoryservices.directoryentry "",$username,$password).psbase.name -ne $null
}

$users = Get-Content parsed.txt 
foreach ($user in $users) {
    $user = $user.Trim()
    $passwords = Get-Content weakpasswords.txt
    foreach ($password in $passwords) {
        $password = $password.Trim()
        $result = Test-ADAuthentication "NOMEDOMINIO\$user" "$password"
        if ($result -like "True") {
            echo "Username $user has got a the weak password $password" >> passresult.txt
        }
        else
        {
            echo "Password for user $user did not match" 
        }
    }
}

Esecuzione

Non ci resta che eseguire tale scrip powershell mediante il comando:

./testauth.ps1

e successivamente verificare il contenuto del file passresult.txt, in cui saranno presenti le associazioni utente/password “debole”.

Alla prossima.