Mettere in sicurezza un VPS
2024-12-26
Un server privato virtuale o VPS
è un ambiente isolato creato su un server fisico a partire da una tecnologia di virtualizzazione. Questa soluzione offre tutti i vantaggi di un server standard: gestione completa della macchina e possibilità di scegliere il sistema operativo e le applicazioni da utilizzare, insieme a una scalabilità completa. Per approfondire: Cos’è un VPS? Vantaggi dei VPS
Regole fondamentali
- Non consentire il login SSH basato su password (solo chiavi)
- SSH non su porta standard 22
- Non consentire SSH all’utente root
- Installare un firewall e consentire solo le porte SSH, HTTP e HTTPS, dietro reverse-proxy
- Installare Fail2Ban (e CrowdSec) per bloccare i tentativi di accesso ripetuti
- Aggiornare i pacchetti di sistema
- Aggiornamenti automatici di sicurezza
- Fare un backup automatico e regolare
Il nostro VPS
Queste le caratteristiche:
- Debian 12
- 6 vCPU Cores
- 16 GB RAM
- 400 GB SSD
Si tratta di una Cloud VPS 2 di Contabo.
UFW
ufw
(Uncomplicated Firewall) è un frontend per iptables che semplifica la gestione del firewall su sistemi GNU/Linux.
- Collegarsi al server remoto e installare ufw col comando:
apt install ufw && ufw enable
Configurare UFW
ufw default allow outgoing && ufw default deny incoming
Il precedente comando imposta le politiche predefinite del firewall per il traffico in uscita e in entrata. Questo comando configura UFW per consentire tutto il traffico in uscita e bloccare tutto il traffico in entrata di default, fornendo una base di sicurezza per il sistema.
- Infine, consentire solo il traffico in ingresso dalle porte tcp 80 e 443 e sulla porta 1329 (o quella che si preferisce) per SSH:
ufw allow 80/tcp && ufw allow 443/tcp && ufw allow 1329
- Verificare le impostazioni:
> ufw status numbered verbose
Status: active
To Action From
-- ------ ----
[ 1] 1329 ALLOW IN Anywhere
[ 2] 80/tcp ALLOW IN Anywhere
[ 3] 443/tcp ALLOW IN Anywhere
[ 4] 1329 (v6) ALLOW IN Anywhere (v6)
[ 5] 80/tcp (v6) ALLOW IN Anywhere (v6)
[ 6] 443/tcp (v6) ALLOW IN Anywhere (v6)
SSH
SSH
(Secure Shell) è un protocollo crittografico progettato per consentire la comunicazione sicura su una rete non sicura. Viene comunemente utilizzato per accedere in modo remoto a sistemi informatici e per eseguire comandi da remoto in modo sicuro.
Generazione delle chiavi
- Sulla propria macchina locale, generare la coppia di chiavi:
ssh-keygen -t ed25519 -C "commento" -f ~/.ssh/keyname
cat ~/.ssh/keyname.pub
- Quindi collegarsi al server remoto con l’utente fornito dal provider (solitamente root):
ssh root@ip_vps -p 1329
- Creare un utente standard:
useradd -m velociraptor
usermod velociraptor -s /bin/bash
passwd velociraptor
usermod -aG sudo velociraptor
su - velociraptor
- Copiare la chiave pubblica creata in precedenza nel file
/home/user/.ssh/authorized_keys
, situato nella home dell’utente autorizzato a connettersi, nell’esempio velociraptor
Configurazione ssh
- Configurare SSH nel modo seguente:
> grep -v ^# /etc/ssh/sshd_config
Include /etc/ssh/sshd_config.d/*.conf
Port 1329
Protocol 2
LogLevel VERBOSE
MaxAuthTries 3
MaxSessions 3
AllowAgentForwarding no
AllowTcpForwarding no
ClientAliveCountMax 2
PubkeyAuthentication yes
PasswordAuthentication no
PermitEmptyPasswords no
KbdInteractiveAuthentication no
UsePAM yes
PrintMotd no
Banner none
PermitRootLogin no
AllowUsers velociraptor
MACs hmac-sha1,hmac-sha2-256,hmac-sha2-512
Nello specifico:
Port 1329
: specifica la porta su cui il server SSH ascolta le connessioni in arrivo. In questo caso, il server SSH ascolterà sulla porta 1329 anziché sulla porta predefinita 22Protocol 2
: specifica che il server SSH dovrebbe utilizzare solo la versione 2 del protocollo. La versione 1 del protocollo è considerata meno sicura e non dovrebbe essere utilizzataMaxAuthTries 3
: limita il numero di tentativi di autenticazione consentiti prima che una connessione venga interrottaAllowTcpForwarding no
: questa direttiva disabilita il forwarding TCP, che consente di inoltrare le connessioni TCP attraverso il server SSH. Ad esempio, un utente potrebbe utilizzare SSH per connettersi a un server e poi inoltrare una connessione a un altro server attraverso il primoClientAliveCountMax 2
: specifica il numero massimo di messaggi keep-alive che il server SSH invierà al client. Se il server non riceve una risposta dopo aver inviato il numero specificato di messaggi, chiuderà la connessionePubkeyAuthentication yes
: abilita l’autenticazione tramite chiave pubblica. Gli utenti possono autenticarsi utilizzando una coppia di chiavi pubbliche e private anziché una passwordPasswordAuthentication no
: disabilita l’autenticazione tramite passwordPermitEmptyPasswords no
: impedisce agli utenti di utilizzare password vuote per l’autenticazioneKbdInteractiveAuthentication no
: Disabilita l’autenticazione interattiva basata sulla tastiera. L’autenticazione interattiva è un metodo di autenticazione che può richiedere all’utente di inserire informazioni aggiuntive, come una password o un codice di verifica, tramite un prompt interattivoUsePAM yes
: abilita l’utilizzo del modulo di autenticazione PAM (Pluggable Authentication Modules) per gestire l’autenticazione degli utentiPrintMotd no
: impedisce la visualizzazione del “Message of the Day” all’accessoBanner none
: non visualizza alcun banner all’accessoPermitRootLogin no
: impedisce il login diretto come utente rootAllowUsers velociraptor
: specifica gli utenti che sono autorizzati a connettersi al server SSH
Una volta modificato il file /etc/ssh/sshd_config
, bisogna riavviare il servizio:
systemctl restart ssh.service && systemctl restart sshd.service
- Sulla propria macchina locale, creare il file
~/.ssh/config
:
Host *
ForwardAgent yes
ControlMaster yes
Compression yes
Host name
hostname ip_server
user velociraptor
IdentityFile ~/.ssh/keyname
TCPKeepAlive yes
port 1329
- Testare il collegamento col comando:
ssh name
NOTA: per eliminare la schermata di benvenuto, dare il seguente comando, una volta che il collegamento sia avvenuto correttamente:
echo "" > /etc/motd
ntfy
ntfy
è un servizio di notifica che consente di inviare notifiche push a dispositivi mobili e desktop utilizzando un protocollo semplice e leggero. È particolarmente utile per inviare avvisi o aggiornamenti in tempo reale da applicazioni o script.
Per ricevere una notifica ad ogni accesso SSH effettuato sul VPS, dobbiamo:
- Installare l’applicazione mobile sul cellulare o sul pc Linux da Flathub
- Utilizzare un server ntfy, come il nostro
- Aggiungere le righe seguenti nel file
/etc/profile
sul VPS
if [ -n "$SSH_CLIENT" ]; then
curl -H "Title: SSH Login" -H "Priority: urgent" -d "${USER}@$(hostname -f) from $(echo $SSH_CLIENT|awk '{print $1}')" https://your-domain-name.com/your-topic > /dev/null 2>&1
fi
- Iscriversi al topic dall’applicazione mobile
Fail2ban
Fail2ban
è un software open-source che monitora il sistema in tempo reale e, in base a determinati criteri di configurazione, blocca automaticamente gli indirizzi IP sospetti che tentano di accedere ripetutamente al server. Questo strumento aiuta a migliorare la sicurezza del server riducendo il rischio di accessi non autorizzati.
- Sulla macchina remota, installare fail2ban:
apt install fail2ban
Configurazione Fail2ban
- Installare
rsyslog
- Assicurarsi che sia presente il file
/var/log/auth.log
, altrimenti crearlo, e che appartenga al gruppoadm
:
touch /var/log/auth.log
chown root:adm /var/log/auth.log
A partire da Debian 8, il sistema di init predefinito è systemd, che gestisce i servizi e i log in modo diverso rispetto ai sistemi precedenti. Invece di scrivere i log in file di testo come /var/log/auth.log
, systemd utilizza un sistema di logging chiamato journal
. In un’immagine cloud minimale di Debian, il file /var/log/auth.log non esiste, quindi fail2ban non riesce a trovare gli eventi di autenticazione necessari per funzionare correttamente.
Per ripristinare il comportamento tradizionale, bisogna installare rsyslog
, un demone di logging che scrive i log in file di testo
- Creare il file
/etc/fail2ban/jail.local
, con le seguenti configurazioni:
[DEFAULT]
destemail = mail@duck.com
sendername = Fail2Ban
[sshd]
enabled = true
port = 1329
mode = aggressive
filter = sshd
maxretry = 3
findtime = 5m
bantime = 120m
logpath = %(sshd_log)s
sshd_backend = systemd
Questo file configura Fail2ban per monitorare e proteggere il servizio SSH sulla porta 1329, consentendo un massimo di 3 tentativi di accesso non validi entro un periodo di 5 minuti prima di bloccare l’indirizzo IP sospetto per 120 minuti.
- Quindi abilitare e avviare il servizio:
systemctl enable --now fail2ban && systemctl status fail2ban.service
- Infine, verificare che tutte le impostazioni siano corrette:
fail2ban-client status sshd
Status for the jail: sshd
|- Filter
| |- Currently failed: 0
| |- Total failed: 0
| `- File list: /var/log/auth.log
`- Actions
|- Currently banned: 0
|- Total banned: 0
`- Banned IP list:
Caddy
Un reverse proxy
è un server che si trova tra i client e uno o più server (o servizi) di backend. Quando un client invia una richiesta al reverse proxy, questo instrada la richiesta al server di backend appropriato e restituisce la risposta al client. Viene attivato come componente di sicurezza aggiuntivo a protezione di uno o più web server, per accettare al loro posto le richieste provenienti da Internet e inoltrarle ad un server di backend. Così il reverse proxy rappresenta l’unica connessione tra Internet e la rete privata.
Viene usato anche per bilanciare il carico, distribuendo le richieste tra più server di backend. Ad esempio, se si ha un’applicazione web che gira su tre server, il reverse proxy può inoltrare le richieste a uno dei tre server in base a vari algoritmi di bilanciamento. Questo aiuta a garantire che nessun singolo server venga sovraccaricato e migliora le prestazioni complessive.
Caddy è un server web open-source che funge da reverse proxy e offre funzionalità avanzate come il rinnovo automatico dei certificati SSL e una configurazione semplificata.
Installazione di caddy
- Sulla macchina remota, installare caddy:
apt install caddy
Configurazione
Modificare il file /etc/caddy/Caddyfile
, in base ai servizi che si installeranno:
# Imposta il livello di log globale
{
log {
output file /var/log/caddy/access.log {
roll_size 10mb
roll_keep 20 # mantenuti 20 file
roll_keep_for 720h # 1 mese
}
level INFO
}
}
# Configurazione del server web
https://www.mywebsite.it {
root * /home/user/website/
# Enable the static file server.
file_server
}
# NTFY
https://ntfy.mywebsite.it {
reverse_proxy localhost:3003
}
- Abilitare e avviare il servizio:
systemctl enable --now caddy.service
- Verificare il log in tempo reale del servizio:
journalctl -f -u caddy.service
Quando Caddy riceve una richiesta su una determinata porta (ad esempio la porta 443 per HTTPS), gestirà internamente il routing del traffico verso i servizi backend specificati nel file di configurazione, senza dover aprire le porte sul firewall del sistema
CrowdSec
CrowdSec è un software di sicurezza open-source progettato per proteggere i server e le applicazioni da attacchi informatici.
Il funzionamento che sta alla base è molto semplice: tutti condividono i risultati dei vari scan e così facendo si crea una lista globale degli ip utilizzati dagli attaccanti per sfruttare vulnerabilità o causare delle interruzioni di servizio.
CrowdSec utilizza dei bouncer
(buttafuori), che sono componenti che applicano le decisioni di blocco o limitazione delle richieste provenienti da indirizzi IP considerati malevoli. CrowdSec offre bouncer per vari sistemi, come iptables (per Linux), AWS, Cloudflare e molti altri.
Quando CrowdSec rileva un comportamento sospetto da un indirizzo IP, questo viene aggiunto a una blacklist. I bouncer utilizzano queste blacklist per bloccare o limitare le richieste in tempo reale.
Poiché CrowdSec è progettato per essere collaborativo, le blacklist possono essere aggiornate in tempo reale con informazioni provenienti da altri utenti.
Il runtime di CrowdSec ruota attorno ad alcuni semplici concetti:
- vengono letti i log (file system, journald, docker, ecc);
- i log vengono analizzati tramite parser (utilizzati per analizzare i log e identificare comportamenti sospetti);
- i log normalizzati vengono confrontati con gli scenari;
- quando uno scenario viene attivato, CrowdSec genera un avviso ed eventualmente una o più decisioni su quale azione dovrebbe essere intrapresa contro l’ip offensivo
Installazione e configurazione di CrowdSec
- Si installa col comando seguente:
curl -s https://packagecloud.io/install/repositories/CrowdSec/CrowdSec/script.deb.sh | bash
apt update
apt install crowdsec crowdsec-firewall-bouncer-iptables
- Abilitare il servizio col comando:
systemctl enable --now srowdsec.service
. - Installare il parser per caddy:
cscli parsers install crowdsecurity/caddy-logs
, quindi dare il comandosystemctl reload crowdsec
, in modo che vengano applicate effettivamente le nuove configurazioni - Installare la collection per caddy:
cscli collections install crowdsecurity/caddy
. Dare sempre il comandosystemctl reload crowdsec
- Dopo aver installato CrowdSec, dobbiamo assicurarci che il file
/etc/crowdsec/acquis.yaml
, contenga tutti i path dei log da monitorare:
[...]
---
filenames:
- /var/log/caddy/access.log
labels:
type: caddy
---
filenames:
- /var/log/fail2ban.log
labels:
type: fail2ban
---
Nel mio caso, ho aggiunto semplicemente il percorso dei log di fail2ban.
Comandi principali
cscli metrics
: mostra le metriche di CrowdSec, come il numero di attacchi rilevati e le azioni intrapresecscli metrics show acquisition
: mostra i log analizzaticscli decisions list
: elenca le decisioni attuali, mostrando quali IP sono stati bloccati e per quanto tempocscli ban <IP>
: aggiunge manualmente un indirizzo IP alla blacklistcscli unban <IP>
: rimuove un indirizzo IP dalla blacklistcscli parsers <list/upgrade --all>
: gestisce i parser, ossia gli strumenti che analizzano i logcscli bouncers <list>
: gestisce i bouncercscli alerts list
: mostra un elenco di allerte generate da CrowdSeccscli scenarios list
: elenca tutti gli scenari disponibili nel sistema. Gli scenari sono regole di rilevamento specifiche che definiscono come CrowdSec deve reagire a determinati comportamenti sospetti o attacchicscli collections list
: Elenca tutte le collezioni disponibili nel sistema. Le collezioni sono gruppi di scenari e parser che possono essere utilizzati per proteggere specifici servizi o applicazioni. Ad esempio, una collezione per un server Linux potrebbe includere scenari per rilevare attacchi SSH, mentre una collezione per un server web potrebbe includere scenari per rilevare attacchi di tipo SQL injectioncscli collections upgrade --all
: aggiorna tutte le collezionicscli hub update
: questo comando aggiorna l’hub di CrowdSec, che è un repository di risorse condivise, come scenari, parser e bouncercscli help
: mostra un elenco di comandi disponibili
CrowdSec Console
La Console di CrowdSec, ovviamente, non è obbligatoria per utilizzare CrowdSec, ma offre un’interfaccia visiva che può rendere più facile l’analisi delle informazioni e il monitoraggio delle minacce.
Maggiori informazioni qui
- Una volta loggati, per registrare un’istanza di CrowdSec con la Console, dare il comando
cscli console enroll $ENROLLMENT_KEY
- La
$ENROLLMENT_KEY
si trova nella pagina security engines
- Dalla console, accettare la registrazione
- Una volta accettata la registrazione, bisogna riavviare CrowdSec:
systemctl restart crowdsec
- Dall’Hub è possibile trovare nuove collezioni, bouncer, block-list, scenari e parser da installare
Aggiornamenti automatici di sicurezza
Gli unattended upgrades
(aggiornamenti non presidiati o automatici) sono una funzionalità presente in Debian (e in altre distribuzioni basate su Debian, come Ubuntu) che consente di installare automaticamente gli aggiornamenti di sicurezza, senza richiedere l’intervento dell’utente. Questa funzionalità è particolarmente utile per mantenere il sistema sicuro e aggiornato, riducendo il rischio di vulnerabilità.
- Installare il pacchetto col comando:
apt install unattended-upgrades
- Modificare il file
/etc/apt/apt.conf.d/50unattended-upgrades
, assicurandosi che siano decommentate le seguenti righe:
"origin=Debian,codename=${distro_codename},label=Debian";
"origin=Debian,codename=${distro_codename},label=Debian-Security";
"origin=Debian,codename=${distro_codename}-security,label=Debian-Security";
- Creare il file
/etc/apt/apt.conf.d/20auto-upgrades
con le seguenti righe:
APT::Periodic::AutocleanInterval "7";
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
Questo passaggio configura la frequenza con cui il sistema esegue operazioni di pulizia, aggiorna le liste dei pacchetti e installa gli aggiornamenti automatici.
- Abilitare il servizio:
systemctl enable --now unattended-upgrades
- Testarne l’esecuzione:
unattended-upgrades --dry-run --debug
Test
Un semplice test, per verificare che tutto sia stato fatto correttamente, può essere fatto con nmap
, dalla propria macchina locale:
# Per le connessioni TCP
sudo nmap -sT ilnostropianetaselvaggio.it
Not shown: 997 filtered tcp ports (no-response)
PORT STATE SERVICE
80/tcp open http
443/tcp open https
2222/tcp open EtherNetIP-1
# Per le connessioni UDP
sudo nmap -sU ilnostropianetaselvaggio.it
nmap (Network Mapper) è uno strumento open source utilizzato per la scansione e l’analisi delle reti. È molto potente e versatile, e viene comunemente utilizzato per vari scopi, tra cui scansionare le porte, in modo da identificare quali su un host sono aperte, chiuse o filtrate.
Lynis
Lynis
è uno strumento di auditing della sicurezza per sistemi basati su UNIX, come Linux, macOS, BSD e altri. Esegue una scansione di sicurezza approfondita del sistema, con lo scopo di fornire suggerimenti per un ulteriore hardening.
Si installa molto semplicemente:
sudo apt install lynis
Si esegue un audit col comando: lynis audit system
systemd
È possibile monitorare i servizi (unit
) falliti col comando:
systemctl list-units --failed
UNIT LOAD ACTIVE SUB DESCRIPTION
0 loaded units listed.
Docker
Nel caso si utilizzasse docker sul proprio VPS, importante che il container ascolti solo in localhost (127.0.0.1) e non su tutte le porte (0.0.0.0):
services:
ntfy:
image: binwiederhier/ntfy:latest
container_name: ntfy
[...]
ports:
- 127.0.0.1:3003:80
Può essere visto col comando:
[21:07 mar dic 24]root@ilnostropianetaselvaggio (4159):/etc/ilnostropianetaselvaggio/gitea
> dps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
56e06f541325 gitea/gitea:latest "/usr/bin/entrypoint…" 6 minutes ago Up 6 minutes 0.0.0.0:2222->22/tcp, 127.0.0.1:3006->3000/tcp gitea
7cea089fea8e binwiederhier/ntfy:latest "ntfy serve" 19 minutes ago Up 19 minutes 127.0.0.1:3003->80/tcp ntfy
Ascoltare solo su localhost limita l’accesso al servizio solo alle applicazioni che girano sulla stessa macchina. Questo riduce il rischio di attacchi esterni: quando un container ascolta su 0.0.0.0, qualsiasi servizio esterno può tentare di connettersi a quella porta. Se il container non è configurato correttamente o se ci sono vulnerabilità nel software in esecuzione, ciò potrebbe portare a exploit o accessi non autorizzati.
Riferimenti
- 26 Security Hardening Tips for Modern Linux Servers
- How to configure automated security updates on Debian automatically
SSH
- VPS e sicurezza - Marvin Pascale
- SSH server - Marvin Pascale
- SSH config - Marvin Pascale
- sudo: unable to resolve host Error in Ubuntu Linux
Fail2ban
- How to Secure Your Linux Computer with Fail2ban
- Preparing your machine
- Debian: auth.log missing from /var/log
Caddy
- Che cos’è un reverse proxy?
- Reverse proxy quick-start - Caddy Documentation
- log caddy
- Caddy — Configure Logging and Access Logs