Come aggiungere una FortiGate VM in GNS3

GNS3 è uno strumento particolarmente comodo per costruire laboratori di networking senza dover necessariamente utilizzare apparati fisici. Nel caso di Fortinet è possibile eseguire anche una FortiGate VM, collegandola a router, switch, client e altri firewall virtuali per provare configurazioni, routing e scenari di laboratorio.

Fortinet ha pubblicato un Technical Tip che descrive la procedura per aggiungere una FortiGate VM a GNS3 e indica come ambito FortiOS 6.0, 6.2, 6.4, 7.0, 7.2, 7.4 e 7.6.

La parte importante da capire è che servono due elementi distinti:

  • l’immagine FortiGate VM per KVM, scaricata dal portale Fortinet;
  • il template dell’appliance FortiGate utilizzato da GNS3.

Una volta associati i due elementi, FortiGate diventa un normale nodo utilizzabile all’interno delle topologie GNS3.

Prerequisiti

Prima di iniziare è necessario avere:

  • GNS3 installato;
  • preferibilmente la GNS3 VM configurata e funzionante;
  • un account Fortinet/FortiCare;
  • accesso al download delle immagini FortiGate VM;
  • l’appliance FortiGate disponibile nel Marketplace GNS3;
  • virtualizzazione hardware abilitata sulla macchina che esegue GNS3.

Fortinet suggerisce l’utilizzo della GNS3 VM per questo tipo di appliance. Anche GNS3 utilizza normalmente i template del Marketplace per installare macchine virtuali di produttori esterni e la GNS3 VM permette di eseguire le VM QEMU/KVM nell’ambiente dedicato.

Scaricare l’immagine FortiGate VM

Il primo elemento necessario è il firmware FortiGate VM.

Dal portale di supporto Fortinet bisogna accedere alla sezione dedicata alle VM Images, selezionare la release FortiOS che si vuole utilizzare e scegliere come piattaforma:

1
KVM

GNS3 utilizzerà infatti l’immagine destinata alla virtualizzazione KVM.

Il nome esatto dei menu del portale Fortinet può cambiare nel tempo, ma nel Technical Tip il percorso viene indicato come:

1
Support -> VM Images

Da qui si seleziona la versione FortiOS desiderata e si scarica l’immagine KVM.

È preferibile conservare il file originale senza modificarlo finché non viene richiesto esplicitamente durante l’importazione dell’appliance.

Scaricare il template FortiGate da GNS3

Il secondo elemento è l’appliance FortiGate presente nel Marketplace GNS3.

La pagina dedicata è:

FortiGate Appliance - GNS3 Marketplace

Qui è utile fare una distinzione tra template appliance e immagine FortiOS.

La documentazione GNS3 identifica i template appliance con estensione .gns3a; questi descrivono come GNS3 deve creare ed eseguire la macchina virtuale. L’immagine FortiOS vera e propria rimane invece quella scaricata dal portale Fortinet.

Questa distinzione è importante perché la formulazione del Technical Tip Fortinet in questo passaggio può risultare poco chiara: operativamente il Marketplace GNS3 fornisce la definizione dell’appliance, mentre il firmware FortiGate deve essere ottenuto legittimamente da Fortinet.

Importare FortiGate in GNS3

A questo punto è possibile aprire GNS3.

Prima di procedere conviene verificare che la GNS3 VM sia connessa e operativa.

Nel wizard delle appliance selezionare:

1
Browse all appliances

quindi creare o importare un nuovo template e scegliere l’installazione dell’appliance sul server GNS3.

Nella lista dei dispositivi cercare:

1
FortiGate

e procedere con l’installazione.

GNS3 mostrerà le versioni FortiOS già conosciute dal template.

Fortinet segnala che le versioni FortiOS più recenti potrebbero non essere ancora presenti nell’elenco perché il repository delle appliance GNS3 deve essere aggiornato.

Questo non significa necessariamente che la release non possa essere utilizzata.

Utilizzare una versione FortiOS non presente nell’elenco

Se la versione scaricata dal portale Fortinet non compare tra quelle proposte dal template, nel wizard è possibile utilizzare:

1
Create a new version

e creare una nuova voce corrispondente alla release FortiOS che si vuole importare.

Successivamente bisogna associare al template l’immagine KVM scaricata dal portale Fortinet.

Il Technical Tip mostra proprio questo scenario: una release FortiOS più recente rispetto a quelle già presenti nel repository GNS3 viene aggiunta manualmente creando una nuova versione.

Questo passaggio è particolarmente utile quando si vuole costruire un laboratorio utilizzando una specifica versione FortiOS senza dover aspettare che il template ufficiale GNS3 venga aggiornato.

Creare la prima topologia

Terminata l’importazione, FortiGate comparirà nell’elenco dei dispositivi disponibili in GNS3.

È quindi possibile creare un nuovo progetto:

1
File -> New Blank Project

e trascinare FortiGate all’interno della topologia.

Per un primo test è sufficiente collegare port1 a una rete dalla quale sia possibile raggiungere la VM.

Una topologia minima può essere concettualmente composta da:

1
2
3
4
5
6
7
8
PC / Host
|
|
FortiGate
port1
|
|
NAT / rete GNS3

Il Technical Tip Fortinet utilizza, come esempio, una rete NAT appartenente alla subnet:

1
192.168.82.0/24

assegnando alla port1 del FortiGate:

1
192.168.82.2/24

Si tratta solamente dell’indirizzamento utilizzato nell’esempio Fortinet: nel proprio laboratorio bisogna naturalmente utilizzare la subnet effettivamente collegata all’interfaccia.

Configurare port1

Dopo aver avviato FortiGate, aprire la console del dispositivo da GNS3.

Per poter raggiungere l’interfaccia web è necessario assegnare un indirizzo IP alla porta collegata alla rete di management e consentire l’accesso HTTPS.

Riprendendo l’indirizzamento utilizzato nell’esempio Fortinet, una configurazione potrebbe essere:

1
2
3
4
5
6
7
config system interface
edit "port1"
set mode static
set ip 192.168.82.2 255.255.255.0
set allowaccess ping https ssh
next
end

Il comando configura port1 con l’indirizzo 192.168.82.2/24 e abilita sulla stessa interfaccia:

  • ping, utile per i test di raggiungibilità;
  • https, necessario per accedere alla GUI;
  • ssh, utile per amministrare FortiGate da terminale.

ssh non è indispensabile per il solo accesso web e può essere omesso se non serve nel laboratorio.

È possibile verificare la configurazione con:

1
show system interface port1

oppure controllare lo stato delle interfacce con:

1
get system interface physical

Una volta verificata la connettività, l’interfaccia grafica sarà raggiungibile utilizzando nel browser l’indirizzo configurato sulla port1, come previsto anche dalla procedura Fortinet.

Nel nostro esempio:

1
https://192.168.82.2

FortiGate VM e licenza di valutazione

L’avvio della macchina virtuale e l’importazione in GNS3 non vanno confusi con la licenza FortiOS.

Fortinet mette a disposizione una modalità di valutazione per FortiGate VM e il Technical Tip richiama esplicitamente la Permanent Evaluation License. Per utilizzarla è necessario un account Fortinet/FortiCare. La licenza di valutazione è pensata per ambienti di test e presenta limitazioni rispetto a una licenza FortiGate VM completa.

Per un HomeLab è quindi importante verificare separatamente:

  1. quale immagine FortiOS si può scaricare;
  2. quale modalità di licensing è disponibile per quella versione;
  3. quali limitazioni introduce la licenza di valutazione.

Questo evita di costruire un laboratorio dando per scontato che tutte le funzionalità disponibili su un FortiGate licenziato siano utilizzabili nello stesso modo sulla VM di evaluation.

Se FortiGate non parte

Durante l’importazione ci sono alcuni punti che conviene controllare prima di modificare il template.

La versione FortiOS non compare

Non è necessariamente un problema.

Se l’immagine è più recente rispetto alla versione conosciuta dal template GNS3, utilizzare:

1
Create a new version

e associare manualmente l’immagine KVM.

La VM non si avvia correttamente

Controllare innanzitutto che la GNS3 VM sia attiva e che KVM sia disponibile.

GNS3 segnala esplicitamente che, quando il supporto KVM non è disponibile all’interno della GNS3 VM, bisogna verificare che la virtualizzazione hardware sia abilitata nel BIOS/UEFI e correttamente esposta all’ambiente virtuale.

Prima di cercare problemi nell’immagine FortiGate conviene quindi verificare l’infrastruttura GNS3.

La GUI non è raggiungibile

Controllare dalla console FortiGate:

  • che l’interfaccia corretta abbia un indirizzo IP;
  • che l’interfaccia sia operativamente attiva;
  • che il PC abbia connettività verso quella subnet;
  • che sull’interfaccia sia consentito https.

Ad esempio:

1
show system interface port1

e verificare la presenza di:

1
set allowaccess ping https

In un laboratorio è spesso utile partire verificando prima il ping e solo successivamente l’accesso HTTPS.

Una base utile per i laboratori Fortinet

Una volta creato correttamente il template, non è necessario ripetere tutta la procedura per ogni progetto.

La FortiGate VM rimane infatti disponibile tra i dispositivi GNS3 e può essere utilizzata per costruire topologie molto più articolate.

Ad esempio:

1
2
3
4
5
6
7
8
9
LAN-A
|
FGT-A
|
Router
|
FGT-B
|
LAN-B

oppure laboratori con più sedi nei quali testare:

  • routing statico;
  • OSPF;
  • BGP;
  • VLAN;
  • policy firewall;
  • NAT;
  • VPN IPsec;
  • SD-WAN;
  • configurazioni multi-FortiGate.

La parte più importante è quindi preparare correttamente una prima appliance FortiGate funzionante. Da quel momento GNS3 può diventare un ambiente molto comodo per riprodurre configurazioni e scenari di rete senza dover necessariamente disporre di più firewall fisici.

Riferimenti

Usare grep -f su FortiGate per cercare più oggetti contemporaneamente

Durante un’attività su FortiGate mi sono trovato a dover recuperare la configurazione di diversi oggetti presenti all’interno di alcuni Address Group.

Il problema era abbastanza semplice: avevo molti oggetti da cercare e lanciare un grep -f separato per ciascuno sarebbe stato inutilmente scomodo.

È possibile invece sfruttare le espressioni regolari supportate da grep nella CLI FortiGate per cercare più oggetti contemporaneamente:

1
show | grep -f "OBJ1\|OBJ2\|OBJ3"

In questo modo possiamo cercare in una sola volta tutti gli oggetti indicati e, grazie all’opzione -f, ottenere il relativo contesto di configurazione.

Il comportamento di grep sulla CLI FortiGate

FortiOS permette di utilizzare grep per filtrare l’output di diversi comandi CLI, ad esempio:

1
show | grep OGGETTO

Una ricerca di questo tipo restituisce però principalmente le righe che corrispondono al pattern cercato.

Quando stiamo analizzando una configurazione spesso questo non basta: conoscere la singola riga in cui compare un oggetto è meno utile rispetto a vedere il blocco di configurazione nel quale viene utilizzato.

Per questo può essere utilizzata l’opzione:

1
-f

Ad esempio:

1
show | grep -f OBJ1

grep -f permette di visualizzare il contesto di configurazione relativo alla corrispondenza trovata.

È particolarmente utile per capire rapidamente dove viene referenziato un oggetto senza dover scorrere manualmente l’intera configurazione.

Cercare più oggetti contemporaneamente

La parte interessante è che il pattern passato a grep può essere una regular expression.

Possiamo quindi utilizzare l’operatore OR per indicare più stringhe:

1
show | grep -f "OBJ1\|OBJ2\|OBJ3"

Il pattern:

1
OBJ1\|OBJ2\|OBJ3

può essere letto come:

1
OBJ1 OR OBJ2 OR OBJ3

Il comando cercherà quindi una corrispondenza con uno qualsiasi degli oggetti specificati.

Questo diventa molto comodo quando la lista comincia ad essere lunga:

1
show | grep -f "SERVER01\|SERVER02\|SERVER03\|SERVER04\|SERVER05"

invece di eseguire:

1
2
3
4
5
show | grep -f SERVER01
show | grep -f SERVER02
show | grep -f SERVER03
show | grep -f SERVER04
show | grep -f SERVER05

Il caso pratico degli Address Group

Nel mio caso il comando è risultato utile durante un’attività nella quale dovevo riportare diversi Address Group e i relativi Address Object.

Un Address Group può contenere molti oggetti e, una volta recuperata la lista dei membri, è possibile costruire rapidamente una ricerca unica.

Supponiamo ad esempio di avere come membri:

1
2
3
4
SERVER01
SERVER02
SERVER03
SERVER04

Possiamo cercarli tutti contemporaneamente con:

1
show | grep -f "SERVER01\|SERVER02\|SERVER03\|SERVER04"

Questo permette di trovare i blocchi di configurazione nei quali compare almeno uno degli oggetti.

È utile anche per capire dove gli oggetti vengono referenziati, perché la ricerca viene effettuata sull’output completo di show.

Limitare la ricerca agli Address Object

Se invece l’obiettivo è esclusivamente recuperare la definizione degli Address Object, è preferibile restringere il comando alla sezione interessata.

Ad esempio:

1
show firewall address | grep -f "SERVER01\|SERVER02\|SERVER03\|SERVER04"

Rispetto a:

1
show | grep -f "SERVER01\|SERVER02\|SERVER03\|SERVER04"

la differenza è importante.

Il primo comando cerca solamente all’interno di:

1
config firewall address

ed è quindi più adatto quando dobbiamo recuperare la configurazione degli oggetti stessi.

Il secondo cerca invece nell’intera configurazione visibile tramite show ed è utile quando vogliamo individuare anche altri punti nei quali gli oggetti vengono utilizzati, ad esempio gruppi o firewall policy.

La scelta dipende quindi da ciò che stiamo cercando.

Recuperare gli oggetti

1
show firewall address | grep -f "SERVER01\|SERVER02\|SERVER03"

Cercare tutti i riferimenti

1
show | grep -f "SERVER01\|SERVER02\|SERVER03"

Questa distinzione è particolarmente utile durante migrazioni o attività di pulizia della configurazione.

Attenzione alla sintassi

Il comando deve essere scritto in questo modo:

1
show | grep -f "OBJ1\|OBJ2\|OBJ3"

Se il comando viene copiato da chat, documentazione Markdown o altri sistemi di formattazione è possibile ritrovarsi accidentalmente qualcosa del genere:

1
OBJ1**\|**OBJ2**\|**OBJ3

Gli ** non fanno parte della sintassi di FortiGate: sono normalmente marcatori utilizzati da Markdown per il testo in grassetto.

La stringa da passare realmente a grep rimane:

1
OBJ1\|OBJ2\|OBJ3

Quando può essere utile

Oltre al caso degli Address Group, lo stesso approccio può tornare comodo quando bisogna:

  • individuare più Address Object;
  • verificare contemporaneamente diversi riferimenti;
  • analizzare una configurazione prima di una migrazione;
  • recuperare rapidamente configurazioni da riportare su un altro FortiGate;
  • verificare dove vengono utilizzati più oggetti;
  • ridurre il numero di ricerche manuali sulla configurazione.

Per pochi oggetti la differenza è minima, ma quando bisogna lavorare con gruppi composti da decine di elementi poter costruire una singola espressione rende l’attività decisamente più rapida.

Riferimenti

Fortinet documenta l’utilizzo di grep nella CLI FortiGate nella sezione CLI basics della FortiOS Administration Guide:

Fortinet Documentation - CLI basics

È disponibile inoltre un Technical Tip Fortinet dedicato all’utilizzo del filtro grep nella CLI:

Fortinet Community - Technical Tip: The usage of grep filter command on the FortiGate CLI

Il punto interessante da ricordare è soprattutto la combinazione tra grep -f e una regular expression con più alternative:

1
show | grep -f "OBJ1\|OBJ2\|OBJ3"

Per attività di migrazione o analisi di configurazioni FortiGate è uno di quei piccoli comandi che evita parecchio lavoro ripetitivo.

Preparare e convertire automaticamente le foto per Waveshare PhotoPainter e display e-paper

Il problema che volevo risolvere

Uso un Waveshare PhotoPainter originale da 7,3 pollici, con display e-paper a 7 colori e risoluzione 800×480. :-D

È un oggetto che mi piace parecchio, soprattutto per utilizzarlo come cornice fotografica, ma dopo averci caricato un po’ di fotografie mi sono scontrato con un problema abbastanza pratico: preparare bene le immagini richiede molto più lavoro di quanto sembri.

Il display ha soltanto 800×480 pixel. Proprio per questo non voglio sprecarne neanche uno.

Con una fotografia orizzontale il problema è relativamente semplice. Con le fotografie verticali, invece, bisogna decidere cosa sacrificare: ritagliare aggressivamente la foto, lasciare dello spazio ai lati oppure trovare un compromesso.

E se le fotografie diventano 50, 100 o diverse centinaia, fare tutto manualmente diventa rapidamente noioso.

Da questa esigenza è nato PhotoPainter Cropper & Converter.

È un piccolo tool che gira interamente nel browser e che ho realizzato per:

  • caricare interi gruppi di fotografie;
  • scegliere velocemente il ritaglio di ogni foto;
  • adattarle esattamente alla risoluzione dello schermo;
  • gestire meglio le fotografie verticali;
  • ricordare i crop già effettuati;
  • convertire automaticamente le immagini nella palette del display e-paper;
  • generare i BMP pronti per PhotoPainter;
  • scaricare tutto in un unico ZIP.

La cosa importante è che tutta l’elaborazione avviene localmente nel browser: le fotografie non vengono inviate a nessun server.

Il tool è disponibile direttamente qui:

PhotoPainter Cropper & Converter

Prima di tutto: capire come convertiva le immagini PhotoPainter

Il primo problema non era realizzare l’interfaccia di crop.

Quella era la parte relativamente semplice.

Il problema vero era riuscire a generare un’immagine che il PhotoPainter interpretasse esattamente nello stesso modo di quella prodotta dagli strumenti che utilizzavo normalmente.

Ho quindi fatto un po’ di reverse engineering del processo di conversione, cercando di replicarne il comportamento.

Nel mio caso il display di riferimento è:

1
2
3
Waveshare PhotoPainter originale / 7.3" HAT (F)
Risoluzione: 800x480
Palette: ACeP 7 colori

La palette utilizzata dal tool è composta da:

1
2
3
4
5
6
7
Nero
Bianco
Verde
Blu
Rosso
Giallo
Arancione

Naturalmente una fotografia normale contiene milioni di possibili colori, mentre questo display può rappresentarne soltanto sette.

Serve quindi una fase di quantizzazione.

Nel tool ho replicato la conversione utilizzando il dithering Floyd–Steinberg.

In pratica, per ogni pixel viene cercato il colore più vicino disponibile nella palette del display. L’errore introdotto da questa approssimazione viene poi distribuito sui pixel vicini.

La distribuzione utilizzata è quella classica:

1
2
        X   7/16
3/16 5/16 1/16

Il risultato finale non aumenta ovviamente il numero reale di colori del pannello, ma sfrutta la disposizione dei pixel per ottenere una resa visiva molto più convincente rispetto a una semplice conversione al colore più vicino.

Dopo la quantizzazione, il tool genera direttamente un BMP 24 bit bottom-up, nel formato utilizzato dalla pipeline che volevo replicare.

Ho confrontato il risultato su decine e successivamente centinaia di fotografie e, nei miei test, sono riuscito ad arrivare allo stesso risultato della conversione originale, fino ad ottenere immagini con i pixel risultanti identici.

A quel punto potevo finalmente eliminare dal mio workflow la conversione manuale e inglobare tutto nello stesso strumento.

Dal crop alla conversione, tutto dentro una pagina HTML

La prima versione del mio workflow non era nemmeno un’applicazione web.

Avevo due script Python separati:

  1. uno script con interfaccia Tkinter per ritagliare manualmente le fotografie;
  2. uno script che effettuava la conversione nel BMP richiesto dal display.

Successivamente ho deciso di riunire tutto.

L’attuale PhotoPainter Cropper & Converter è quindi scritto in HTML, CSS e JavaScript ed è contenuto in un unico file statico.

Non richiede installazione.

Non richiede Python.

Non richiede un backend.

Non richiede l’upload delle fotografie.

Può essere pubblicato come una normale pagina statica oppure aperto direttamente dal computer.

Non è limitato al mio PhotoPainter

Anche se il progetto è nato principalmente per il mio PhotoPainter 800×480 a 7 colori, ho cercato di non legarlo esclusivamente a quel modello.

All’apertura è possibile scegliere il dispositivo di destinazione.

Tra i profili presenti ci sono, ad esempio:

  • Waveshare PhotoPainter (B), 800×480, Spectra 6;
  • Waveshare PhotoPainter originale / 7.3” HAT (F), 800×480, ACeP 7 colori;
  • Waveshare 5.65” e-Paper (F), 600×448;
  • Waveshare 4.01” e-Paper HAT (F), 640×400;
  • Waveshare 4”/3.6” e-Paper HAT+ (E), 600×400;
  • Waveshare 13.3” e-Paper HAT+ (E), 1600×1200;
  • alcuni display Waveshare bianco/nero/rosso;
  • bianco/nero/giallo;
  • bianco e nero;
  • display in scala di grigi.

Ho aggiunto inoltre dei profili generici, nei quali è possibile indicare manualmente larghezza e altezza e scegliere la tipologia di palette:

1
2
3
4
5
6
7
Bianco/Nero
Bianco/Nero/Rosso
Bianco/Nero/Giallo
4 livelli di grigio
16 livelli di grigio
6 colori Spectra 6 / E6
7 colori ACeP

Quindi il cropper può essere utilizzato anche con altri display, purché il formato di output sia adatto al proprio workflow.

Il crop in batch

Il workflow che utilizzo normalmente parte da una cartella contenente tutte le fotografie che voglio preparare.

Dal tool posso selezionare direttamente la cartella oppure aggiungere le immagini separatamente.

A quel punto si passa all’editor.

Per ogni fotografia viene visualizzato il rettangolo corrispondente esattamente al rapporto d’aspetto del display scelto.

Nel mio caso:

1
800 / 480 = 1,666...

Posso quindi spostare e ridimensionare velocemente l’inquadratura fino a ottenere la composizione che voglio.

Questo è particolarmente utile quando preparo tante foto insieme: non voglio che sia un algoritmo a decidere automaticamente quale sia la parte importante della fotografia.

Se ci sono delle persone, ad esempio, voglio essere io a decidere chi deve rimanere al centro.

Mi è capitato anche di utilizzare la stessa fotografia in raccolte differenti con crop diversi. Per una raccolta destinata ai nonni, ad esempio, posso tranquillamente scegliere un’inquadratura maggiormente concentrata sui bambini piuttosto che sugli adulti.

È una piccola cosa, ma quando si preparano centinaia di immagini fa la differenza.

Le fotografie verticali e il riempimento sfocato

Questo è probabilmente l’aspetto che personalmente trovo più utile.

Una fotografia verticale e un display 800×480 orizzontale hanno rapporti d’aspetto completamente diversi.

Posso ovviamente ingrandire la fotografia fino a riempire lo schermo, ma in quel modo rischio di perdere una quantità enorme dell’immagine originale.

Oppure posso mantenere un’inquadratura più ampia.

A quel punto, però, alcune aree del frame rimangono fuori dalla fotografia.

Il tool permette di gestirle in due modi:

1
2
white
blur

Con white viene utilizzato semplicemente uno sfondo bianco.

Con blur, invece, viene generato uno sfondo utilizzando la fotografia stessa, ingrandita e fortemente sfocata, mentre la parte selezionata rimane nitida in primo piano.

È lo stesso tipo di effetto che si vede spesso nei player video o nelle applicazioni social quando un contenuto verticale deve essere mostrato all’interno di uno spazio orizzontale.

Nel mio caso lo preferisco nettamente alle bande vuote.

Soprattutto su un piccolo display 800×480 permette di sfruttare l’intera superficie mantenendo comunque visibile una porzione più grande della fotografia originale.

Il raggio della sfocatura viene inoltre calcolato proporzionalmente alla larghezza del display, quindi non è legato rigidamente agli 800 pixel del mio PhotoPainter.

L’altra cosa che mi serviva: ricordare tutti i crop

Dopo aver preparato parecchie fotografie mi sono accorto di un altro problema.

Immaginiamo di avere una raccolta di 100 fotografie.

Le preparo tutte, le converto e le metto sul PhotoPainter.

Passano quattro mesi.

Nel frattempo trovo altre venti fotografie e voglio aggiungerle alla raccolta.

Potrei naturalmente elaborare soltanto quelle nuove, ma magari riguardando le vecchie mi accorgo che su alcune vorrei modificare leggermente l’inquadratura.

Senza conservare lo stato precedente dovrei praticamente ricominciare da capo.

Per questo, insieme a ogni fotografia, PhotoPainter Cropper genera un piccolo file:

1
<nome>_ppcrop.txt

Al suo interno vengono memorizzate le informazioni necessarie per ricostruire il ritaglio.

Il formato contiene dati come:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
image_name=
image_w=
image_h=

rect_x1=
rect_y1=
rect_x2=
rect_y2=

rect_nx1=
rect_ny1=
rect_nx2=
rect_ny2=

target_w=
target_h=
ratio=
fill_mode=
device=

Oltre alle coordinate assolute salvo anche le coordinate normalizzate rispetto alla dimensione dell’immagine.

Questo permette al programma di recuperare la selezione anche quando le dimensioni dell’immagine non coincidono più esattamente con quelle memorizzate, purché siano disponibili le coordinate normalizzate.

Quando seleziono nuovamente una cartella, il programma associa automaticamente:

1
2
foto.jpg
foto_ppcrop.txt

e ripristina l’inquadratura precedente.

Questa, nel mio utilizzo, è diventata una delle funzioni più importanti.

Posso conservare insieme:

1
2
IMG_1234.jpg
IMG_1234_ppcrop.txt

e considerare il file TXT quasi come un piccolo file di progetto della fotografia.

La foto originale rimane intatta.

Il TXT descrive semplicemente come voglio visualizzarla sul PhotoPainter.

Lavorare velocemente con la tastiera

Un’altra esigenza nata dall’elaborazione di molte fotografie era evitare di dover cliccare continuamente sui pulsanti.

Il crop può quindi essere controllato quasi interamente dalla tastiera.

Le scorciatoie principali sono:

1
2
3
4
5
6
7
8
9
10
11
12
13
Frecce       sposta il crop
Shift+Frecce spostamento più rapido

+ / - ridimensiona il crop
Shift ridimensionamento più rapido

Invio conferma e passa alla foto successiva
Tab conferma e passa alla foto successiva
A conferma e passa alla foto successiva

Esc salta la fotografia

F alterna sfondo bianco / sfocato

È possibile utilizzare anche la rotellina del mouse per cambiare la dimensione del ritaglio.

Nella parte inferiore dell’editor è inoltre presente una barra con le miniature.

In questo modo posso vedere dove mi trovo nella raccolta, quali immagini ho già confermato e tornare rapidamente su una fotografia precedente.

Quando bisogna sistemare cento foto, queste piccole scorciatoie fanno risparmiare parecchio tempo.

Esportazione

Una volta completata la selezione si passa alla fase di esportazione.

Per ogni fotografia confermata il programma genera tre elementi:

1
2
3
<nome>_ppcrop.txt
<nome>_pp.jpg
<nome>_pp_scale_output.bmp

Il JPG contiene il risultato del crop.

Il BMP contiene invece l’immagine convertita nella palette del display selezionato con dithering Floyd–Steinberg.

È possibile scaricare i singoli file oppure generare direttamente:

1
photopainter_export.zip

All’interno dello ZIP viene mantenuta questa struttura:

1
2
3
4
5
6
7
8
9
10
11
foto1_ppcrop.txt
foto2_ppcrop.txt
foto3_ppcrop.txt

_export_photopainter_jpg/
├── foto1_pp.jpg
├── foto1_pp_scale_output.bmp
├── foto2_pp.jpg
├── foto2_pp_scale_output.bmp
├── foto3_pp.jpg
└── foto3_pp_scale_output.bmp

I file _ppcrop.txt possono poi essere riportati nella stessa cartella delle fotografie originali.

Al caricamento successivo il tool li riconoscerà e ripristinerà i crop.

Nessuna fotografia viene caricata online

Visto il tipo di dati che normalmente passo a questo strumento, per me era importante anche questo aspetto.

Le fotografie sono spesso foto personali e familiari.

PhotoPainter Cropper & Converter non necessita di inviarle da nessuna parte.

Il browser legge i file locali, effettua il crop, crea il canvas, esegue la quantizzazione, costruisce il BMP e infine crea anche lo ZIP.

Tutto avviene lato client.

Persino la generazione dello ZIP è implementata direttamente nella pagina, senza appoggiarsi a un servizio esterno.

Questo significa che posso utilizzare il programma anche semplicemente aprendo localmente il file HTML.

Un singolo file HTML

Alla fine il progetto è diventato volutamente molto semplice da distribuire.

Tutto è contenuto in un unico:

1
index.html

Al suo interno ci sono:

1
2
3
4
5
6
7
8
9
10
11
HTML
CSS
JavaScript
profili dei dispositivi
palette colori
editor Canvas
gestione dei file di stato
Floyd-Steinberg dithering
encoder BMP
generazione ZIP
traduzioni dell'interfaccia

L’interfaccia è disponibile in:

1
2
3
4
Italiano
English
Español
Français

Il browser prova a scegliere automaticamente la lingua, che può comunque essere cambiata dall’interfaccia.

Questa scelta rende il progetto molto semplice da pubblicare: non c’è un’applicazione da installare o un servizio da mantenere.

È semplicemente una pagina statica.

Provare PhotoPainter Cropper & Converter

Il tool è pubblicato qui:

https://5m1.ovh/PhotoPainterCropper/index.html

La procedura completa è:

  1. aprire PhotoPainter Cropper & Converter;
  2. scegliere il proprio display e-paper;
  3. caricare la cartella contenente le fotografie;
  4. includere gli eventuali _ppcrop.txt di una sessione precedente;
  5. iniziare il crop;
  6. posizionare e ridimensionare l’inquadratura;
  7. scegliere, quando necessario, tra riempimento bianco e sfocato;
  8. confermare le fotografie;
  9. passare all’esportazione;
  10. generare JPG e BMP;
  11. scaricare lo ZIP;
  12. conservare i file _ppcrop.txt insieme alle immagini originali.

Il codice sorgente sarà disponibile anche su GitHub:

[DA VERIFICARE: inserire URL repository GitHub]

Conclusioni

Questo progetto è nato semplicemente perché avevo un problema che continuava a ripresentarsi.

Volevo scegliere le mie fotografie preferite, visualizzarle sul PhotoPainter sfruttando al massimo quei 800×480 pixel e non perdere ogni volta tempo tra crop, fotografie verticali, conversioni e lavorazioni già fatte mesi prima.

Prima ho automatizzato il crop.

Poi la conversione.

Poi ho aggiunto il riempimento sfocato.

Poi mi sono accorto che avevo bisogno di ricordare le selezioni.

Alla fine tutto è finito in una singola pagina HTML che ormai utilizzo per elaborare intere raccolte di fotografie.

È esattamente il genere di progetto per cui esiste GeeGeek: qualcosa che mi serviva, che ho costruito per risolvere un mio problema concreto e che, una volta arrivato a funzionare come volevo, tanto vale condividere.

Se volete provarlo, lo trovate qui:

PhotoPainter Cropper & Converter

Spero possa essere utile anche a qualcun altro che utilizza un PhotoPainter, un display Waveshare o più in generale una cornice e-paper e si è trovato davanti allo stesso problema.

Impostazione dei permessi in /var/www/html con il bit SGID

Introduzione

Quando più utenti devono collaborare su un progetto in un ambiente
Linux, nasce l’esigenza di gestire correttamente i permessi su file e
directory. Per evitare che i file creati da un singolo utente assumano
come owner e group il suo gruppo primario, possiamo sfruttare il bit
SGID (Set Group ID) sulle directory condivise.

In questo articolo vedremo come impostare il bit SGID solo sulle
directory — perché è pensato esclusivamente per gestire l’ereditarietà
del gruppo —, così da semplificare la collaborazione in una struttura
come /var/www/html.

Il problema

Supponiamo che un utente (es. user1) carichi o modifichi file via FTP
nella directory /var/www/html. Di default, ogni file nuovo assume come
proprietario user1 e come gruppo il gruppo primario di user1 (es.
user1 stesso). Se vogliamo che il gruppo di questi file sia invece
www-data (tipico in ambiente web), dobbiamo configurare correttamente
i permessi e impostare il bit SGID sulle directory.

Obiettivi

  1. Far sì che tutte le directory sotto /var/www/html abbiano il
    gruppo www-data e il bit SGID attivo, in modo che qualsiasi file
    creato o caricato al loro interno eredi automaticamente il gruppo
    www-data.
  2. Applicare permessi ragionevoli per directory (2775) e file (0644),
    così da garantire che i membri del gruppo www-data possano
    interagire correttamente con il contenuto, mantenendo un livello di
    sicurezza adeguato.
  3. Verificare che tutti i file e le directory appartengano
    effettivamente al gruppo www-data.

Passo 1: Assegnare proprietà e gruppo a /var/www/html

Per prima cosa, se non l’hai già fatto, assegna ricorsivamente owner e
gruppo www-data:www-data a /var/www/html:

1
sudo chown -R www-data:www-data /var/www/html

Questo fa sì che l’utente e il gruppo su tutti i file e directory
all’interno di /var/www/html siano ora www-data:www-data.

Passo 2: Impostare i permessi sui file e sulle directory

Distinguiamo due situazioni: directory e file.

  1. Directory: vogliamo che abbiano i permessi 2775 (rwxrwsr-x).
    • Il “2” all’inizio indica il bit SGID, così che tutti i nuovi
      file/dir ereditino il gruppo della cartella madre (in questo
      caso, www-data).
    • “775” permette al proprietario (www-data) e al gruppo di
      leggere, scrivere ed entrare nella directory; gli “altri”
      possono solo leggere ed entrare (r-x).
  2. File: vogliamo che abbiano i permessi 0644 (rw-r--r--).
    • In questo modo, il proprietario e il gruppo possono leggere e
      scrivere, mentre gli altri possono solo leggere (nessuna
      esecuzione di default).

Per applicare questi permessi ricorsivamente:

1
2
3
4
5
# Imposta 2775 su tutte le directory
sudo find /var/www/html -type d -exec chmod 2775 {} \;

# Imposta 0644 su tutti i file
sudo find /var/www/html -type f -exec chmod 0644 {} \;

In questo modo, ogni directory avrà:
rwxrwsr-x www-data www-data (2775), mentre ogni file avrà:
rw-r--r-- www-data www-data (0644).

Passo 3: Verificare che il bit SGID sia applicato solo alle directory

Il bit SGID va usato solo sulle directory, non sui file. Se vuoi
controllare che nelle directory sia attivo, puoi eseguire:

1
ls -ld /var/www/html

Vedrai un output simile:

1
drwxrwsr-x  5 www-data www-data 4096 Jan 22 12:34 /var/www/html

dove la presenza di s nella sezione dei permessi del gruppo (rws)
indica che la directory ha il bit SGID attivo.

Se accidentalmente hai applicato SGID anche ai file, puoi rimuoverlo dai
soli file con:

1
sudo find /var/www/html -type f -exec chmod g-s {} \;

Passo 4: Verificare l’appartenenza al gruppo www-data

Infine, se vuoi controllare che tutti i file e le directory
appartengano al gruppo www-data (e segnalare se qualcosa non va), puoi
usare un comando find dedicato:

1
sudo find /var/www/html -not -group www-data -exec ls -l {} \;

Se non viene stampato nulla, significa che tutti gli elementi presenti
in /var/www/html hanno già il gruppo www-data.

Conclusioni

Configurare correttamente i permessi e il bit SGID in /var/www/html è
fondamentale per gestire un ambiente di sviluppo o produzione in cui più
utenti collaborano sui file. Impostando i permessi 2775 sulle directory
e 0644 sui file, e assicurandoti che il bit SGID sia attivo solo sulle
directory, potrai lavorare in modo coerente e ordinato, senza dover
correggere manualmente le impostazioni di proprietà ogni volta che
vengono caricati nuovi file.

Generazione e condivisione di password online tramite github Pages

Introduzione alla Sicurezza delle Password

Le password sono la prima linea di difesa per proteggere dati, account personali e risorse sensibili. Tuttavia, creare e ricordare password sufficientemente forti non è sempre semplice: è diffusa la cattiva abitudine di riutilizzare la stessa password per più servizi, oppure di crearne una troppo semplice e prevedibile.

Inoltre, quando si tratta di condividere queste credenziali con un collega, un collaboratore o un familiare, spesso vengono utilizzati canali non sicuri come email non cifrate o messaggistica istantanea. Questo tipo di condivisione espone a notevoli rischi, poiché chi intercetta il messaggio potrà potenzialmente utilizzare quella password. Per mitigare questi problemi, esistono strumenti online che semplificano sia la creazione di password complesse sia la loro condivisione in modo sicuro e temporaneo.

Generatore di Password: Caratteristiche e Utilizzo

Il primo strumento è un generatore di password disponibile su GitHub Pages. Questo servizio permette di creare password casuali di diversa complessità. L’utente può personalizzare i parametri in base alle proprie necessità: lunghezza, utilizzo di caratteri speciali, maiuscole, minuscole e numeri.

  • Accesso allo Strumento:
    Il generatore è disponibile qui: https://geegeek.github.io/password/index.html
    Una volta aperta la pagina, è possibile selezionare i parametri desiderati (ad esempio, una lunghezza compresa tra 12 e 16 caratteri, includendo numeri e simboli) e generare una password complessa.

  • Esempio di Generazione:
    Supponiamo di voler creare una password robusta di 16 caratteri, contenente lettere maiuscole, minuscole, numeri e simboli. Lo strumento restituirà una stringa casuale, ad esempio:

    XyZ!9mLpQ3r#1BdT

    Questa password, lunga e complessa, non è facile da indovinare e rappresenta un buon punto di partenza per garantire un livello di sicurezza medio.

Il secondo strumento consente di condividere in modo sicuro la password generata, creando un link monouso attraverso cui il destinatario potrà visualizzare la password una sola volta. Questo meccanismo riduce la probabilità che la password resti esposta a lungo in chiaro su un canale di comunicazione insicuro.

  • Accesso allo Strumento:
    Il servizio one-time si trova qui: https://geegeek.github.io/password/1timepassword/index.html

  • Funzionamento:
    Una volta ottenuta la password dal generatore, è possibile trasferirla allo strumento 1timepassword, che creerà un link univoco. Chi riceve questo link potrà visualizzare la password una sola volta; dopodiché, il link non sarà più valido. In questo modo si riducono notevolmente i rischi legati alla condivisione diretta del testo.

  • Vantaggi della Condivisione Monouso:

    • Evita di scrivere la password in chiaro su un canale di comunicazione.
    • La password non rimane disponibile online a lungo.
    • Una volta visualizzata, il link si “autodistrugge”, minimizzando l’esposizione.

Integrazione tra i due Strumenti

Una delle caratteristiche più interessanti di questi due servizi è la possibilità di integrarli tra loro. Il flusso può essere riassunto così:

  1. L’utente genera una password complessa con il primo strumento.
  2. La password viene automaticamente passata allo strumento one-time password.
  3. Si genera un link monouso, che l’utente può inviare al destinatario.

Questo processo semplifica notevolmente la fase di condivisione. Non si deve copiare e incollare manualmente la password, riducendo errori e garantendo un flusso più lineare.

  • Esempio Pratico Passo Passo:

    1. Aprire https://geegeek.github.io/password/index.html
    2. Generare una password con i parametri desiderati.
    3. Cliccare sull’opzione per passare la password generata allo strumento one-time (se disponibile nell’interfaccia).
    4. Aprire https://geegeek.github.io/password/1timepassword/index.html
    5. Ottenere il link generato.
    6. Condividere il link con il destinatario in modo sicuro.
  • Benefici dell’Integrazione:

    • Facilità d’uso: non serve copiare e incollare.
    • Riduzione degli errori: la password passa direttamente dall’uno all’altro strumento.
    • Maggiore sicurezza: il link monouso limita l’esposizione della password.

Aspetti Tecnici e Codice di Base

Entrambi gli strumenti sono hostati su GitHub Pages, una soluzione semplice per pubblicare siti statici. Le pagine si basano su HTML, CSS e JavaScript. Il codice di integrazione può essere facilmente analizzato e modificato a seconda delle esigenze.

  • Struttura dei File:
    In genere, si hanno file HTML per la struttura della pagina, CSS per il layout e JS per la logica di generazione e passaggio delle password.
    Uno schema generico potrebbe essere:

    index.html
    ├── style.css
    └── script.js

  • Esempio di Integrazione del Codice:
    Nella pagina del generatore di password (index.html) potrebbe esserci un codice JavaScript che, una volta generata la password, effettua un redirect o invoca un endpoint della pagina del one-time password.

    Ad esempio:

    // Generazione della password
    const password = generatePassword({ length: 16, symbols: true, numbers: true });
    // Invio la password allo strumento one-time attraverso un parametro GET
    const oneTimeUrl = “https://geegeek.github.io/password/1timepassword/index.html?pwd=“ + encodeURIComponent(password);
    console.log(“Visita questo link per la password monouso:”, oneTimeUrl);

    Questa è una semplice illustrazione. In pratica, il codice effettivo potrebbe essere più complesso.

  • Configurazioni di Base Consigliate:

    1. Lunghezza della password: almeno 12 caratteri.
    2. Caratteri inclusi: lettere minuscole, maiuscole, numeri e simboli.
    3. HTTPS obbligatorio: assicurarsi che la condivisione del link avvenga sempre tramite protocollo HTTPS.
    4. Aggiornamenti periodici: mantenere il codice aggiornato per includere eventuali fix di sicurezza.

Buone Pratiche di Sicurezza

L’impiego di strumenti come questi non elimina la necessità di attenersi a buone pratiche di sicurezza:

  • Non riutilizzare le password: Non utilizzare la stessa password per più account.
  • Cambiare periodicamente le password: Aggiornare le credenziali ogni tre-sei mesi.
  • Utilizzare password manager riconosciuti: Se necessario, impiegare un password manager affidabile.
  • Verificare la provenienza dei link: Non cliccare su link sospetti. Il link monouso per la password deve provenire da una fonte fidata.

Conclusioni e Sviluppi Futuri

Gli strumenti presentati offrono una soluzione semplice per migliorare la sicurezza nella creazione e condivisione delle password. La combinazione tra un generatore affidabile e un servizio di link monouso riduce al minimo i rischi legati alla divulgazione non autorizzata delle credenziali.

Guardando al futuro, sarebbe possibile integrare ulteriormente queste funzionalità con API di messaggistica sicura o aggiungere restrizioni temporali più raffinate (ad esempio, il link è valido per un numero limitato di minuti).

In conclusione, l’approccio è semplice, non richiede particolari competenze tecniche e può migliorare la vita di chiunque debba gestire e condividere password in modo più sicuro e consapevole.

NOTA BENE:
Pur essendo un metodo pratico e immediato per condividere informazioni sensibili senza l’ausilio di infrastrutture complesse, è importante considerare attentamente le implicazioni di sicurezza e le limitazioni di questo approccio, tenendo presente che – anche se crittografata – la password viene comunque trasmessa nell’URL, con i relativi rischi.

Come identificare e gestire i file che occupano troppo spazio su disco da linea di comando

Quando lo spazio su disco inizia a ridursi, diventa importante individuare quali directory o file consumano grandi quantità di spazio di archiviazione. Disporre dei giusti comandi da riga di comando è essenziale per una manutenzione quotidiana del proprio HomeLab, permettendo di affrontare con calma ed efficienza situazioni potenzialmente critiche.

In questo articolo vedremo alcuni comandi utili per analizzare lo spazio su disco su sistemi Linux. Verranno illustrate anche alcune strategie per liberare spazio, mantenendo un livello di sicurezza medio-alto e operando in modo ragionevole. Nessuna pratica eccessivamente rischiosa verrà proposta, e suggeriremo sempre di operare con la massima cautela.


Panoramica sullo spazio su disco

Prima di tutto, è utile avere una panoramica generale dell’utilizzo delle partizioni:

1
df -h

L’opzione -h (human-readable) converte i valori in unità facilmente leggibili (KB, MB, GB). Da questo output, potrai vedere subito se una partizione è vicina al limite della sua capacità.


Identificare le directory più grandi

Quando individui una partizione critica (ad esempio /opt/NOME_DIRECTORY), puoi analizzare la struttura delle directory al suo interno:

1
du -h /opt/NOME_DIRECTORY --max-depth=1 2>/dev/null | sort -hr | head -n 10
  • du -h: mostra la dimensione delle directory in modo leggibile
  • --max-depth=1: limita la profondità dell’analisi a un solo livello
  • sort -hr: ordina i risultati dal più grande al più piccolo
  • head -n 10: mostra le prime 10 linee
  • L’opzione 2>/dev/null viene utilizzata per ignorare i messaggi di errore relativi a directory non accessibili, semplificando l’analisi dell’output. In alcuni contesti potresti ometterla, se preferisci vedere quali percorsi non possono essere letti.

Se individui una sottodirectory di grandi dimensioni, puoi approfondire ulteriormente nello stesso modo:

1
du -h /opt/NOME_DIRECTORY/GRANDE_CARTELLA_1 --max-depth=1 2>/dev/null | sort -hr | head -n 10

Queste analisi a imbuto ti consentono di scendere gradualmente fino ai singoli file più ingombranti.


Cercare file di grandi dimensioni

Se desideri individuare direttamente i file più pesanti, puoi utilizzare:

1
find / -type f -size +100M 2>/dev/null | head -n 20
  • find /: inizia la ricerca dalla radice
  • -type f: cerca solo file
  • -size +100M: limita la ricerca ai file maggiori di 100MB
  • 2>/dev/null: sopprime i messaggi di errore su directory non accessibili
  • head -n 20: mostra solo i primi 20 risultati

In questo modo otterrai una rapida lista dei maggiori responsabili del consumo di spazio.


Strumenti interattivi: ncdu

Se puoi installare nuovi tool nel tuo HomeLab, ncdu è uno strumento interattivo molto utile:

1
2
apt update
apt install ncdu

Una volta installato, puoi eseguirlo con:

1
ncdu /home/utente

ncdu fornisce un’interfaccia testuale per navigare tra le directory, visualizzarne le dimensioni e, se necessario, eliminare i file direttamente dall’interfaccia. Eccone simile esempio:

1
2
3
4
5
6
7
8
9
10
11
12
13
ncdu 1.19 ~ Use the arrow keys to navigate, press ? for help
--- /home/utente ---------------------------------------------------------------------------
120.0 MiB [########################] /progettoX
60.5 MiB [############ ] /.local
32.2 MiB [##### ] /.cache
15.0 MiB [## ] /documenti
5.0 MiB [ ] /.ssh
2.0 MiB [ ] config_backup.tar.gz
1.0 MiB [ ] notes.txt
40.0 KiB [ ] .bash_history
4.0 KiB [ ] .bashrc
4.0 KiB [ ] .profile


Altri comandi utili

  1. du -sh * nella directory corrente
    Mostra la dimensione di ogni directory e file nel percorso corrente, per una rapida panoramica.

  2. lsof +aL1 /NOME_MONTAGGIO
    A volte lo spazio è occupato da file già cancellati ma ancora aperti da qualche processo. Questo comando mostra i file aperti con link count zero, evidenziando i casi in cui è sufficiente terminare il processo per liberare spazio.

  3. df -i
    Se sospetti che non sia lo spazio ad esaurirsi, ma gli inode, df -i ti mostrerà quanti inode sono utilizzati. Gli inode sono strutture dati utilizzate per gestire informazioni sui file, come metadati, permessi e puntatori al contenuto; un eccesso di file molto piccoli può saturare il numero di inode disponibili.


Caso reale: avviso da un servizio di monitoraggio (Nagios)

Vediamo ora un esempio pratico di come questi comandi possano risultare utili, sia in un’infrastruttura aziendale complessa che in un semplice HomeLab. È una pratica diffusa configurare uno o più servizi di monitoraggio, come Nagios o Zabbix, per tenere sotto controllo lo stato delle macchine. Questi strumenti possono raccogliere dati in modi diversi:

  • Con agent: Il sistema monitorato esegue un software agente (come NRPE per Nagios o l’agente nativo di Zabbix) che invia periodicamente informazioni sullo stato delle risorse (utilizzo CPU, RAM, spazio disco, servizi attivi) al server di monitoraggio.

  • Senza agent (agentless): Il server di monitoraggio interroga direttamente i sistemi target usando protocolli standard come SNMP, WMI (per macchine Windows) o SSH. In questo caso non è necessario installare nulla sul sistema da controllare, riducendo così la complessità dell’infrastruttura.

Nel mio HomeLab, ad esempio, ho ricevuto un avviso da Nagios, che segnalava una situazione critica su un host generico (NOME_HOST). Ecco un esempio del messaggio:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
***** Nagios Monitor XI Alert *****

Notification Type: PROBLEM

Service: Check linux disk usage
Host: NOME_HOST
Address: NOME_INDIRIZZO_IP
State: CRITICAL

Date/Time: NOME_DATA_ORA

Additional Info:

CRITICAL. DISK STATS: / al 90%, /opt/NOME_DIRECTORY al 100%.

Questa notifica mi ha spinto a utilizzare i comandi sopra descritti, individuando con facilità i file e le directory più ingombranti. Ciò mi ha permesso di liberare spazio in modo mirato e sicuro, riducendo l’impatto sull’ambiente e prevenendo potenziali downtime.


In conclusione, utilizzare comandi come df, du, find, o tool interattivi come ncdu, ti permette di individuare rapidamente le aree problematiche del tuo spazio su disco, mantenendo un approccio umile, controllato e sicuro nel tempo. Queste pratiche diventano fondamentali per evitare situazioni di emergenza e mantenere il tuo HomeLab ottimizzato e funzionale.

Esempi Pratici di Expect sulla CLI Linux: Accesso Remoto e Gestione Password

Introduzione

In ambiente Linux/Unix, l’automazione di compiti ripetitivi e l’interazione non presidiata con programmi che richiedono input da tastiera sono attività frequenti. L’utilizzo di Expect offre una soluzione semplice e versatile: questo strumento consente di definire in anticipo le risposte a richieste interattive, evitando la necessità di sviluppare interi script in linguaggi più complessi come Python o PHP.

Garantire un buon livello di sicurezza nell’automazione è fondamentale. Gli esempi forniti di seguito mantengono un approccio prudente: utilizzeremo account non privilegiati o con le autorizzazioni minime necessarie, eviteremo l’uso diretto dell’utente root e ci assicureremo di non memorizzare password in chiaro su file non protetti. L’obiettivo è automatizzare task comuni in modo sicuro e affidabile.

Cosa è Expect?

Expect è un programma che permette di “dialogare” con altri programmi interattivi secondo uno script. In altre parole, con Expect si può:

  • Avviare un programma interattivo (come ssh o passwd)
  • Attendere determinate risposte, prompt o messaggi
  • Inviare input predefiniti in risposta a tali messaggi

Il linguaggio di scripting di Expect si basa su Tcl, un linguaggio interpretato, semplice ma potente, che fornisce strutture di controllo (if, for), definizione di procedure, manipolazione di stringhe e molto altro. Questa combinazione consente di creare script di automazione flessibili, capaci di gestire condizioni variabili e flussi logici complessi.

Quando e Perché Usare Expect?

Expect è utile in qualsiasi scenario in cui si necessiti di fornire risposte previste a input richiesti da un programma. Ad esempio:

  • Accesso remoto a sistemi via SSH senza dover inserire la password manualmente, utile quando si devono eseguire comandi su più server.
  • Gestione automatizzata delle password, ad esempio per aggiornare le credenziali di un account locale su più macchine.
  • Automazione di procedure interne a sistemi legacy o applicazioni non modernizzate.

Rispetto ad altre soluzioni come l’uso di librerie Python o di Ansible, Expect può risultare più semplice e immediato, specialmente per piccole automazioni quotidiane o integrazioni rapide all’interno di script Bash esistenti.

Installazione e Uso di Base

Prima di tutto, verificare che Expect sia installato:

1
2
3
4
5
which expect
```
Se non installato, utilizzare il gestore pacchetti della distribuzione per aggiungerlo. Ad esempio su Debian/Ubuntu:
```bash
sudo apt-get update && sudo apt-get install expect

Per eseguire uno script Expect:

  • Creare il file con estensione .exp
  • Assicurarsi che abbia i permessi di esecuzione
  • Lanciare lo script con:
    1
    expect -f nome_script.exp

È anche possibile rendere lo script eseguibile e utilizzare il shebang:

1
#!/usr/bin/expect -f

In questo modo si potrà lanciare lo script direttamente, come un normale comando.

Per maggiori dettagli sulle opzioni, consultare la pagina man di Expect:

1
man expect

Esempio 1: Connessione SSH e Comando Remoto

Un caso tipico è l’accesso a un server remoto via SSH per eseguire un comando specifico. Immaginiamo di dover connetterci a un server senza inserire manualmente la password e lanciare un singolo comando remoto.

Prerequisiti di sicurezza:

  • Assicurarsi di utilizzare chiavi SSH protette da passphrase se possibile, oppure conservare la password in modo sicuro (ad esempio in un file con permessi limitati).
  • Non utilizzare l’utente root, ma un account non privilegiato.

Script di Esempio

Creare un file ssh_command.exp con il seguente contenuto:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/usr/bin/expect -f

# Verifica dei parametri: username, password, server, porta, comando
if {[llength $argv] != 5} {
puts "Uso: ./ssh_command.exp <username> <password> <server> <porta> <comando>"
exit 1
}

set username [lindex $argv 0]
set password [lindex $argv 1]
set server [lindex $argv 2]
set port [lindex $argv 3]
set command [lindex $argv 4]

set timeout 60

# Avvio della sessione SSH
spawn ssh -p $port $username@$server $command
expect "?assword:"

# Invio della password
send "$password\r"

# Attendo la fine dell’esecuzione del comando
expect eof

Rendere lo script eseguibile:

1
chmod +x ssh_command.exp

Eseguire lo script:

1
./ssh_command.exp utente password server.example.com 22 "ls -l"

Lo script effettuerà la connessione, inserirà la password per voi ed eseguirà il comando ls -l sul server remoto.

Esempio 2: Cambio Password Utente con Expect

Supponiamo di voler aggiornare la password di un account locale. L’uso di Expect consente di automatizzare questo processo senza inserire manualmente la password all’interno del prompt di passwd.

Nota di Sicurezza:

  • Non utilizzare l’utente root. Utilizzare un account con i permessi minimi sufficienti a modificare la password desiderata. In un contesto reale, valutare attentamente le autorizzazioni del proprio ambiente.
  • Evitare di lasciare password in chiaro su file non sicuri. Eventualmente usare variabili d’ambiente protette, o gestori di segreti sicuri.

Script di Esempio

Creare il file passwd_change.exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/expect -f

if {[llength $argv] != 2} {
puts "Uso: ./passwd_change.exp <username> <nuova_password>"
exit 1
}

set username [lindex $argv 0]
set newpass [lindex $argv 1]

set timeout 20

spawn passwd $username
expect "assword:"
send "$newpass\r"
expect "assword:"
send "$newpass\r"
expect eof

Rendere lo script eseguibile:

1
chmod +x passwd_change.exp

Eseguire lo script per cambiare la password:

1
./passwd_change.exp utente locale_nuova_password

Integrazione con Script Bash

Expect può essere facilmente integrato all’interno di script Bash più ampi. Ad esempio, potremmo avere uno script Bash che esegue aggiornamenti periodici su un server e successivamente richiama Expect per eseguire comandi remoti in modo automatizzato.

Esempio di snippet Bash che chiama lo script di connessione SSH:

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash

# Aggiornamenti o altre operazioni di contesto qui...
# Variabili definite all’interno dello script Bash
USERNAME="utente"
PASSWORD="mypass"
SERVER="server.example.com"
PORT=22
COMMAND="uptime"

# Richiama lo script Expect
./ssh_command.exp "$USERNAME" "$PASSWORD" "$SERVER" "$PORT" "$COMMAND"

In questo modo è possibile combinare logica Bash, controllo di flussi, cicli e condizioni con la capacità interattiva di Expect.

Considerazioni Finali

Gli esempi presentati mostrano come Expect possa semplificare l’automazione di operazioni comuni:

  • Connettersi a un server remoto e dare comandi in autonomia.
  • Aggiornare la password di un utente locale senza interazioni manuali.

L’uso di Expect rimane flessibile: può essere applicato a numerosi altri scenari, dalla configurazione di dispositivi di rete all’interazione con applicazioni legacy. L’approccio basato su Tcl rende Expect potente e adattabile. È consigliabile esplorare la documentazione completa per scoprire funzionalità avanzate come la gestione dei timeout, l’uso di pattern più complessi e l’integrazione con altri strumenti.

Riferimenti e Risorse

  • Pagina man di Expect:

    1
    man expect
  • Documentazione Tcl:
    https://www.tcl.tk/

  • Esempi aggiuntivi e progetti open source su GitHub e altri repository di script per l’automazione, dove potete trovare soluzioni reali e suggerimenti pratici.

In definitiva, l’obiettivo è mantenere un equilibrio tra automazione e sicurezza, adottando pratiche prudenziali come l’uso di account non privilegiati, la protezione delle credenziali e la verifica costante degli script prima di metterli in produzione.

Automatizzare la configurazione differenziata dell'accesso SSH con Ansible

Introduzione

Nel precedente articolo abbiamo esplorato come implementare una configurazione SSH modulare su un server Ubuntu/Debian, differenziando i metodi di accesso a seconda della provenienza (interna o esterna), degli utenti e dei metodi di autenticazione. Abbiamo separato la configurazione in file multipli all’interno di sshd_config.d, applicando politiche restrittive per l’accesso esterno e più permissive per la rete interna, oltre a integrare fail2ban, firewall (ufw) e il port forwarding su porte alte per aumentare la sicurezza.

In questo nuovo articolo ci concentreremo sull’automazione dello stesso identico approccio utilizzando Ansible, uno strumento di automazione dell’infrastruttura che ci consentirà di distribuire e mantenere le medesime configurazioni su uno o più server in modo semplice, ripetibile e privo di errori umani. L’uso di Ansible garantisce che le configurazioni siano idempotenti: eseguendo il playbook più volte otterremo sempre lo stato desiderato, senza dover ritoccare manualmente i file o rischiare inconsistenze.

Obiettivi principali:

  • Automatizzare l’installazione e configurazione di OpenSSH Server.
  • Gestire i file di configurazione (/etc/ssh/sshd_config e /etc/ssh/sshd_config.d/*.conf) tramite Ansible.
  • Impostare regole ufw e configurazione base di fail2ban.
  • Creare utenti, impostare chiavi SSH, differenziare l’accesso da interno ed esterno.
  • Integrare il port forwarding su porte alte e mostrare come questa configurazione rimane coerente nel tempo.
  • Mantenere la stessa logica del precedente articolo, ma ora tramite playbook Ansible.

Prerequisiti

  • Un controller Ansible (ad esempio un sistema locale con Ansible installato).
  • Connessione SSH al server o ai server bersaglio, con utente avente privilegi sudo.
  • Chiavi SSH già installate sul controller per l’utente amministrativo che si collegherà al target in modo da non dover usare password negli ansible-playbook.
  • Un server Ubuntu/Debian di destinazione, aggiornato e con un utente sudo.
  • Configurazione base di rete, con la possibilità di configurare il router per il port forwarding (come descritto nel precedente articolo).
  • Conoscenza base di Ansible e della struttura di un playbook.

Struttura del Progetto Ansible

Possiamo organizzare il nostro progetto con la seguente struttura:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ansible/
├─ inventory.ini
├─ playbook.yaml
└─ roles/
└─ ssh_config/
├─ tasks/
│ ├─ main.yaml
│ ├─ firewall.yaml
│ ├─ fail2ban.yaml
│ ├─ sshd.yaml
│ └─ users.yaml
├─ templates/
│ ├─ sshd_config.j2
│ ├─ 00-internal.conf.j2
│ └─ 01-external.conf.j2
└─ files/
└─ authorized_keys_deploy
  • inventory.ini: Contiene l’inventario dei nostri host da configurare.
  • playbook.yaml: Il file principale che esegue il ruolo ssh_config.
  • roles/ssh_config/tasks/: Directory con i task divisi per argomento (firewall, fail2ban, sshd, utenti).
  • roles/ssh_config/templates/: I template Jinja2 per generare i file di configurazione.
  • roles/ssh_config/files/: Eventuali file statici come chiavi autorizzate.

È possibile variare la struttura secondo le preferenze, ma questa offre una buona separazione delle responsabilità.

L’inventario di Ansible

Nel file inventory.ini definiremo i server target:

1
2
[ssh_servers]
myserver ansible_host=aa.bb.cc.dd ansible_user=mio_utente

Sostituite aa.bb.cc.dd con l’IP pubblico del server o un dominio che lo punti. L’ansible_user è l’utente sudo locale creato in precedenza.

Variabili e Considerazioni

Nelle variabili potremmo definire:

  • La rete interna da cui consentire l’accesso con password (es. 192.168.0.0/24).
  • L’IP esterno o range ammesso all’accesso via chiave.
  • L’utente dedicato all’accesso esterno (es. deploy).

Queste variabili possono essere definite nel playbook.yaml o in group_vars/ssh_servers.yaml per maggiore scalabilità.

Esempio di variabili (in playbook.yaml o in un file vars.yaml):

1
2
3
4
5
6
vars:
internal_network: "192.168.0.0/24"
external_ip: "aa.bb.cc.dd"
external_user: "deploy"
ssh_port: 22
external_port: 22222 # porta esterna sul router

Il Playbook Principale: playbook.yaml

Questo playbook eseguirà il ruolo ssh_config sui server del gruppo ssh_servers:

1
2
3
4
5
6
7
8
9
10
11
- name: Configure SSH access via Ansible
hosts: ssh_servers
become: true
vars:
internal_network: "192.168.0.0/24"
external_ip: "aa.bb.cc.dd"
external_user: "deploy"
ssh_port: 22
external_port: 22222
roles:
- ssh_config

Il Ruolo ssh_config

Il ruolo si occupa di:

  1. Installare e configurare OpenSSH Server:

    • Assicurarsi che openssh-server sia installato.
    • Copiare i template di configurazione in /etc/ssh/.
    • Riavviare il demone sshd.
  2. Configurare il firewall (ufw):

    • Consentire la porta 22 (interna) se serve.
    • Limitare l’accesso esterno eventualmente per IP specifici.
    • Gestire le regole per consentire l’accesso dalla LAN e limitare l’esterno.
  3. Configurare fail2ban:

    • Installare fail2ban se non presente.
    • Copiare una configurazione base.
    • Riavviare fail2ban.
  4. Creare utenti, chiavi SSH, assegnare i privilegi:

    • Creare l’utente deploy se non esiste.
    • Aggiungere la chiave pubblica a ~deploy/.ssh/authorized_keys.
    • Configurare l’utente amministrativo.
  5. Template per sshd_config e sshd_config.d/*.conf:

    • sshd_config.j2 contenente configurazioni generali.
    • 00-internal.conf.j2 e 01-external.conf.j2 per differenziare gli accessi.

Esempio di tasks/main.yaml

Questo file includerà gli altri file di task:

1
2
3
4
5
6
7
8
9
10
11
- name: Include firewall tasks
include_tasks: firewall.yaml

- name: Include fail2ban tasks
include_tasks: fail2ban.yaml

- name: Include sshd tasks
include_tasks: sshd.yaml

- name: Include users tasks
include_tasks: users.yaml

Esempio di tasks/firewall.yaml

Questa sezione:

  • Installa ufw se non presente.
  • Resetta le regole, permette SSH interno, limita l’esterno all’IP definito.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
- name: Ensure ufw is installed
apt:
name: ufw
state: present
update_cache: yes

- name: Reset ufw rules
command: ufw --force reset

- name: Allow internal SSH access
ufw:
rule: allow
port: "{{ ssh_port }}"
proto: tcp
source: "{{ internal_network }}"

- name: Allow external SSH from specified IP only
ufw:
rule: allow
port: "{{ ssh_port }}"
proto: tcp
source: "{{ external_ip }}"

- name: Enable ufw
ufw:
state: enabled

Qui apriamo la 22 solo per la rete interna e per l’IP specificato per l’esterno. Questo riflette la logica precedente: da esterno accede solo un IP e uno specifico utente.

Esempio di tasks/fail2ban.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
- name: Ensure fail2ban is installed
apt:
name: fail2ban
state: present
update_cache: yes

- name: Configure fail2ban
copy:
dest: /etc/fail2ban/jail.local
content: |
[sshd]
enabled = true
port = {{ ssh_port }}
filter = sshd
logpath = /var/log/auth.log
maxretry = 5
findtime = 600
bantime = 3600
ignoreip = 127.0.0.1/8 {{ internal_network }}

- name: Restart fail2ban
service:
name: fail2ban
state: restarted

Abbiamo ignorato il range interno in modo che la LAN non venga bannata da tentativi multipli.

Esempio di tasks/users.yaml

Creiamo l’utente deploy e aggiungiamo la sua chiave pubblica. Presumiamo di avere una chiave pubblica pronta nel ruolo (in files/authorized_keys_deploy):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
- name: Ensure deploy user exists
user:
name: "{{ external_user }}"
shell: /bin/bash
create_home: yes

- name: Ensure .ssh directory exists
file:
path: "/home/{{ external_user }}/.ssh"
state: directory
owner: "{{ external_user }}"
group: "{{ external_user }}"
mode: '0700'

- name: Deploy the authorized_keys file
copy:
src: authorized_keys_deploy
dest: "/home/{{ external_user }}/.ssh/authorized_keys"
owner: "{{ external_user }}"
group: "{{ external_user }}"
mode: '0600'

Esempio di tasks/sshd.yaml

Qui gestiamo i file di configurazione sshd_config e sshd_config.d tramite template:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
- name: Ensure openssh-server is installed
apt:
name: openssh-server
state: present
update_cache: yes

- name: Backup original sshd_config if present
copy:
src: /etc/ssh/sshd_config
dest: /etc/ssh/sshd_config.bak
remote_src: yes
force: no
when: ansible_stat.exists

vars:
ansible_stat: "{{ lookup('ansible.builtin.stat', '/etc/ssh/sshd_config') }}"

- name: Deploy main sshd_config
template:
src: sshd_config.j2
dest: /etc/ssh/sshd_config
owner: root
group: root
mode: '0644'

- name: Ensure sshd_config.d directory exists
file:
path: /etc/ssh/sshd_config.d
state: directory
mode: '0755'

- name: Deploy 00-internal.conf
template:
src: 00-internal.conf.j2
dest: /etc/ssh/sshd_config.d/00-internal.conf
owner: root
group: root
mode: '0644'

- name: Deploy 01-external.conf
template:
src: 01-external.conf.j2
dest: /etc/ssh/sshd_config.d/01-external.conf
owner: root
group: root
mode: '0644'

- name: Restart ssh service
service:
name: ssh
state: restarted

Template sshd_config.j2

Questo ricalca le configurazioni base:

1
2
3
4
5
6
UsePAM yes
PermitRootLogin no
ChallengeResponseAuthentication no
PasswordAuthentication yes
PubkeyAuthentication yes
Include /etc/ssh/sshd_config.d/*.conf

Template 00-internal.conf.j2

Consente da rete interna l’uso della password e delle chiavi a qualsiasi utente:

1
2
3
Match address {{ internal_network }}
PasswordAuthentication yes
PubkeyAuthentication yes

Template 01-external.conf.j2

Limitato all’utente deploy e all’indirizzo IP esterno, solo chiave:

1
2
3
Match User {{ external_user }}, Address {{ external_ip }}
PasswordAuthentication no
PubkeyAuthentication yes

Port Forwarding su Porta Alta (22222)

Dal lato del router, come nel precedente articolo, si configura il port forwarding della porta 22222 esterna verso la 22 interna del server. Ansible non può effettuare questa operazione sul router a meno di avere plugin specifici o un router programmabile (ad esempio via API). Presumiamo che questa modifica sia stata già fatta a mano sul router:

  • Dall’esterno: ssh -p 22222 deploy@mio_dominio
    Il router inoltra la 22222 → 22 del server interno.

Nella configurazione di Ansible non cambia nulla per sshd, rimane in ascolto sulla 22 interna. Il firewall filtra gli accessi, l’utente deploy può accedere solo dall’external_ip consentito con chiave, mentre la rete interna può accedere con password.

Se si volesse essere più coerenti, potremmo cambiare la Port in sshd_config.j2. Tuttavia, il port forwarding è una soluzione migliore, perché non richiede modifiche al demone SSH e non influisce sugli accessi LAN.

Eseguire il Playbook

Dopo aver preparato tutto:

1
ansible-playbook -i inventory.ini playbook.yaml

Se il vostro accesso SSH al server è pronto, Ansible applicherà in pochi secondi tutte le configurazioni descritte. Eseguite nuovamente il playbook in futuro per mantenere lo stato o dopo modifiche alle variabili: le configurazioni saranno sempre coerenti.

Possibili Estensioni e Conclusione

In questo articolo abbiamo replicato l’approccio modulare e differenziato dell’accesso SSH mediante la creazione e applicazione automatizzata di playbook Ansible. Questo consente di scalare la stessa configurazione su più server e di mantenere un controllo centralizzato, coerente e privo di rischi di errore umano.

Per ulteriori estensioni future, si potrebbero creare ruoli separati per la gestione delle chiavi SSH, per l’applicazione di policy di sicurezza più complesse, per l’integrazione con sistemi di gestione delle identità o per la distribuzione automatica di fail2ban con configurazioni personalizzate.
Inoltre, si potrebbe integrare Ansible con strumenti CI/CD per testare automaticamente le configurazioni prima del deployment in produzione.

Con l’introduzione di Ansible, abbiamo compiuto un passo significativo verso l’automazione dell’infrastruttura e la riduzione del carico di lavoro amministrativo, garantendo un accesso SSH sicuro, modulare e facile da mantenere.

Implementare un server SSH su Ubuntu/Debian, configurazioni differenziate e accesso esterno con port forwarding

Introduzione

In questo articolo approfondiremo la configurazione di un server SSH su Ubuntu/Debian con un livello di sicurezza un po’ piu’ elevato. Non ci limiteremo alla semplice attivazione del servizio, ma esploreremo una strategia di configurazione modulare utilizzando la directory sshd_config.d. Questo approccio consente di creare differenti casistiche di accesso in base alla rete di provenienza, al metodo di autenticazione e all’utente che tenta di collegarsi. Inoltre, vedremo come:

  • Limitare gli accessi esterni a determinati utenti e chiavi pubbliche, filtrando per indirizzi IP di origine.
  • Permettere, da rete interna, l’accesso anche con password per tutti gli utenti.
  • Integrare firewall e fail2ban per mitigare i tentativi di accesso non autorizzati.
  • Esporre la porta SSH su una porta alta tramite port forwarding, aumentandone la sicurezza.
  • Preparare il terreno per automatizzare questi processi in futuro.

Assumeremo i seguenti prerequisiti:

  • Il server è basato su Ubuntu/Debian con sudo abilitato per l’utente di amministrazione.
  • OpenSSH Server è installato.
  • Un firewall (ad esempio ufw) è attivo e configurato.
  • Fail2ban è installato per prevenire i tentativi di brute-force.
  • Il server dispone di un IP interno (LAN) e di un IP pubblico (o di un router con port forwarding configurabile).
  • L’utente di amministrazione appartiene al gruppo sudo.

Perche’� adottare una configurazione modulare con sshd_config.d

Il file principale /etc/ssh/sshd_config definisce il comportamento globale del server SSH. Tuttavia, utilizzando la directory /etc/ssh/sshd_config.d, possiamo inserire file aggiuntivi che sovrascrivono o integrano la configurazione di base. Questo approccio modulare permette di mantenere il file principale pulito e di organizzare le diverse casistiche di accesso in file separati. È particolarmente utile quando si gestiscono scenari complessi e si ha necessità di apportare modifiche incrementali senza rischiare di compromettere l’intera configurazione.

Configurazione di base di OpenSSH

Installazione

Se non lo avete già fatto, procedete all’installazione:

1
2
sudo apt update
sudo apt install openssh-server

Il servizio sshd sarà avviato e abilitato automaticamente.

Configurazione del firewall (UFW)

Assicuratevi che il firewall ufw sia installato e attivato:

1
2
sudo apt install ufw
sudo ufw enable

Per consentire la connessione sulla porta SSH standard (22), eseguite:

1
sudo ufw allow 22/tcp

Successivamente, quando imposteremo un port forwarding su una porta differente, modificheremo le regole di conseguenza.

Configurazione di fail2ban

Fail2ban blocca gli indirizzi IP che tentano di eseguire accessi non autorizzati (brute-force). Se non presente:

1
sudo apt install fail2ban

Nella configurazione predefinita, fail2ban monitorerà il file di log di SSH e bloccherà automaticamente gli IP che generano troppi tentativi falliti. È possibile personalizzare /etc/fail2ban/jail.local per definire tempi di ban, numero di tentativi e altro. Un esempio basilare (da aggiungere o modificare in /etc/fail2ban/jail.local):

1
2
3
4
5
6
7
8
[sshd]
enabled = true
port = 22
filter = sshd
logpath = /var/log/auth.log
maxretry = 5
findtime = 600
bantime = 3600

Dopo aver modificato i parametri:

1
sudo systemctl restart fail2ban

Con questa configurazione di base, fallimenti ripetuti di autenticazione verranno puniti con il blocco temporaneo dell’IP.

Gestione utenti e privilegi sudo

L’utente amministrativo dovrebbe appartenere al gruppo sudo. Se state utilizzando un utente diverso, potete aggiungerlo al gruppo:

1
2
sudo adduser mio_utente
sudo usermod -aG sudo mio_utente

In questo modo mio_utente potrà eseguire comandi sudo e gestire la configurazione del sistema.

Creazione di scenari differenziati

L’obiettivo è creare due casi d’uso:

  1. Accessi dall’esterno:

    • Limitati a specifici utenti (ad esempio deploy)
    • Limitati a specifici IP di origine
    • Autenticazione solo con chiave, niente password.
  2. Accessi dalla rete interna:

    • Consentiti per tutti gli utenti di sistema (ad esempio mio_utente o altri)
    • Autenticazione con password abilitata e chiavi ammessa
    • Nessuna restrizione di IP (ma ci si basa sul fatto che l’indirizzo IP provenga dalla rete interna, ad esempio 192.168.0.0/24).

Configurazione di base di /etc/ssh/sshd_config

Nel file principale /etc/ssh/sshd_config lasceremo impostazioni generali di sicurezza:

1
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak

Modifichiamo /etc/ssh/sshd_config per disabilitare l’accesso root e alcune opzioni generali:

1
2
3
4
5
6
7
UsePAM yes
PermitRootLogin no
ChallengeResponseAuthentication no
PasswordAuthentication yes # Abilitiamo qui la password come default, poi la limitiamo nei match esterni
PubkeyAuthentication yes
# Includiamo la directory di configurazione aggiuntiva
Include /etc/ssh/sshd_config.d/*.conf

Salviamo e chiudiamo. Con Include /etc/ssh/sshd_config.d/*.conf abbiamo dato istruzioni a sshd di leggere file aggiuntivi nella directory sshd_config.d.

Creazione dei file di configurazione modulari

Creeremo due file all’interno di /etc/ssh/sshd_config.d:

  • 00-internal.conf per la rete interna
  • 01-external.conf per l’accesso esterno

Configurazione interna: /etc/ssh/sshd_config.d/00-internal.conf

Questa configurazione consente a chiunque si trovi all’interno della rete interna (es. 192.168.0.0/24) di autenticarsi con password:

1
sudo nano /etc/ssh/sshd_config.d/00-internal.conf

Inseriamo:

1
2
3
4
Match address 192.168.0.0/24
PasswordAuthentication yes
PubkeyAuthentication yes
# In questo scenario lasciamo qualsiasi utente della LAN entrare con password o chiave.

Salviamo e chiudiamo.

Configurazione esterna: /etc/ssh/sshd_config.d/01-external.conf

Per l’accesso esterno, supponiamo di avere un IP pubblico o di filtrare l’accesso tramite firewall. Ad esempio, immaginiamo che solo da un certo IP pubblico o da un range (ad esempio aa.bb.cc.dd) possa accedere l’utente deploy. Inoltre, vogliamo obbligare l’autenticazione solo tramite chiave.

1
sudo nano /etc/ssh/sshd_config.d/01-external.conf

Inseriamo:

1
2
3
Match User deploy, Address aa.bb.cc.dd
PasswordAuthentication no
PubkeyAuthentication yes

In questo modo, se la connessione proviene dall’indirizzo aa.bb.cc.dd e l’utente che tenta di accedere è deploy, la password non sarà accettata, ma solo la chiave pubblica. Nessun altro IP o utente potrà usufruire di queste impostazioni.

Riavviare il servizio SSH per applicare le modifiche

Dopo aver creato i file di configurazione, riavviamo SSH:

1
sudo systemctl restart ssh

Chiavi SSH

L’utente deploy che accede da remoto dovrà avere una coppia di chiavi. Sul client remoto, generiamo una chiave:

1
ssh-keygen -t ed25519 -C "deploy@example.com"

Copiare la chiave pubblica sul server (da remoto):

1
ssh-copy-id deploy@ip_o_dominio_del_server

Il comando ssh-copy-id aggiungerà la chiave a ~/.ssh/authorized_keys dell’utente deploy.

Configurazione del firewall per differenti casistiche

Poiché da esterno si deve accedere solo con chiave e da determinati IP, si puo’ò rafforzare il tutto tramite ufw, consentendo solo l’IP esterno specifico:

1
sudo ufw allow from aa.bb.cc.dd to any port 22

Se desiderate bloccare tutti gli altri tentativi di accesso esterni, assicuratevi di non eseguire un ufw allow 22/tcp generico, ma solo quello limitato all’IP sopra indicato. In caso foste costretti ad aprire a tutti l’accesso per qualche motivo, ricordate che fail2ban entra in azione per mitigare i tentativi di brute force.

Fail2ban e le due casistiche di accesso

Fail2ban non fa distinzioni tra accessi interni o esterni di default, ma grazie alla sua configurazione blocca gli IP che tentano numerosi accessi non autorizzati. Questo è utile specialmente per gli attacchi provenienti da Internet. Se notate che IP interni vengono bloccati, potete modificare la configurazione ignoreip in /etc/fail2ban/jail.local:

1
2
3
4
5
6
7
8
9
[sshd]
enabled = true
port = 22
filter = sshd
logpath = /var/log/auth.log
maxretry = 5
findtime = 600
bantime = 3600
ignoreip = 127.0.0.1/8 192.168.0.0/24

In questo modo gli IP interni non saranno bloccati, permettendo maggiore flessibilità nella LAN.

Dopo le modifiche:

1
sudo systemctl restart fail2ban

Spostare la porta SSH esterna su una porta alta con port forwarding

È una buona pratica non esporre la porta 22 direttamente su Internet. Si può configurare il router per effettuare un port forwarding da una porta alta (ad esempio 22222) verso la porta 22 del server.

Passi generali

  1. Sul router/NAT:
    Accedete all’interfaccia di gestione del vostro router e individuate la sezione “Port Forwarding” o “Virtual Server”.
    Create una regola che inoltri la porta esterna 22222 (TCP) all’indirizzo IP interno del vostro server sulla porta 22.

  2. Configurazione del firewall interno per la nuova porta:

    Poiché la porta 22 rimane aperta internamente, nella rete LAN tutto rimane come prima. Dall’esterno, però, l’utente si collegherà a ssh -p 22222 deploy@mio_dominio (se avete un nome di dominio puntato sul vostro IP pubblico).

    Se volete che il firewall accetti esplicitamente connessioni solo su 22 in LAN e non dall’esterno, potete chiudere la 22 dall’esterno e lasciare aperta solo tramite la regola del router:

    1
    sudo ufw deny 22/tcp

    Ma questo bloccherebbe completamente SSH via 22 (anche internamente), quindi meglio gestire il firewall sul router o, se il server deve essere raggiungibile da LAN su 22, lasciare ufw allow 22/tcp ma consentire accesso esterno solo tramite l’IP specifico. Dipende dalla vostra topologia di rete.
    Se volete segmentare, potete usare regole UFW avanzate per differenziare l’accesso esterno/interno (ad esempio definendo allow from 192.168.0.0/24 to any port 22 per la LAN, e negare tutto il resto).

Collegamento esterno sulla porta alta

Da un host remoto:

1
ssh -p 22222 deploy@mio_dominio

La connessione arriverà al vostro router, che la inoltrerà alla porta 22 del server, passando le regole di sshd. Ricordate che l’utente deploy ha l’accesso da quell’IP autorizzato e soltanto con chiave.

Considerazioni finali e spunti per l’automazione

Abbiamo creato una configurazione modulare che differenzia gli accessi SSH sulla base della rete di provenienza, del metodo di autenticazione e dell’utente, utilizzando i file in sshd_config.d. Abbiamo integrato firewall, fail2ban e illustrato come effettuare un port forwarding per aumentare la sicurezza.

Questo approccio è solido, ma la sua gestione manuale puo’ò diventare complessa in ambienti di grandi dimensioni o con frequenti variazioni. Nel prossimo articolo potremmo esplorare meccanismi di automazione, utilizzando tool come Ansible, Puppet o Chef, per distribuire e mantenere queste configurazioni in maniera scalabile e ripetibile. L’automazione permetterebbe di applicare, testare e aggiornare queste configurazioni su un parco macchine esteso, riducendo il rischio di errori umani e semplificando il lavoro dell’amministratore di sistema.

Con questi spunti, si chiude questo lungo articolo, augurandoci che le informazioni fornite siano utili per implementare un accesso SSH sicuro, flessibile e ben organizzato.

Possibili Miglioramenti

Un ulteriore passo avanti verso una configurazione più robusta e scalabile potrebbe essere l’utilizzo di un reverse proxy posizionato davanti alla porta SSH esposta su Internet. In particolare, adottare un servizio come Cloudflare (gratuito nella fascia free per il traffico su porte HTTP/HTTPS, ma non per la porta SSH) consentirebbe di usufruire della loro rete globale di distribuzione, di strumenti di mitigazione avanzati contro attacchi DDoS, e di ulteriori livelli di filtraggio del traffico.

Tuttavia, questa configurazione introduce complessità aggiuntive: occorrerebbe consentire l’accesso solo agli indirizzi IP di Cloudflare, con una conseguente modifica delle regole firewall, una gestione più granulare delle liste di trusted IP e una combinazione di impostazioni su Cloudflare stesso.

Questa soluzione, pur più articolata, incrementa significativamente la resilienza del sistema e riduce l’esposizione diretta della vostra infrastruttura, rendendola meno vulnerabile alle minacce provenienti da Internet. Consideratela un’evoluzione del setup descritto in quest’articolo, una strada da intraprendere quando le esigenze di sicurezza e affidabilità diventano più stringenti.

Gestire la configurazione di rete con il comando ip su Linux

Introduzione

Il comando ip su Linux è uno strumento estremamente versatile e potente per la gestione e la configurazione dei parametri di rete del sistema. Sostituisce gradualmente alcuni comandi più datati (come ifconfig, route, netstat) offrendo funzionalità più moderne e una sintassi coerente. Grazie a ip è possibile visualizzare, modificare e mantenere in efficienza la rete locale, le interfacce, i gateway e le rotte in modo sicuro, scalabile e senza ricorrere ad azioni rischiose.

In questo articolo esamineremo, in un ordine più coerente rispetto alla lista originale, come utilizzare il comando ip per coprire una serie di attività comuni in ambito di amministrazione di rete. Saranno illustrate le funzioni principali, la configurazione di base consigliata, alcune opzioni utili e le best practice per mantenere un livello di sicurezza medio-alto, senza ricorrere ad un accesso root diretto.

Perché usare il comando ip?

Il comando ip fa parte del pacchetto iproute2 e offre una sintassi modulare in cui le operazioni si esprimono come combinazioni di ip [oggetto] [comando] [parametri]. Gli oggetti principali sono link (le interfacce), addr (gli indirizzi IP), route (le rotte), neigh (gli ARP/neighbour), e così via.

Rispetto ad altri comandi datati, ip fornisce un output più chiaro, supporta funzionalità moderne (come tunnel e policy routing) e permette di integrare opzioni avanzate (es. gestione di MTU, queueing discipline, bridging, bonding).

Ordine logico delle operazioni con il comando ip

Di seguito una lista ordinata di 15 azioni comuni che si possono effettuare con il comando ip, riorganizzate in un ordine più coerente per un amministratore di sistema:

  1. Individuare le interfacce di rete disponibili sul sistema
    Prima di qualsiasi operazione è fondamentale sapere quali interfacce siano presenti: Ethernet, Wi-Fi, loopback, virtuali ecc.

  2. Consultare lo stato di una singola interfaccia IP
    Una volta individuata un’interfaccia, è utile controllarne stato, parametri e statistiche.

  3. Configurare l’interfaccia di loopback, Ethernet e altre interfacce IP
    Il loopback e le interfacce fisiche o virtuali possono essere configurate con indirizzi IP, MTU, etichette, ecc.

  4. Mettere un’interfaccia in stato attivo (up) o inattivo (down)
    Attivare o disattivare un’interfaccia senza rimuoverne la configurazione.

  5. Modificare parametri aggiuntivi di un’interfaccia, ad esempio MTU o nome
    Non solo up/down, ma anche impostare l’MTU e, se supportato, rinominare l’interfaccia in modo coerente.

  6. Assegnare, eliminare e configurare indirizzi IP, subnet e altre informazioni IP
    Aggiungere un indirizzo IP, rimuoverlo, configurare maschere di rete e gateway può essere fatto con pochi comandi.

  7. Visualizzare e modificare l’elenco degli indirizzi IP e le loro proprietà
    Effettuare un inventario degli indirizzi configurati, controllare indirizzi multipli su una singola interfaccia, ecc.

  8. Configurare e modificare rotte predefinite e statiche
    Impostare una route di default o aggiungere rotte statiche verso sottoreti specifiche.

  9. Impostare o eliminare singole voci di routing
    Se necessario, aggiungere o rimuovere rotte individuali per un fine più granulare.

  10. Verificare il percorso (traccia) che un indirizzo IP seguirà
    Controllare come i pacchetti raggiungono una destinazione, utile per diagnosticare problemi di rete.

  11. Configurare tunnel su IP
    Creare e gestire tunnel IP (ad esempio GRE o IPIP) per connettere due reti remote attraverso un canale sicuro.

  12. Gestire e visualizzare lo stato globale della rete
    Panoramica dello stato di tutte le interfacce e delle relative statistiche.

  13. Raccogliere informazioni sugli indirizzi IP multicast
    Verificare quali gruppi multicast sono configurati sull’host.

  14. Mostrare la cache ARP o NDISC
    Visualizzare i mapping tra indirizzi IP e MAC (ARP su IPv4) o NDISC (su IPv6).

  15. Gestire gli oggetti neighbour: invalidare ARP cache, aggiungere entry ARP, ecc.
    Aggiungere manualmente voci ARP, rimuoverle o invalidarle per forzare la risoluzione dell’indirizzo in caso di problemi.

Comandi utili ed esempi di configurazione

Di seguito riportiamo alcuni esempi pratici, usando il comando ip.
Nota: Evita di operare come root; utilizza invece sudo quando necessario. Prima di modificare configurazioni critiche di rete, sperimenta su macchine di test o sistemi non di produzione.

1. Individuare le interfacce disponibili

ip link show

### 2. Consultare lo stato di una singola interfaccia

```bash
ip link show dev eth0

Questo comando mostra lo stato di `eth0`, le sue proprietà e se è up o down.

### 3. Configurare l’interfaccia di loopback

L’interfaccia loopback `lo` è solitamente già configurata di default, ma per verificarne lo stato:

```bash
ip link set lo up
ip addr show dev lo

### 4. Attivare o disattivare un’interfaccia

```bash
sudo ip link set eth0 up
sudo ip link set eth0 down

### 5. Modificare parametri avanzati dell’interfaccia

Ad esempio, per modificare l’MTU:

```bash
sudo ip link set eth0 mtu 1400

### 6. Assegnare un indirizzo IP

```bash
sudo ip addr add 192.168.1.10/24 dev eth0

Per rimuoverlo:

```bash
sudo ip addr del 192.168.1.10/24 dev eth0

### 7. Visualizzare gli indirizzi IP configurati

```bash
ip addr show

### 8. Configurare una route di default

```bash
sudo ip route add default via 192.168.1.1 dev eth0

### 9. Eliminare una route

```bash
sudo ip route del 192.168.2.0/24 dev eth0

### 10. Verificare il percorso verso un host remoto

Questo non è un comando `ip` diretto, ma `ip route get` può fornire una traccia del percorso:

```bash
ip route get 8.8.8.8

### 11. Configurare un tunnel IP (esempio GRE)

```bash
sudo ip tunnel add gre1 mode gre remote 203.0.113.5 local 198.51.100.10 dev eth0
sudo ip link set gre1 up
sudo ip addr add 10.0.0.1/24 dev gre1

### 12. Stato globale della rete

```bash
ip -s link

Mostra statistiche di rete su tutte le interfacce.

### 13. Informazioni sugli indirizzi multicast

```bash
ip maddr show

### 14. Mostrare la cache ARP

```bash
ip neigh show

### 15. Gestire la ARP cache

Aggiungere una voce statica ARP:

```bash
sudo ip neigh add 192.168.1.50 lladdr 00:11:22:33:44:55 dev eth0 nud permanent

Rimuoverla:

```bash
sudo ip neigh del 192.168.1.50 dev eth0

## Configurazione di base consigliata

Una configurazione di rete di base consigliata potrebbe prevedere:

- Un’interfaccia Ethernet principale con IP statico e una route di default verso il gateway della LAN.
- Un indirizzo IP assegnato con il comando `ip addr add ...`.
- Una route di default impostata con `ip route add default via ...`.
- Niente accessi diretti come root: utilizzare sempre `sudo`.
- Mantenere l’MTU standard (1500) a meno di necessità specifiche.
- Verificare che la cache ARP non contenga entry obsolete e mantenere aggiornato l’elenco delle rotte.

Per rendere persistenti queste configurazioni, l’amministratore può utilizzare file di configurazione specifici della distribuzione (ad esempio `/etc/network/interfaces` su Debian/Ubuntu, o i file in `/etc/sysconfig/network-scripts/` su Red Hat/CentOS), riportando le stesse informazioni che abbiamo testato con `ip`.

## Conclusioni

Il comando **ip** mette a disposizione un set completo di strumenti per configurare, diagnosticare e mantenere in efficienza la rete di un host Linux. Prendere confidenza con le sue opzioni più importanti è un passo fondamentale per qualsiasi amministratore di sistema moderno. Aumentare la sicurezza e la stabilità della rete non richiede l’uso di pratiche rischiose, ma una buona comprensione degli strumenti a disposizione.

Con l’approccio presentato in questo articolo, è possibile migliorare la propria padronanza di `ip`, organizzare il lavoro in modo sistematico e mantenere un livello di sicurezza medio-alto anche nella gestione quotidiana del networking Linux.