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

  1. Non consentire il login SSH basato su password (solo chiavi)
  2. SSH non su porta standard 22
  3. Non consentire SSH all’utente root
  4. Installare un firewall e consentire solo le porte SSH, HTTP e HTTPS, dietro reverse-proxy
  5. Installare Fail2Ban (e CrowdSec) per bloccare i tentativi di accesso ripetuti
  6. Aggiornare i pacchetti di sistema
  7. Aggiornamenti automatici di sicurezza
  8. 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

ssh_keys

  • 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 22
  • Protocol 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 utilizzata
  • MaxAuthTries 3: limita il numero di tentativi di autenticazione consentiti prima che una connessione venga interrotta
  • AllowTcpForwarding 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 primo
  • ClientAliveCountMax 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 connessione
  • PubkeyAuthentication yes: abilita l’autenticazione tramite chiave pubblica. Gli utenti possono autenticarsi utilizzando una coppia di chiavi pubbliche e private anziché una password
  • PasswordAuthentication no: disabilita l’autenticazione tramite password
  • PermitEmptyPasswords no: impedisce agli utenti di utilizzare password vuote per l’autenticazione
  • KbdInteractiveAuthentication 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 interattivo
  • UsePAM yes: abilita l’utilizzo del modulo di autenticazione PAM (Pluggable Authentication Modules) per gestire l’autenticazione degli utenti
  • PrintMotd no: impedisce la visualizzazione del “Message of the Day” all’accesso
  • Banner none: non visualizza alcun banner all’accesso
  • PermitRootLogin no: impedisce il login diretto come utente root
  • AllowUsers 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 gruppo adm:
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.

reverse_proxy

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 comando systemctl reload crowdsec, in modo che vengano applicate effettivamente le nuove configurazioni
  • Installare la collection per caddy: cscli collections install crowdsecurity/caddy. Dare sempre il comando systemctl 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 intraprese
  • cscli metrics show acquisition: mostra i log analizzati
  • cscli decisions list: elenca le decisioni attuali, mostrando quali IP sono stati bloccati e per quanto tempo
  • cscli ban <IP>: aggiunge manualmente un indirizzo IP alla blacklist
  • cscli unban <IP>: rimuove un indirizzo IP dalla blacklist
  • cscli parsers <list/upgrade --all>: gestisce i parser, ossia gli strumenti che analizzano i log
  • cscli bouncers <list>: gestisce i bouncer
  • cscli alerts list: mostra un elenco di allerte generate da CrowdSec
  • cscli 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 attacchi
  • cscli 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 injection
  • cscli collections upgrade --all: aggiorna tutte le collezioni
  • cscli hub update: questo comando aggiorna l’hub di CrowdSec, che è un repository di risorse condivise, come scenari, parser e bouncer
  • cscli 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

crowdsec_console

  • 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

SSH

Fail2ban

Caddy

CrowdSec

ntfy

lynis