Vai al contenuto principale

#howto

Podman: l’alternativa a Docker che ogni sysadmin Linux dovrebbe conoscere

Per anni Docker è stato il default indiscusso quando si parlava di container su Linux. Ma l’architettura basata su un daemon centrale che gira come ro

Altro...

Per anni Docker è stato il default indiscusso quando si parlava di container su Linux. Ma l’architettura basata su un daemon centrale che gira come root ha sempre lasciato sul tavolo un problema di superficie d’attacco: se qualcuno compromette dockerd, ha di fatto accesso root all’intero host. Podman nasce proprio per chiudere questo gap, offrendo un motore container daemonless, compatibile con le immagini OCI e con la CLI Docker, che si integra in modo molto più nativo con systemd e con il modello di permessi di Linux.

Vediamo come installarlo, come si differenzia realmente da Docker oltre gli slogan, e come portarlo in produzione con systemd e le Quadlet, che sono probabilmente la ragione migliore per prenderlo sul serio.

Cos’è Podman, in praticaPodman (da Pod Manager) è un motore container open source senza demone centrale. Ogni container gira come processo figlio dell’utente che lo ha avviato, non come figlio di un servizio di sistema con privilegi elevati. Questo significa che è possibile eseguire container completamente rootless, senza mai invocare sudo, riducendo drasticamente cosa un container compromesso può effettivamente toccare sull’host.

Sotto il cofano Podman usa gli stessi runtime OCI di Docker e parla lo stesso formato immagine, quindi la stragrande maggioranza dei comandi Docker funziona invariata sostituendo semplicemente il nome del binario (o creando un alias docker=podman, oppure installando il pacchetto podman-docker che fa da shim trasparente).

Un concetto che Docker non ha nativamente è quello di pod: gruppi di uno o più container che condividono rete e storage, concettualmente vicini ai pod di Kubernetes. Comodo quando si vogliono far girare insieme più container che devono comunicare come se fossero sulla stessa macchina.

Installazione# Debian/Ubuntu (Debian 11+, Ubuntu 20.10+)
sudo apt-get update
sudo apt-get -y install podman

Fedora/CentOS/RHEL 8+

sudo dnf -y install podman

openSUSE

sudo zypper install podman

Arch/Manjaro

sudo pacman -S podmanVerifica dell’installazione:

podman --version
podman info
podman run hello-worldSe l’ultimo comando restituisce il messaggio di benvenuto di Podman, l’installazione è a posto.

Uso quotidiano: i comandi non cambiano quasi nullaShell interattiva dentro un container Ubuntu:

podman run -it ubuntu bashServizio in background, con Nginx esposto sulla porta 8080 dell’host:

podman run -d --name web -p 8080:80 nginx
podman psIl resto della CLI ricalca Docker praticamente 1:1: podman pull, podman images, podman stop/start, podman rm/rmi. Dietro le quinte, podman build è in realtà un wrapper attorno a Buildah, mentre lo spostamento di immagini tra registry passa per Skopeo: strumenti separati che Podman orchestra per te, senza che serva conoscerli nel dettaglio per l’uso base.

Dove Docker e Podman divergono davveroLa compatibilità è alta ma non totale, e i problemi emergono quasi sempre dal modello rootless. Il caso più comune sono i bind mount: poiché i container rootless usano user namespace e mapping subuid/subgid, una directory montata dall’host non sempre ha la proprietà che il container si aspetta. Su sistemi con SELinux attivo serve anche il suffisso :z o :Z per far ri-etichettare correttamente i file:

podman run -v /host/path:/container/path:Z myimage:z minuscolo condivide il volume tra più container, :Z maiuscolo lo rende privato per un singolo container. Se serve far coincidere esattamente la proprietà con quella dell’host, l’opzione --uidmap permette un controllo fine, oppure si può far girare il container in modalità rootful per replicare il comportamento di Docker.

Altri attriti da conoscere prima di migrare: l’accesso GPU da container rootless è limitato (NVIDIA richiede nvidia-container-toolkit e setup CDI, con i container da ricreare a ogni aggiornamento driver), e i Docker secrets insieme ad alcune configurazioni di rete non hanno una corrispondenza 1:1. Niente di bloccante, ma va testato prima di assumere che la migrazione sia un semplice “find and replace”.

Container come servizi systemd: le QuadletQuesto è probabilmente il motivo migliore per scegliere Podman in un contesto server. Invece di lasciare un demone in background a gestire lo stato dei container, si delega tutto a systemd, che diventa responsabile di avvio, riavvio e supervisione, esattamente come per qualsiasi altro servizio di sistema.

Il meccanismo si chiama Quadlet: un file dichiarativo con estensione .container che Podman traduce automaticamente in una unit systemd. Per un servizio utente rootless, il file va in ~/.config/containers/systemd/. Esempio minimo per Nginx:

[Container]
ContainerName=web
Image=docker.io/library/nginx:latest
PublishPort=8080:80

[Install]
WantedBy=default.targetAttivazione:

systemctl --user daemon-reload
systemctl --user start webDa questo momento il container è gestito da systemd come un servizio qualsiasi: si riavvia in caso di crash, si integra con i log di journald, si può abilitare al boot. Aggiungendo l’etichetta AutoUpdate=registry a un container, inoltre, podman auto-update può controllare periodicamente nuove versioni dell’immagine e riavviare il servizio in automatico, senza bisogno di Watchtower o strumenti equivalenti.

Migrare da Docker ComposeChi ha un’infrastruttura basata su Compose ha due strade percorribili. La prima è continuare a usare Compose così com’è: il binario standalone docker compose può puntare al socket di Podman senza toccare i file docker-compose.yml esistenti:

systemctl --user enable --now podman.socketLa seconda è convertire i file Compose in Quadlet, così che sia systemd a gestire tutto nativamente. Scrivere le unit a mano è tedioso, quindi conviene usare podlet, un tool che legge un docker-compose.yml e genera i file Quadlet corrispondenti. C’è una curva di apprendimento, ma è comunque più veloce che partire da zero.

Docker resta rilevanteNonostante i vantaggi di Podman, Docker non sta scomparendo. L’ecosistema attorno a Docker (Compose, Swarm, e tutta la tooling che si integra con esso, inclusi molti sistemi CI/CD già configurati per il socket Docker) resta enorme, e non tutte le piattaforme gestiscono bene le peculiarità rootless di Podman. Se un team è già standardizzato su Docker, spesso ha più senso restare sull’esistente piuttosto che affrontare una migrazione per un guadagno marginale.

Dove Podman convince davvero è quando si parte da zero: setup più sicuro per default, nessun demone da tenere sotto controllo, integrazione diretta con systemd per la gestione del ciclo di vita dei servizi.

ConclusionePodman è un motore container completo, compatibile con Docker, che funziona senza demone e senza bisogno di privilegi root. Per l’uso quotidiano è quasi un drop-in replacement: si installa dal repository della distribuzione, si usano gli stessi comandi (o si crea l’alias docker=podman), e si ottengono benefici di sicurezza concreti senza dover reimparare nulla. I limiti di compatibilità, soprattutto su bind mount, GPU e secrets, vanno conosciuti e testati prima di una migrazione in produzione, ma per chi sta impostando nuovi ambienti containerizzati su Linux, specialmente se pensa di gestirli con systemd e Quadlet, vale decisamente la pena valutarlo.

Fonte originale: Hayden James, “Docker Alternative: Podman on Linux”, LinuxBlog.io.

#linux #container #devops #docker #guide #howto #podman #tutorial

0 0 0

Nmap su Linux: la guida pratica a scanning e discovery di rete per sistemisti

Chi amministra server Linux prima o poi si trova a dover rispondere a una domanda apparentemente semplice: “cosa è realmente esposto su questa macchin

Altro...

Chi amministra server Linux prima o poi si trova a dover rispondere a una domanda apparentemente semplice: “cosa è realmente esposto su questa macchina, e su questa rete?” La risposta corretta non arriva mai da un elenco di regole firewall letto a memoria, ma da una verifica attiva. Nmap (Network Mapper) resta lo strumento di riferimento per questo tipo di verifica: open source, nato nel 1997, ancora oggi il punto di partenza per audit di sicurezza, mappatura di reti e troubleshooting di connettività.

In questo articolo vediamo un percorso pratico per usare nmap in scenari reali di amministrazione sistemi: dalla discovery degli host alla scansione delle porte, fino agli script NSE per individuare vulnerabilità e configurazioni deboli.

Nota importante: esegui scansioni solo su reti e host di tua proprietà o per cui hai autorizzazione esplicita. La scansione non autorizzata può costituire reato in molte giurisdizioni, Italia compresa (accesso abusivo a sistema informatico, art. 615-ter c.p.).

InstallazioneNmap è disponibile nei repository di tutte le distribuzioni principali:

Debian/Ubuntu

sudo apt install nmap

Fedora/RHEL/CentOS

sudo dnf install nmap

Arch/Manjaro

sudo pacman -S nmap

Verifica

nmap --versionHost discovery: chi è vivo sulla reteIl primo passo in qualsiasi audit è capire quali host rispondono. Per questo si usa la scansione “ping”, che salta completamente il controllo delle porte:

nmap -sn 192.168.1.0/24Su una rete locale nmap non si limita all’ICMP: usa il protocollo ARP, molto più veloce e capace di scovare anche dispositivi che ignorano i normali ping. Su reti instradate, invece, combina richieste ICMP echo, TCP SYN sulla porta 443, TCP ACK sulla porta 80 e timestamp ICMP. Il risultato è un inventario rapido e silenzioso di ciò che è realmente connesso, utile ad esempio quando serve scoprire quale indirizzo IP il DHCP ha assegnato a un nuovo dispositivo.

Scansione delle porteUna volta identificati gli host attivi, il passo successivo è capire quali servizi espongono. Senza opzioni, nmap scansiona le 1.000 porte TCP più comuni e non richiede privilegi root:

nmap 192.168.1.10Da root, il tipo di scansione predefinito diventa la SYN scan (o “stealth scan”), più veloce perché non completa mai l’handshake TCP a tre vie e lascia meno tracce nei log applicativi:

sudo nmap -sS 192.168.1.10Le 1.000 porte di default lasciano fuori parecchio. Un’istanza MySQL su una porta non standard, o un demone SSH spostato sulla 2222, restano invisibili. Per una copertura completa:

sudo nmap -sS -p- 192.168.1.10 # tutte le 65.535 porte
sudo nmap -p 22,80,443,3306 192.168.1.10 # porte specifiche
sudo nmap -p 1-1024 192.168.1.10 # un intervalloVa tenuto d’occhio anche l’UDP, spesso trascurato ma sede di servizi critici come DNS (53), SNMP (161) e NTP (123):

sudo nmap -sU -p 53,161,123 192.168.1.1Le scansioni UDP sono più lente perché una porta chiusa non sempre genera una risposta esplicita: conviene limitare l’intervallo di porte o armarsi di pazienza.

Version detection e OS fingerprintingSapere che la porta 22 è aperta è utile. Sapere che dietro c’è OpenSSH 8.9p1 lo è molto di più, soprattutto per intercettare versioni obsolete durante un audit di sicurezza:

sudo nmap -sV 192.168.1.10

PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.6
80/tcp open http nginx 1.24.0
3306/tcp open mysql MySQL 8.0.35Con --version-intensity (da 0 a 9, default 7) si regola quanto nmap insiste nel probing: abbassarlo a 2-3 velocizza la scansione senza perdere molta precisione sui servizi comuni.

Per un’ipotesi sul sistema operativo, tramite fingerprinting dello stack TCP/IP, serve almeno una porta aperta e una chiusa:

sudo nmap -O 192.168.1.10Su macchine virtuali o stack TCP personalizzati la stima può essere imprecisa, ma resta un segnale utile per separare rapidamente server Linux, macchine Windows e dispositivi embedded su uno stesso segmento di rete.

Per un quadro completo in un colpo solo (OS detection, version detection, script scanning e traceroute) c’è la scansione aggressiva:

sudo nmap -A 192.168.1.10Genera molto traffico: da evitare su reti di produzione senza una finestra di manutenzione concordata.

Nmap Scripting Engine (NSE): oltre il semplice port scanLa vera potenza di nmap emerge con NSE, il motore di scripting che esegue controlli automatizzati sugli host scoperti: dalla ricerca di vulnerabilità note alla verifica di configurazioni deboli. Gli script risiedono in /usr/share/nmap/scripts/ e sono organizzati in categorie (default, auth, vuln, discovery, intrusive, safe).

Vulnerabilità note (categoria più invasiva, usarla con criterio)

sudo nmap --script=vuln 192.168.1.10

Accesso FTP anonimo

sudo nmap --script=ftp-anon -p 21 192.168.1.10

Header HTTP (spesso rivelano versioni software o debug info)

sudo nmap --script=http-headers -p 80,443 192.168.1.10

Open relay SMTP

sudo nmap --script=smtp-open-relay -p 25 192.168.1.20Un controllo rapido su porta 80/443 con http-headers capita spesso di far emergere header con versioni software esposte inutilmente: una correzione da cinque minuti che chiude una falla di information disclosure.

Output e automazionePer qualsiasi verifica che vada oltre il controllo estemporaneo, conviene salvare i risultati:

sudo nmap -sV 192.168.1.0/24 -oA scan_resultsIl flag -oA genera contemporaneamente output normale (.nmap), XML (.xml, utile per l’integrazione con altri strumenti e dashboard) e formato “grepable” (.gnmap), comodo per il parsing rapido da shell.

Combinazioni utili nel lavoro quotidiano# Solo porte effettivamente aperte, timing aggressivo su rete affidabile
sudo nmap -sS -T4 --open 192.168.1.10

Tutti i server SSH su una subnet

sudo nmap -p 22 --open -sV 192.168.1.0/24

Verifica che MySQL non sia esposto inutilmente

sudo nmap -p 3306 --open 192.168.1.0/24

Discovery + version scan solo sugli host realmente attivi

sudo nmap -sn 192.168.1.0/24 -oG - | grep "Up" | awk '{print $2}' | sudo nmap -sV -iL -MySQL esposto senza motivo è uno degli errori di configurazione più comuni e più pericolosi: una scansione mirata come quella sopra richiede due secondi e può intercettare il problema prima che lo trovi qualcun altro.

Nmap ha inoltre sei template di timing, da T0 (paranoico, lentissimo) a T5 (aggressivo): T3 è il default bilanciato, T4 va bene su reti locali affidabili, mentre su VPN o collegamenti lenti conviene scendere a T2 per evitare falsi negativi dovuti a pacchetti persi.

Porte filtrate: un segnale, non un fastidioNmap distingue tre stati: open, closed e filtered. Quest’ultimo indica che un firewall o un packet filter sta bloccando silenziosamente la sonda. Se compaiono molte porte filtrate su un server che non ti aspetti sia protetto da firewall, vale la pena indagare: potrebbe essere ufw, firewalld, un ruleset nftables o un security group del provider cloud. In ogni caso, è un’indicazione da non ignorare, e lo stesso principio vale per i probe di version detection e OS fingerprinting, che un firewall può alterare o azzerare.

ConclusioneNmap non si impara in un pomeriggio, ma i comandi visti coprono la maggior parte del lavoro quotidiano di un sistemista: discovery degli host, scansione delle porte, identificazione di servizi e versioni, script NSE per approfondire, e output strutturato per automazione o revisione successiva. La sequenza tipica è semplice: si parte con -sn per la discovery, si aggiunge -sV quando servono i dettagli sui servizi, e si porta NSE in campo quando serve scavare più a fondo. Timing prudente in produzione, aggressivo nel proprio lab: è una distinzione che vale la pena interiorizzare prima di lanciare la prima scansione su un ambiente che non si controlla del tutto.

Fonte originale: Hayden James, “nmap on Linux: Guide to Network Scanning and Discovery”, LinuxBlog.io.

#sicurezza #linux #guide #howto #tutorial #networking #nmap

0 0 0

PHP-FPM: perché pm static batte dynamic e ondemand sui server ad alto traffico

Il process manager sbagliato è spesso il vero collo di bottiglia di PHPQuando un’applicazione PHP inizia a rallentare sotto traffico reale, la prima c

Altro...

Il process manager sbagliato è spesso il vero collo di bottiglia di PHPQuando un’applicazione PHP inizia a rallentare sotto traffico reale, la prima cosa che si tende a ottimizzare è il codice: query più efficienti, cache applicativa, opcache. Tutte cose giuste, ma c’è un parametro a monte che viene sistematicamente sottovalutato e che, su un server con traffico costante, può pesare quanto tutto il resto messo insieme: il process manager (PM) di PHP-FPM.

La quasi totalità delle installazioni lascia pm impostato su dynamic, il valore di default, oppure viene consigliato di passare a ondemand quando la memoria disponibile è scarsa. Per un server che riceve traffico costante e prevedibile, però, esiste una terza opzione quasi sempre trascurata: pm = static. In questo articolo vediamo perché, come calcolare i parametri corretti e in quali scenari conviene davvero.

Le tre modalità del process managerPHP-FPM gestisce un pool di processi worker che eseguono lo script PHP per ogni richiesta. Il parametro pm nel file di configurazione del pool decide come questi worker vengono creati e distrutti nel tempo:

dynamic: il numero di processi figli varia dinamicamente in base a pm.max_children, pm.start_servers, pm.min_spare_servers e pm.max_spare_servers. All’avvio del servizio vengono lanciati pm.start_servers worker, poi il pool si espande e si contrae seguendo il carico.

ondemand: i processi vengono avviati solo quando arriva una richiesta, invece di essere già pronti all’avvio del servizio come accade con dynamic. Ottimo per il risparmio di memoria, meno per la latenza sul primo hit.

static: il numero di processi figli è fisso, determinato unicamente da pm.max_children. Nessuna logica di scaling: i worker vengono creati all’avvio e restano attivi.

La documentazione ufficiale di PHP elenca tutte le direttive globali di php-fpm.conf, ma la scelta tra queste tre modalità è più una questione di architettura del server che di singola direttiva.

Un parallelo utile: il governor della CPUChiunque abbia mai armeggiato con le impostazioni di risparmio energetico della CPU (CPUFreq governor, presenti sia su *nix che su Windows) riconoscerà lo stesso identico compromesso:

ondemand: scala la frequenza dinamicamente in base al carico corrente, saltando rapidamente alla frequenza massima per poi scendere durante i periodi di inattività.

conservative: scala la frequenza in modo più graduale rispetto a ondemand.

performance: mantiene sempre la CPU alla frequenza massima.

Il compromesso è lo stesso che si ritrova in PHP-FPM: un’impostazione privilegia la reattività immediata, le altre il risparmio di risorse durante i periodi di inattività. Con il governor performance, i core mantengono la frequenza massima invece di scalare verso il basso in idle: è un boost di prestazioni relativamente sicuro, il cui costo dipende quasi solo dai limiti termici della CPU. Lo stesso principio, applicato ai processi PHP-FPM invece che ai cicli di clock, è ciò che rende pm = static efficace su un server sotto carico costante.

Usare pm static per il massimo delle prestazioniL’impostazione pm = static dipende fortemente dalla memoria libera disponibile sul server. Se la memoria è scarsa, ondemand o dynamic restano scelte più sicure. Se invece la memoria è disponibile, static elimina gran parte dell’overhead di gestione del pool impostando il numero di worker al massimo che il server può sostenere.

In pratica, pm.max_children con static va calcolato come il numero massimo di processi PHP-FPM che possono girare senza generare pressione sulla memoria disponibile o sulla cache del sistema, e senza saturare le CPU con una coda di operazioni PHP-FPM in attesa.

Un caso reale: un server con 32 GB di RAM installata, pm = static e pm.max_children = 100, usa un massimo di circa 10 GB. Anche con circa 200 utenti attivi negli ultimi 60 secondi (dato preso da Google Analytics), circa il 70% dei worker PHP-FPM resta idle. Questo è precisamente il punto: PHP-FPM lavora sempre alla capacità massima configurata, indipendentemente dal traffico istantaneo, e i worker idle restano pronti a rispondere immediatamente ai picchi di traffico invece di dover attendere che il process manager ne generi di nuovi (e poi li termini dopo che pm.process_idle_timeout scade).

Calcolare pm.max_children, non indovinarloIl passaggio più importante, spesso saltato, è misurare invece di stimare a occhio. Prima si misura la dimensione media residente (RSS) di un worker PHP-FPM sotto carico reale:

ps --no-headers -o rss -C php-fpm | awk '{ sum += $1; n++ } END { print sum/n/1024 " MB" }'A questo punto si divide la memoria che si è disposti a dedicare a PHP-FPM per questo valore medio. Se un worker occupa in media 60 MB e si vogliono allocare 6 GB a PHP-FPM, il calcolo è circa pm.max_children = 100 (6144 / 60). È fondamentale lasciare margine per il sistema operativo, il web server e il database: non va mai assegnata a PHP-FPM tutta la RAM fisica disponibile.

Da qui si procede per iterazioni: si testa sotto carico reale e si affina il valore osservando uso di memoria, utilizzo CPU e tempi di risposta. Con pm = static, poiché i worker restano già residenti in memoria, i picchi di traffico si traducono in picchi di carico e CPU molto più contenuti, e le medie restano più stabili nel tempo.

Per monitorare i processi attivi in tempo reale si può usare top filtrato per utente:

top -bn1 | grep php-fpmImpostando anche pm.max_requests a un valore alto (o a 0 per disabilitare il riavvio periodico dei worker) si evita ulteriore overhead di gestione, ma questa scelta ha senso solo su un server di produzione senza memory leak noti negli script PHP. In generale conviene comunque impostare un valore alto ma finito, ad esempio pm.max_requests = 1000, per garantire un riavvio periodico dei worker senza reintrodurre overhead significativo.

Quando usare ondemand e dynamic invece di staticCon pm = dynamic capita spesso di incontrare un warning simile a questo nei log:

WARNING: [pool xxxx] seems busy (you may need to increase pm.start_servers,
or pm.min/max_spare_servers), spawning 32 children, there are 4 idle,
and 59 total childrenIl consiglio più comune, in questi casi, è passare a ondemand. Su un server costantemente sotto carico, però, questa scelta si ritorce contro: ondemand azzera i worker idle appena il traffico cala, per poi doverli rigenerare non appena il traffico torna a salire, scambiando risparmio di memoria con latenza di spawn esattamente nel momento peggiore. Un timeout di idle molto alto attenua il problema, ma a quel punto conviene semplicemente passare a pm.static con un pm.max_requests elevato.

dynamic e soprattutto ondemand restano invece la scelta giusta in scenari con molti pool PHP-FPM distinti sullo stesso server, ad esempio hosting condiviso con centinaia di account cPanel o siti diversi ciascuno con il proprio pool. In un ambiente con 100+ pool e 200+ domini, dove la maggior parte dei siti riceve pochissimo traffico, static o dynamic sprecherebbero enormi quantità di memoria su worker perennemente idle: ondemand chiude i worker inattivi liberando memoria, motivo per cui è diventato il default in ambienti come cPanel.

Un cenno ai containerLo stesso ragionamento va adattato quando PHP-FPM gira dentro un container con risorse limitate (ad esempio 0.5 vCPU e 1 GB di RAM) e la scalabilità è orizzontale, tramite orchestrazione (Docker Swarm, Kubernetes). In questi contesti pm.static resta spesso l’unica scelta sensata a livello di singolo container, ma la decisione su quando far partire un nuovo container non può basarsi solo su CPU e memoria: va monitorato anche il numero di processi PHP-FPM attivi rispetto a pm.max_children. Se il pool ha 50 worker configurati e 40 sono già occupati, è il momento di avviare un nuovo container, indipendentemente da quanto CPU e RAM stiano effettivamente segnalando in quel momento. Questo richiede di esporre lo stato di php-fpm status al sistema di autoscaling, valutato a intervalli brevi.

ConclusioneSuperata una certa soglia di traffico costante, ondemand e dynamic introducono un overhead di gestione dei processi che una configurazione static ben calcolata elimina alla radice. La regola pratica è semplice da enunciare ma richiede disciplina nell’applicarla: non indovinare pm.max_children, misurarlo a partire dal consumo medio di RSS dei worker sotto carico reale, lasciare margine per OS, web server e database, e poi affinare osservando le metriche reali. Su un server dedicato o una VM con traffico prevedibile, il guadagno in stabilità di CPU e tempi di risposta è concreto. Su hosting condiviso con centinaia di pool a bassissimo traffico, ondemand resta la scelta più razionale. Conoscere il proprio sistema, prima ancora del proprio codice PHP, è ciò che fa la differenza.

Fonte: PHP-FPM tuning: Using ‘pm static’ for max performance, LinuxBlog.io (Hayden James)

#linux #howto #performance #php

0 0 0

Fail2ban su Linux: come configurarlo per bloccare davvero gli attacchi brute-force

Perché ogni server esposto a Internet ha bisogno di Fail2banBasta controllare i log di autenticazione di un qualunque server Linux raggiungibile da In

Altro...

Perché ogni server esposto a Internet ha bisogno di Fail2banBasta controllare i log di autenticazione di un qualunque server Linux raggiungibile da Internet per rendersi conto di un fatto scomodo: nel giro di poche ore compaiono centinaia di tentativi di accesso falliti su SSH, pannelli web o form di login. Non è un attacco mirato: sono scanner automatici che perlustrano di continuo intere sottoreti, alla ricerca di credenziali deboli o servizi mal configurati. Ignorare questo rumore di fondo non è un’opzione, ma bloccare manualmente ogni IP sospetto è impraticabile.

Fail2ban risolve il problema analizzando i log in tempo reale e bannando automaticamente, tramite il firewall, gli indirizzi IP che superano una soglia di tentativi falliti in una finestra temporale configurabile. È uno strumento maturo, leggero, presente nei repository di tutte le principali distribuzioni, ma la configurazione di default lascia molto sul tavolo: un bantime di 10 minuti, tanto per fare un esempio, è quasi inutile contro un attaccante automatizzato che può semplicemente aspettare e riprovare.

In questa guida vediamo come installare, configurare e soprattutto tunare Fail2ban per ottenere una protezione reale, con particolare attenzione agli scenari più comuni su un server di produzione: SSH, Nginx, firewall moderni basati su nftables e persistenza dei ban tra un reboot e l’altro.

I tre concetti chiave: filter, jail, actionPrima di mettere mano alla configurazione conviene avere chiaro il modello concettuale di Fail2ban, perché tutta la configurazione ruota attorno a tre elementi:

Filter: un insieme di espressioni regolari che individuano le righe di log corrispondenti a un tentativo di accesso fallito.

Jail: combina un filtro con il percorso del log da monitorare, le soglie di attivazione e l’azione da eseguire al superamento della soglia.

Action: cosa succede quando la soglia viene superata. Nella maggior parte dei casi è una regola firewall, ma può includere anche l’invio di una notifica via email.

Fail2ban include già filtri e jail pronti per decine di servizi (SSH, Apache, Nginx, Postfix, Dovecot…). Nella pratica quotidiana ci si limita ad abilitare le jail utili e a regolare qualche parametro.

InstallazioneFail2ban è disponibile nei repository ufficiali di tutte le distribuzioni principali.

Debian/Ubuntu:

sudo apt update
sudo apt install fail2banFedora / RHEL 9+ / Rocky / AlmaLinux:

sudo dnf install fail2banArch Linux:

sudo pacman -S fail2banAbilitiamo e avviamo il servizio, poi verifichiamo lo stato:

sudo systemctl enable --now fail2ban
sudo systemctl status fail2banSe lo stato non riporta active (running), i log vanno controllati con sudo journalctl -u fail2ban -n 50.

Configurare Fail2ban nel modo correttoUn errore comune è modificare direttamente /etc/fail2ban/jail.conf: questo file viene sovrascritto a ogni aggiornamento del pacchetto, con conseguente perdita delle personalizzazioni. L’approccio corretto è creare un file dedicato dentro jail.d/:

sudo nano /etc/fail2ban/jail.d/custom.confIn alternativa si può copiare il file di default in jail.local, che ha priorità sui valori in jail.conf:

sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.localLa sezione [DEFAULT]Nella sezione [DEFAULT] si impostano i valori applicati a tutte le jail, salvo override specifico:

[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
ignoreip = 127.0.0.1/8 ::1bantime: durata del ban. Il default (spesso 10 minuti) è troppo permissivo: 1 ora è un buon punto di partenza, e per attaccanti persistenti si può salire a 24h o 1w. Il valore -1 produce un ban permanente, da usare con cautela.

findtime: la finestra temporale in cui vengono contati i fallimenti.

maxretry: numero di tentativi falliti prima del ban. 5 è ragionevole per SSH, si può scendere a 3 per una postura più aggressiva.

ignoreip: gli IP che non verranno mai bannati. È fondamentale aggiungere qui il proprio IP prima di abilitare qualsiasi jail: restare fuori dal proprio server per un ban accidentale è un classico errore da evitare.

Se il server ha un indirizzo IPv6 pubblico, va incluso anche quello: alcuni filtri più datati intercettano solo IPv4, quindi conviene verificare che le jail catturino correttamente entrambi i protocolli.

La jail SSHÈ la jail più importante per la maggior parte dei server. In jail.local o in un nuovo file /etc/fail2ban/jail.d/sshd.conf:

[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
maxretry = 3
bantime = 1hSe SSH è stato spostato su una porta non standard (buona pratica consigliata), va aggiornata la riga port. Sui sistemi basati su systemd, %(sshd_log)s punta automaticamente al journal; sui sistemi più datati che usano /var/log/auth.log o /var/log/secure, Fail2ban gestisce la differenza tramite il parametro backend. Dopo ogni modifica alla configurazione:

sudo fail2ban-client reloadJail per NginxI server web attirano un tipo diverso di abuso: scanner di URL 404, bruteforcer su form di login, bot che generano richieste inutili.

[nginx-http-auth]
enabled = true
logpath = %(nginx_error_log)s
maxretry = 3

[nginx-limit-req]
enabled = true
logpath = %(nginx_error_log)s
maxretry = 10La jail nginx-limit-req intercetta i client che superano i limit_req configurati in Nginx: è una combinazione efficace se il server web è già stato ottimizzato per gestire traffico elevato. Se Fail2ban segnala che un percorso di log non esiste, va impostato esplicitamente, ad esempio logpath = /var/log/nginx/error.log.

Verificare jail e ban attiviIl comando fail2ban-client è lo strumento principale per monitorare la situazione. Elenco delle jail attive:

sudo fail2ban-client statusDettaglio di una jail specifica, comprensivo di IP attualmente bannati:

sudo fail2ban-client status sshdPer bannare o sbannare manualmente un IP:

sudo fail2ban-client set sshd banip 203.0.113.99
sudo fail2ban-client set sshd unbanip 203.0.113.99Il comando unbanip è quello da tenere a portata di mano nel caso in cui ci si banni da soli per errore, prima di aver aggiunto il proprio IP a ignoreip.

Ban incrementali con la jail recidiveUna delle funzionalità meno conosciute ma più efficaci di Fail2ban è la jail recidive, che monitora il log interno di Fail2ban stesso e applica ban molto più lunghi agli IP che, dopo la scadenza di un primo ban, tornano a fare bruteforcing.

[recidive]
enabled = true
logpath = /var/log/fail2ban.log
action = %(action_mwl)s
bantime = 1w
findtime = 1d
maxretry = 5Con questa configurazione, un IP bannato 5 volte in un giorno riceve un ban di una settimana: è l’equivalente più vicino a una blocklist persistente senza dover integrare feed di threat intelligence esterni. Su sistemi che scrivono solo sul journal, va impostato backend = systemd nella jail recidive, oppure va verificato che Fail2ban stia scrivendo un log tradizionale.

Testare i filtri prima di attivarliPrima di abilitare una jail, conviene verificare che il regex del filtro corrisponda davvero alle righe di log presenti sul sistema:

sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.confL’output riporta gli IP individuati e il numero di righe che hanno fatto match. Un filtro che non intercetta nulla non protegge nulla: questo comando è indispensabile soprattutto quando si scrive un filtro personalizzato per un’applicazione custom, dentro /etc/fail2ban/filter.d/:

/etc/fail2ban/filter.d/myapp-auth.conf

[Definition]
failregex = ^<HOST> .* "POST /login" 401
ignoreregex =Il tag <HOST> è obbligatorio: Fail2ban lo sostituisce con un’espressione regolare che cattura l’indirizzo IP da bannare. Un pattern troppo generico rischia di bannare traffico legittimo, quindi va sempre validato con fail2ban-regex prima di collegarlo a una jail attiva.

nftables, firewalld e persistenza dei banSu Debian 12+ e Ubuntu 22.04+, nftables è il backend firewall di default. L’azione di ban predefinita di Fail2ban usa ancora iptables, che nella maggior parte delle installazioni funziona tramite il layer di compatibilità iptables-nft. Se invece si usa nftables puro, l’azione va impostata esplicitamente:

banaction = nftables-multiport
banaction_allports = nftables-allportsSu RHEL, Fedora e Rocky, dove firewalld è lo standard, va usata l’azione corrispondente:

banaction = firewallcmd-rich-rules
banaction_allports = firewallcmd-allportsPer default, i ban sono mantenuti in memoria e vengono persi a ogni riavvio. Per farli sopravvivere ai reboot va abilitato il database SQLite (su molte distribuzioni recenti è già attivo di default):

dbfile = /var/lib/fail2ban/fail2ban.sqlite3
dbpurgeage = 7dUna configurazione di partenza completaEcco un file /etc/fail2ban/jail.d/custom.conf che copre i casi d’uso più comuni su un server Linux tipico, da usare come punto di partenza:

[DEFAULT]
bantime = 2h
findtime = 10m
maxretry = 5
ignoreip = 127.0.0.1/8 ::1
dbfile = /var/lib/fail2ban/fail2ban.sqlite3
dbpurgeage = 7d

[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
maxretry = 3
bantime = 6h

[nginx-http-auth]
enabled = true
logpath = %(nginx_error_log)s
maxretry = 4

[nginx-limit-req]
enabled = true
logpath = %(nginx_error_log)s
maxretry = 10

[recidive]
enabled = true
logpath = /var/log/fail2ban.log
bantime = 1w
findtime = 1d
maxretry = 5sudo fail2ban-client reload
sudo fail2ban-client statusCosa Fail2ban non risolveFail2ban è uno strumento reattivo, non preventivo: banna un IP solo dopo che ha già effettuato diversi tentativi. Non copre, da solo, alcuni scenari:

attacchi bruteforce distribuiti su migliaia di IP diversi, ciascuno con uno o due tentativi soltanto;

exploit zero-day che non generano righe di log riconoscibili;

attacchi a livello applicativo che non producono un fallimento di autenticazione tracciabile.

Per una protezione a più livelli, Fail2ban va affiancato all’autenticazione SSH tramite chiavi (disabilitando del tutto l’autenticazione via password), a un firewall configurato correttamente e a una revisione periodica dei log. Un’attenzione particolare va riservata ai server dietro Cloudflare o un altro reverse proxy: senza ripristinare l’IP originale del visitatore (tramite mod_remoteip su Apache o real_ip_module su Nginx), Fail2ban finirebbe per bannare gli IP del proxy stesso invece degli attaccanti reali.

Comandi da tenere sempre a portata di manosudo fail2ban-client status — elenco di tutte le jail attive

sudo fail2ban-client status sshd — stato dettagliato di una jail

sudo fail2ban-client set sshd banip 1.2.3.4 — ban manuale di un IP

sudo fail2ban-client set sshd unbanip 1.2.3.4 — rimozione manuale di un ban

sudo fail2ban-client reload — ricarica la configurazione dopo una modifica

sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf — test di un filtro

sudo tail -f /var/log/fail2ban.log — monitoraggio dei ban in tempo reale

ConclusioneFail2ban resta uno degli strumenti che meritano un posto fisso su ogni server Linux esposto a Internet: l’installazione richiede pochi minuti e già con una configurazione minima riduce in modo drastico il rumore generato da scanner SSH e probe automatizzati sui servizi web. La differenza reale, però, la fanno tre accorgimenti spesso trascurati: impostare un bantime ragionevole (il default di 10 minuti è quasi inutile), aggiungere sempre il proprio IP a ignoreip prima di abilitare le jail, e attivare la jail recidive per penalizzare chi insiste. Da soli, questi tre passaggi fanno la differenza tra un’installazione di default e una protezione che funziona davvero.

Fonte: Fail2ban on Linux: Protect Your Server from Brute-Force Attacks, LinuxBlog.io

#sicurezza #linux #howto #tutorial

0 0 0

Swap attivo con RAM libera? Ecco come scoprire il processo colpevole con smem su Linux

Perché il tuo server usa swap con RAM libera (e come scoprire chi è il colpevole con smem)Capita spesso: un server ha 32 o 64 GB di RAM, il carico è t

Altro...

Perché il tuo server usa swap con RAM libera (e come scoprire chi è il colpevole con smem)Capita spesso: un server ha 32 o 64 GB di RAM, il carico è tutto sommato modesto, eppure free -h mostra qualche centinaio di MB o addirittura qualche GB in swap. Il riflesso istintivo di molti sistemisti è colpevolizzare la RAM insufficiente e chiedere un upgrade. Nella maggior parte dei casi, però, il problema non è la quantità di memoria disponibile, ma quali processi stanno finendo in swap e perché. Per rispondere serve uno strumento che guardi dentro ai singoli processi, non solo ai numeri aggregati: smem.

Perché Linux usa lo swap anche con RAM liberaIl kernel Linux non tratta la RAM come una risorsa da tenere il più vuota possibile: la usa aggressivamente per la page cache, per velocizzare I/O su file e librerie. Quando il kernel individua pagine di memoria che non vengono acquisite/toccate da tempo, può decidere di spostarle in swap per liberare RAM fisica da destinare alla cache, anche se tecnicamente c’è ancora memoria “libera” disponibile. Questo comportamento è regolato dal parametro vm.swappiness (0-100, con default storicamente a 60 su molte distribuzioni), che indica al kernel quanto è propenso a scambiare memoria anonima verso lo swap piuttosto che liberare pagine di cache.

Il punto chiave: prima di toccare vm.swappiness alla cieca, bisogna sapere chi sta effettivamente occupando swap. Un valore aggregato come quello di free non lo dice. Serve la vista per processo.

smem: memoria proporzionale, non solo RSSTool classici come top o ps mostrano RSS (Resident Set Size), che però ha un difetto noto: se due processi condividono le stesse pagine di memoria (librerie condivise, memoria mappata), quella memoria viene contata per intero in ognuno dei due, gonfiando artificialmente i numeri quando si sommano i processi.

smem risolve il problema calcolando anche:

USS (Unique Set Size): memoria usata esclusivamente da quel processo, non condivisa con nessun altro — utile per capire quanto libereresti davvero uccidendo il processo

PSS (Proportional Set Size): memoria condivisa divisa proporzionalmente tra i processi che la usano — la metrica più corretta per sommare l’uso reale di memoria di un sistema senza doppi conteggi

Swap: quanta memoria di quello specifico processo è stata spostata su disco

Installazionesmem non è quasi mai preinstallato, ma è nei repository di tutte le principali distribuzioni:

RHEL / CentOS / AlmaLinux / Fedora

dnf install smem

Debian / Ubuntu

apt install smemUso pratico: trovare chi consuma swapIl comando base per ordinare i processi per swap consumato:

smem -rs swapOutput tipico (troncato):

PID User Command Swap USS PSS RSS
28986 mysql /usr/sbin/mysqld --daemon 476372 10963864 10963932 10965112
29152 root /usr/sbin/rsyslogd -n 371424 3956 17475 43352
31423 root /opt/fluent-bit/bin/fluent 22508 26612 26739 29100Da un output così è immediato capire che mysqld e rsyslogd sono i principali responsabili dell’uso di swap su questo host, e non un generico “poca RAM”. Da qui l’indagine si sposta su quel servizio specifico: per MySQL, ad esempio, tipicamente significa rivedere innodb_buffer_pool_size rispetto alla RAM totale disponibile, o verificare connessioni/thread che allocano memoria inutilmente.

Alcune varianti utili del comando:

Ordina per USS (memoria realmente esclusiva del processo)

smem -rs uss

Filtra per utente

smem -u

Vista grafica a torta per RSS (richiede matplotlib)

smem --pie name -s rssDalla diagnosi al tuningUna volta identificati i servizi che finiscono in swap, ci sono due strade complementari:

Agire sul servizio: ridimensionare i buffer/pool applicativi (buffer pool di MySQL, heap JVM, cache applicative) in base alla RAM effettivamente disponibile, invece di lasciare valori di default pensati per macchine generiche.

Agire sul kernel, solo dopo aver capito il quadro reale: ridurre vm.swappiness per rendere il kernel meno aggressivo nello spostare memoria anonima in swap:

sysctl vm.swappiness=1
echo 'vm.swappiness=1' >> /etc/sysctl.confDa notare che vm.swappiness=0 non disabilita completamente lo swap su kernel recenti (dal 3.5 in poi il comportamento è cambiato rispetto alle versioni più vecchie), mentre valori molto bassi come 1 riducono drasticamente la propensione allo swap mantenendo comunque una valvola di sicurezza in caso di pressione di memoria reale. Su un database server dedicato, dove si preferisce quasi sempre tenere i dati “caldi” in RAM piuttosto che liberare cache, è una delle prime ottimizzazioni da considerare.

ConclusioneVedere swap attivo su un server con RAM apparentemente libera non è di per sé un allarme: è il comportamento normale di un kernel che ottimizza l’uso della cache. Il problema comincia quando lo swap coinvolge processi critici per la latenza, come un database o un servizio applicativo, degradando le performance in modo silenzioso. smem -rs swap è il primo comando da lanciare in questi casi: in pochi secondi isola il processo responsabile, distingue la memoria condivisa da quella esclusiva, e trasforma un sintomo generico (“il server è lento”) in un’azione concreta di tuning, sul servizio o sul kernel.

Fonte: LinuxBlog.io, “Diagnosing Swap Usage with smem on Linux”.

#linux #howto #tutorial #performance #swap

0 0 0