Per migliorare la sicurezza del mio vps, ho pensato che non potevo lasciarlo solo con un “semplice” firewall e basta.
Per prima cosa, visto che ho installato WireGuard sia sul server VPS che sul mio client, ho spostato tutte le comnessioni da “any” per le interfacce di ftp, al wg0, linterfaccia di wireGuard
[ 7] 21/tcp on wg0 ALLOW IN 10.20.0.0/24
[ 8] 50000:50999/tcp on wg0 ALLOW IN 10.20.0.0/24
Facendo un controolo sul failban incorporato nel docker del mail sercve faccio una pessima scoperta (ma prevedibile)
docker exec -it mailserver iptables -L -n
OCI runtime exec failed: exec failed: unable to start container process: exec: "iptables": executable file not found in $PATH
Quindi il failban inserito nel container, non solo non fa il suo lavoro, ma come potrebbe farlo se modifica il caneuto del firewall all0interno di un container che non contiene iptables ?
Per tutelare la macchina allora dovrei installare failban a livello di SO, ma girovagando zmi sono imbattuto in CrowdSec che è un IDS/IPS ed anche WAF: perfetto !
In soldoni CrowdSec analizza i log e verifica se sono attacchi o meno.
per installarlo
curl -s https://packagecloud.io/install/repositories/crowdsec/crowdsec/script.deb.sh | bash
apt install -y crowdsec crowdsec-firewall-bouncer-iptables
Per prima cosa, allora ho disabilitato all’interno del container del mail server fail2ban
ENABLE_FAIL2BAN=0
e poi
docker compose restart mailserver
e cosiderato che CS deve leggere i log, ho modificato dove scrivere i log in modo che possano essere analizzati
il reverse proxy in
- /var/log/docker/nginx:/var/log/nginx
ed il mail server in
- /var/log/docker/mail:/var/log/mail
ho lasciato il “resto” nei path preimpostati.
I log sono definiti nel file
/etc/crowdsec/acquis.d/prod.yaml
ed il cui contenuto deve essere il seguente
filenames:
- /var/log/auth.log
- /var/log/nginx/*.log
- /var/log/mail.log
- /var/log/docker/mail/*.log
- /var/log/docker/nginx/*.log
labels:
type: syslog
riavviamo
systemctl restart crowdsec
e vediamo che succede
cscli metrics
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Acquisition Metrics │
├────────────────────────────────────────┬────────────┬──────────────┬────────────────┬────────────────────────┬───────────────────┤
│ Source │ Lines read │ Lines parsed │ Lines unparsed │ Lines poured to bucket │ Lines whitelisted │
├────────────────────────────────────────┼────────────┼──────────────┼────────────────┼────────────────────────┼───────────────────┤
│ file:/var/log/auth.log │ 209 │ 179 │ 30 │ 581 │ - │
│ file:/var/log/docker/mail/clamav.log │ 40 │ - │ 40 │ - │ - │
│ file:/var/log/docker/mail/fail2ban.log │ 45 │ - │ 45 │ - │ - │
│ file:/var/log/docker/mail/mail.log │ 27 │ 2 │ 25 │ 1 │ - │
│ file:/var/log/docker/nginx/access.log │ 324 │ - │ 324 │ - │ - │
│ file:/var/log/docker/nginx/error.log │ 1 │ - │ 1 │ - │ - │
│ file:/var/log/kern.log │ 61 │ - │ 61 │ - │ - │
│ file:/var/log/syslog │ 100 │ - │ 100 │ - │ - │
╰────────────────────────────────────────┴────────────┴──────────────┴────────────────┴────────────────────────┴───────────────────╯
bene: stiamo loggndo il traffico.
Ulteriore conferma da
cscli bouncers list
─────────────────────────────────────────────────────────────────────────────────
Name IP Address Valid Last API pull Type Version Auth Type
─────────────────────────────────────────────────────────────────────────────────
cs-firewall-bouncer ✔️ api-key
─────────────────────────────────────────────────────────────────────────────────
CrowdSec blocca gli ip PRIMA del loro arrivo sul container
| Azione | Comando |
| IP bannati | cscli decisions list |
| Sblocca IP | cscli decisions delete --ip X.X.X.X |
| Metriche | cscli metrics |
per verificare che l’estensioni del fireall siamo installate
il comando rowdsec-firewall-bouncer -version deve rispondere
rowdsec-firewall-bouncer -version
version: v0.0.34-debian-pragmatic-amd64-4144555453620958398aee64253dfd90bbc1f698
BuildDate: 2025-08-04_10:04:33
GoVersion: 1.24.5
Platform: linux
e con iptables -S | grep CROWDSEC abbiamo la conferma che il iptables hasubito un’aggiunta
-N CROWDSEC_CHAIN
-A INPUT -j CROWDSEC_CHAIN
-A CROWDSEC_CHAIN -m set --match-set crowdsec-blacklists-1 src -m comment --comment "CrowdSec: CAPI" -j DROP
-A CROWDSEC_CHAIN -m set --match-set crowdsec-blacklists-0 src -m comment --comment "CrowdSec: crowdsec" -j DROP
Il database gestito da CrowdSec non va bene in sqlite (secondo la mia testa) ed alloa utilizzo postresql in container il cui file docker-compose.yaml in /opt/postgis è
services:
postgres:
container_name: postgiis_container
image: postgis/postgis:16-3.5
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: defaultpassword
PGDATA: /var/lib/postgresql/data
POSTGRES_LOGGING_COLLECTOR: "off"
volumes:
- ./data:/var/lib/postgresql/data
- ./postgresql.conf:/etc/postgresql/postgresql.conf
- ./pg_hba.conf:/etc/postgresql/pg_hba.conf
ports:
- "5432:5432"
restart: always
command: ["postgres", "-c", "config_file=/etc/postgresql/postgresql.conf",
"-c", "hba_file=/etc/postgresql/pg_hba.conf",]
volumes:
data:
driver: local
logs:
driver: local
definire db ed utente di postgresql
sudo -u postgres psql
CREATE DATABASE crowdsec;
CREATE USER crowdsec WITH PASSWORD 'PASSWORD_FORTE';
GRANT ALL PRIVILEGES ON DATABASE crowdsec TO crowdsec;
GRANT USAGE, CREATE ON SCHEMA public TO crowdsec;
GRANT CONNECT ON DATABASE crowdsec TO crowdsec;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO crowdsec;
ALTER SCHEMA public OWNER TO crowdsec;
CREATE USER crowdsec_ro WITH PASSWORD 'PASSWORD_RO';
GRANT CONNECT ON DATABASE crowdsec TO crowdsec_ro;
GRANT USAGE ON SCHEMA public TO crowdsec_ro;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO crowdsec_ro;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
\q
l’utente crowdsec_ro potrebbe serivire per leggere le tabelle di postgresql.
ho impostato postgres_logging_collector a off in quanto mi dava problemi per la reazione del file di log, ma essendo un database solo per CrowdSec non mi ci ho pensato due volte as togliere ilfile di log.
modifichiamo il file /etc/crowdsec/config.yaml per togliere sqllite ed instanziare postgresql: da
db_config:
type: sqlite
db_path: /var/lib/crowdsec/data/crowdsec.db
a
db_config:
type: postgresql
host: 127.0.0.1
port: 5432
user: crowdsec
password: PASSWORD_FORTE
db_name: crowdsec
sslmode: disable
a questo punto
systemctl restart crowdsec
eseguendo
sudo -u root psql crowdsec -c "\dt"
devono apparire le seguenti tabelle
crowdsec=> \dt
List of relations
Schema | Name | Type | Owner
--------+----------------------------+-------+----------
public | alerts | table | crowdsec
public | allow_list_allowlist_items | table | crowdsec
public | allow_list_items | table | crowdsec
public | allow_lists | table | crowdsec
public | bouncers | table | crowdsec
public | config_items | table | crowdsec
public | decisions | table | crowdsec
public | events | table | crowdsec
public | locks | table | crowdsec
public | machines | table | crowdsec
public | meta | table | crowdsec
public | metrics | table | crowdsec
(12 rows)
allora tutto bene!
Siccome abbiamo cambiato le carte in tavola, crowdsec potrebbe non essere contento del cambio.
Potrebbe essere necessario eseguire
rm -f /etc/crowdsec/local_api_credentials.yaml
che non fa altro che cancellare il vecchio riferimento e per ricrearlo bisogna eseguire
cscli machines add localhost --auto
il cui output deve essere
Machine 'localhost' successfully added
ed allora far ripartire crowdsec
systemctl restart crowdsec
e vedere il risultato da
cscli alerts list
cscli alerts inspect "alert da sopra"
cscli decisions list
