A la lliçó anterior vas posar pany a la porta principal. Però srv-tramontana continua tenint totes les finestres obertes: qualsevol que arribi a la màquina pot parlar amb el 8080 de l'aplicació, i si demà PostgreSQL escoltés a 0.0.0.0 en lloc de a localhost, també amb el 5432. El bot de 203.0.113.44 continua trucant 47 vegades per matinada i ningú no l'hi impedeix.

Un tallafocs respon a una pregunta anterior a la de l'autenticació: qui té ni tan sols dret a parlar amb aquest servidor, i per quin port? En acabar aquesta lliçó tindràs una política escrita i aplicada —només SSH limitat i HTTPS des de fora, PostgreSQL només des de la xarxa interna, el 8080 tancat a l'exterior—, entendràs què hi ha sota de ufw, sabràs escriure un conjunt de regles de nftables des de zero i tindràs fail2ban bloquejant automàticament qui insisteixi. I tot això sense perdre la sessió SSH, perquè la regla d'or no canvia: no tanquis mai la porta per la qual estàs entrant.

Contingut

  1. Què és i què no és un tallafocs
  2. El model de Linux: netfilter i els seus frontals
  3. Taules, cadenes, hooks i estat de connexió
  4. ufw a la pràctica
  5. Perfils d'aplicació
  6. Quan ufw no arriba: nftables directe
  7. Equivalències iptables → nftables
  8. Regles de sortida i per què gairebé ningú no les posa
  9. sysctl de xarxa amb impacte en seguretat
  10. fail2ban: del registre al bloqueig automàtic
  11. Verificar des de fora amb nmap
  12. Cas Tramontana: la política i l'informe a la Marta

  1. Què és i què no és un tallafocs

Un tallafocs decideix quins paquets entren, surten o travessen una màquina, segons regles que tu escrius. Això és tot el que fa, i convé tenir-ho molt clar:

Un tallafocs sí Un tallafocs no
Redueix la superfície exposada a la xarxa Arregla un servei mal configurat
Limita qui pot intentar autenticar-se Impedeix un atac pel port que sí que deixes obert
Frena escanejos i soroll automatitzat Detecta que ja t'hi han entrat (això és 06-04)
Conté el dany lateral després d'un compromís Substitueix les actualitzacions de seguretat

La defensa en profunditat consisteix precisament a no dependre d'una sola capa: si un atacant supera el tallafocs, es troba amb SSH sense contrasenyes; si supera SSH, es troba amb svc-tramontana sense shell i amb ProtectSystem=strict; si arriba al disc, es troba amb els secrets xifrats del 06-05. Cap capa no és suficient tota sola, i aquesta és la idea.

  1. El model de Linux: netfilter i els seus frontals

Al nucli hi ha un únic motor de filtratge, netfilter. Tota la resta són maneres d'escriure-li regles:

Capa Què és Estat a Ubuntu 24.04
netfilter El motor, dins del nucli El que realment filtra
nftables El llenguatge i l'eina nft actuals L'opció nativa: una sola ordre per a IPv4, IPv6, ARP i bridge
iptables La interfície històrica Present com a iptables-nft: tradueix a nftables per sota
ufw Uncomplicated Firewall, frontal d'Ubuntu Instal·lat per defecte, escriu regles de nftables
firewalld Frontal amb zones, típic de RHEL Disponible, poc habitual aquí

La conseqüència pràctica: a Ubuntu 24.04, quan escrius ufw allow 22/tcp, ufw genera regles que acaben al mateix motor nftables que veuries amb nft list ruleset. No són sistemes rivals: són dos nivells d'abstracció sobre el mateix.

I l'advertiment que estalvia tardes senceres: fes servir l'un o l'altre, no tots dos alhora. Si actives ufw i a més habilites el servei nftables amb el teu propi /etc/nftables.conf, tindràs dos conjunts de regles competint, un flush ruleset que esborra les d'ufw en cada arrencada i un comportament impossible de raonar.

  1. Taules, cadenes, hooks i estat de connexió

Quatre conceptes i ja pots llegir qualsevol conjunt de regles:

  • Taula: el contenidor. A nftables es declara amb una família: ip (IPv4), ip6, inet (les dues alhora, el que voldràs gairebé sempre), arp, bridge, netdev.
  • Cadena: un conjunt ordenat de regles penjat d'un hook del nucli. Tres importen: input (paquets destinats a aquesta màquina, on escrius gairebé tot), output (paquets generats per ella, l'egress de l'apartat 8) i forward (paquets que la travessen, només si és encaminador o VPN → 08-04).
  • Política per defecte: què passa amb un paquet que no encaixa en cap regla. Només hi ha dues filosofies, i una és la correcta: policy drop (llista blanca: es prohibeix tot i es permet el necessari) davant de policy accept (llista negra: es permet tot i es prohibeix el dolent conegut). La llista negra és impossible de mantenir, perquè exigeix conèixer per endavant tot el que pot anar malament.
  • Estat de connexió: netfilter recorda les connexions en curs (connection tracking). Això permet escriure ct state established,related accept i despreocupar-te del trànsit de tornada.

Aquest últim punt és el que ho canvia tot. Sense filtratge amb estat hauries d'obrir a mà els ports alts per a les respostes, cosa que equival a no filtrar res. Amb estat la lògica és netíssima: new és el primer paquet d'una connexió i és aquí on es decideix; established pertany a una connexió ja acceptada i s'accepta sense mirar; related és una connexió secundària d'una altra (errors ICMP, dades d'FTP) i també s'accepta; i invalid no encaixa en cap connexió coneguda, així que es descarta.

  1. ufw a la pràctica

ufw és el que faràs servir el 95 % de les vegades. Comença sempre mesurant:

$ sudo ufw status verbose
Status: inactive

L'ordre correcte d'operacions, i no hi ha cap altra manera de fer-ho bé en una màquina remota:

# 1. Politiques per defecte: denegar entrant, permetre sortint
$ sudo ufw default deny incoming
$ sudo ufw default allow outgoing
$ sudo ufw default deny routed
# 2. PRIMER permetre SSH. Sense aixo, el pas 4 et deixa fora.
$ sudo ufw limit 22/tcp comment 'SSH amb limitacio de tasa'
# 3. La resta de serveis
$ sudo ufw allow 443/tcp comment 'HTTPS public'
$ sudo ufw allow from 10.0.2.0/24 to any port 5432 proto tcp comment 'PostgreSQL xarxa interna'
# 4. ARA si, habilitar
$ sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup

Aquell avís del pas 4 no és decoratiu: si executes ufw enable amb la política deny incoming i sense haver permès SSH, la sessió es talla a l'acte i només recuperes la màquina per la consola de la VM. Tingues aquella consola oberta abans de començar.

$ sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), deny (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
22/tcp                     LIMIT IN    Anywhere                   # SSH amb limitacio
443/tcp                    ALLOW IN    Anywhere                   # HTTPS public
5432/tcp                   ALLOW IN    10.0.2.0/24                # PostgreSQL xarxa interna
22/tcp (v6)                LIMIT IN    Anywhere (v6)

Quatre detalls que importen d'aquesta sortida:

  • ufw crea automàticament la regla IPv6 equivalent. És exactament el motiu pel qual no es desactiva IPv6 «per si de cas»: aquí està cobert.
  • LIMIT no és ALLOW: ufw limit bloqueja una IP que obre 6 o més connexions en 30 segons. És una defensa barata contra la força bruta, encara que fail2ban (apartat 10) és molt més fi.
  • El comment és documentació viva, i deny (routed) deixa clar que aquesta màquina no reenvia res, coherent amb l'ip_forward = 0 del 06-01.

deny davant de reject, que és una diferència real i no un matís:

Acció Què fa el nucli El que veu qui truca Quan fer-la servir
deny (DROP) Descarta en silenci Temps d'espera esgotat: no sap si la màquina existeix De cara a Internet: costa temps a l'escàner
reject Respon ICMP port unreachable o TCP RST «Tancat» immediat Xarxa interna: evita esperes de 30 s a les teves aplicacions

Gestionar regles existents exigeix veure-les numerades, perquè l'ordre importa: guanya la primera que encaixa.

$ sudo ufw status numbered
     To                         Action      From
     --                         ------      ----
[ 1] 22/tcp                     LIMIT IN    Anywhere
[ 2] 443/tcp                    ALLOW IN    Anywhere
[ 3] 5432/tcp                   ALLOW IN    10.0.2.0/24
$ sudo ufw delete 3
$ sudo ufw insert 1 deny from 203.0.113.44 comment 'bloqueig manual bot'

Compte: en esborrar la regla 3, les següents es renumeren. Esborra sempre de major a menor, o millor, esborra per especificació (sudo ufw delete allow 443/tcp), que és idempotent i no depèn de números.

  1. Perfils d'aplicació

ufw porta perfils amb nom a /etc/ufw/applications.d/, que tradueixen «OpenSSH» a «port 22/tcp»:

$ sudo ufw app list
Available applications:
  Nginx Full
  OpenSSH
$ sudo ufw app info OpenSSH
Profile: OpenSSH — Ports: 22/tcp
$ sudo ufw allow OpenSSH

I pots escriure el teu, que és la manera neta de documentar els ports de la teva aplicació:

[Tramontana]
title=Tramontana Reserves
description=Aplicacio web de reserves (servidor intermediari invers a 08-01)
ports=443/tcp

Guarda'l a /etc/ufw/applications.d/tramontana i recarrega'l amb sudo ufw app update Tramontana: si demà canvia el port, es canvia en un sol lloc.

  1. Quan ufw no arriba: nftables directe

ufw es queda curt quan necessites limitació de tasa fina, conjunts d'adreces (set), marcatge de paquets, NAT elaborat o simplement llegir exactament què hi ha. Aleshores s'escriu nftables a mà, a /etc/nftables.conf:

#!/usr/sbin/nft -f
flush ruleset

table inet filter {
    set xarxes_internes {
        type ipv4_addr ; flags interval ; elements = { 10.0.2.0/24 }
    }

    chain input {
        type filter hook input priority 0; policy drop;
        # Trànsit de tornada i brossa: el primer, per eficiència
        ct state established,related accept
        ct state invalid drop
        # Loopback: sense això es trenquen mig sistema i els túnels SSH
        iif lo accept
        # ICMP imprescindible (no bloquegis ICMP sencer: trenca la MTU)
        ip protocol icmp icmp type { echo-request, destination-unreachable, time-exceeded } accept
        ip6 nexthdr ipv6-icmp accept
        # SSH amb limitació d'intents nous, i HTTPS públic
        tcp dport 22 ct state new limit rate 6/minute burst 6 packets accept
        tcp dport 443 accept
        # PostgreSQL només des de la xarxa interna
        ip saddr @xarxes_internes tcp dport 5432 accept
        # La resta cau per la política, deixant rastre acotat
        limit rate 5/minute log prefix "nft-drop-in: " level info
        counter
    }

    chain forward {
        type filter hook forward priority 0; policy drop;
    }

    chain output {
        type filter hook output priority 0; policy accept;
    }
}

Comentaris sobre el disseny, que és el que s'aprèn:

  • table inet cobreix IPv4 i IPv6 amb les mateixes regles. Amb iptables necessitaries duplicar-ho tot a ip6tables, i és allà on la gent es deixa forats.
  • policy drop a input i forward, accept a output: llista blanca on importa.
  • L'ordre és deliberat: el més freqüent a dalt (established), l'excepcional a baix. Cada paquet recorre la cadena fins a trobar la seva regla.
  • No bloquegis tot l'ICMP. destination-unreachable transporta el descobriment de MTU: sense ell tindràs connexions que es pengen en transferir fitxers grans i et tornaràs boig buscant-ne la causa.
  • El log final porta el seu propi limit rate, perquè un escaneig pot generar milers de línies per segon i omplir-te el disc. Registrar el que es descarta és el que fa diagnosticable el tallafocs.
$ sudo nft -c -f /etc/nftables.conf && echo "sintaxi correcta"
sintaxi correcta
$ sudo systemctl enable --now nftables
$ sudo nft list ruleset | head -2
table inet filter {
        set xarxes_internes {

nft -c comprova sense aplicar: és el netplan generate dels tallafocs, i es fa servir sempre. La persistència la dona el servei nftables, que executa /etc/nftables.conf en cada arrencada; sense ell, nft és tan volàtil com ip addr add.

  1. Equivalències iptables → nftables

Continua havent-hi muntanyes de documentació escrita en iptables. Aquesta taula et permet llegir-la:

iptables nftables
-A INPUT -p tcp --dport 22 -j ACCEPT tcp dport 22 accept
-P INPUT DROP policy drop a la definició de la cadena
-m state --state ESTABLISHED,RELATED -j ACCEPT ct state established,related accept
-s 10.0.2.0/24 / -i lo -j ACCEPT ip saddr 10.0.2.0/24 / iif lo accept
-j REJECT --reject-with icmp-port-unreachable reject with icmpx type port-unreachable
iptables -L -n -v / iptables-save nft list ruleset
Regles separades a iptables/ip6tables Una de sola a table inet

  1. Regles de sortida i per què gairebé ningú no les posa

Gairebé tothom escriu output policy accept i se n'oblida. És còmode i és una oportunitat perduda: les regles d'egress no impedeixen que t'entrin, però limiten moltíssim el que un atacant pot fer després. Sense sortida lliure, no pot descarregar la seva segona fase des d'un servidor extern, no pot exfiltrar reserves.csv a un amfitrió qualsevol i no es pot unir a una xarxa de bots.

    chain output {
        type filter hook output priority 0; policy drop;
        ct state established,related accept
        oif lo accept
        udp dport { 53, 123 } accept       # DNS i NTP
        tcp dport { 53, 80, 443 } accept   # DNS/TCP i dipòsits apt
        ip daddr 10.0.2.0/24 accept        # xarxa interna
        limit rate 5/minute log prefix "nft-drop-out: "
    }

Per què gairebé ningú no les posa, amb honestedat: trenquen coses de manera subtil i difícil de diagnosticar. Un apt update contra un mirall nou, un webhook, una actualització de certificats... tot falla amb temps d'espera esgotats que ningú no relaciona amb el tallafocs. Si les adoptes, fes-ho mesurant primer quines sortides fa servir de debò la màquina (amb el registre a output i política accept durant una setmana) i només després canviant la política a drop.

  1. sysctl de xarxa amb impacte en seguretat

Aquests paràmetres no són de rendiment —això és 07-03—, sinó de comportament de la pila de xarxa davant d'abusos:

$ sudo tee /etc/sysctl.d/60-seguretat-xarxa.conf > /dev/null <<'CONF'
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.tcp_syncookies = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
CONF
$ sudo sysctl --system | grep -A8 60-seguretat
Paràmetre Què evita
rp_filter = 1 Paquets amb origen falsificat que no tornarien per la mateixa interfície (antispoofing)
accept_redirects = 0 / send_redirects = 0 Que un ICMP redirect aliè reescrigui la teva taula de rutes, i que tu informis de la topologia a tercers
accept_source_route = 0 Paquets que dicten el seu propi camí, tècnica clàssica d'evasió
tcp_syncookies = 1 Que una inundació SYN esgoti la cua de connexions a mig fer
icmp_echo_ignore_broadcasts = 1 Ser amplificador d'un atac smurf
log_martians = 1 Registra paquets impossibles: senyal primerenc d'alguna cosa estranya

Compte amb rp_filter = 1 (estricte): en una màquina amb diverses interfícies i rutes asimètriques descarta trànsit legítim. A srv-tramontana, amb una sola interfície, és segur; en un encaminador o una màquina amb VPN, fes servir 2 (mode lax).

  1. fail2ban: del registre al bloqueig automàtic

fail2ban tanca el bucle: llegeix els registres, detecta patrons d'abús i demana al tallafocs que bloquegi la IP durant un temps. No substitueix el tallafocs, el pilota.

$ sudo apt install -y fail2ban
$ sudo tee /etc/fail2ban/jail.local > /dev/null <<'CONF'
[DEFAULT]
# MAI et bloquegis a tu mateix: xarxa interna i portàtils de l'equip
ignoreip  = 127.0.0.1/8 ::1 10.0.2.0/24
bantime   = 1h
findtime  = 10m
maxretry  = 5
backend   = systemd
banaction = ufw

[sshd]
enabled   = true
port      = ssh
maxretry  = 3
bantime   = 24h
CONF
$ sudo systemctl enable --now fail2ban
$ sudo fail2ban-client status sshd
Status for the jail: sshd
|- Filter
|  |- Total failed:     47
|  `- Journal matches:  _SYSTEMD_UNIT=ssh.service + _COMM=sshd
`- Actions
   |- Currently banned: 1
   `- Banned IP list:   203.0.113.44

S'edita jail.local, mai jail.conf: el segon pertany al paquet i la propera actualització s'endú els teus canvis per davant. Les tres xifres que ho governen tot:

Paràmetre Significat Valor triat
maxretry / findtime Errors tolerats i finestra en què es compten 3 en 10 minuts
bantime Durada del bloqueig 24 h (-1 seria permanent)
banaction Com bloqueja ufw, per no crear un tercer conjunt de regles
ignoreip Qui és immune La teva xarxa i els teus portàtils

ignoreip és la protecció contra l'error més humiliant de tots: teclejar malament la contrasenya de sudo tres vegades i que el teu propi servidor et bloquegi. Si tot i així passa:

$ sudo fail2ban-client set sshd unbanip 10.0.2.77
$ sudo fail2ban-client set sshd banip 203.0.113.44

I l'honestedat que toca: amb el PasswordAuthentication no del 06-02, fail2ban ja no et protegeix que endevinin res, perquè no hi ha res per endevinar. El que fa és reduir soroll, consum i superfície: menys connexions, menys registres, menys oportunitats davant d'una fallada futura de sshd. És una mesura d'higiene, no la que et salva.

  1. Verificar des de fora amb nmap

Un tallafocs no està verificat fins que el mires des de fora. Des de portatil-alumne, contra la teva pròpia VM:

$ nmap -Pn -p 22,443,5432,8080 10.0.2.15
Nmap scan report for srv-tramontana (10.0.2.15)
PORT     STATE    SERVICE
22/tcp   open     ssh
443/tcp  open     https
5432/tcp open     postgresql
8080/tcp filtered http-proxy

Com es llegeix: open respon, closed respon que no hi ha ningú, i filtered significa que alguna cosa descarta el paquet en silenci — just l'efecte de la teva política deny. El 8080 apareix filtered: objectiu complert. El 5432 surt open perquè l'escaneig ve de 10.0.2.77, que és dins de la xarxa interna permesa; repetit des de fora d'aquell rang sortiria filtered.

Advertiment legal, sense matisos: escanejar ports de sistemes aliens sense autorització escrita és il·legal a Espanya i a la pràctica totalitat de les jurisdiccions, i pot constituir delicte encara que no causis cap dany. En aquest curs tot escaneig es fa des de portatil-alumne contra srv-tramontana, totes dues teves i dins del teu laboratori. Que una eina sigui legal no fa legal qualsevol ús: la diferència entre auditoria i atac és el permís, i el permís es documenta per escrit abans de teclejar res.

  1. Cas Tramontana: la política i l'informe a la Marta

La política queda així, i es decideix abans de tocar cap ordre:

Servei Port Des d'on Motiu
SSH 22/tcp Qualsevol, amb limit Administració; enfortit a 06-02
HTTPS 443/tcp Qualsevol Cara pública; el servidor intermediari arriba a 08-01
PostgreSQL 5432/tcp Només 10.0.2.0/24 Mai des d'Internet
Aplicació 8080/tcp Ningú Quedarà darrere del servidor intermediari invers (08-01)
Tota la resta — Denegat És una llista blanca

Diagnòstic quan «el servei no respon» i la causa ets tu: primer mira si el servei escolta (ss -tulpn | grep 8080), després si el tallafocs el descarta.

$ sudo journalctl -k --since "-15m" | grep 'UFW BLOCK' | tail -2
ago 18 19:22:41 srv-tramontana kernel: [UFW BLOCK] IN=enp0s3 SRC=203.0.113.44 DST=10.0.2.15 PROTO=TCP SPT=44210 DPT=8080 SYN
ago 18 19:23:02 srv-tramontana kernel: [UFW BLOCK] IN=enp0s3 SRC=198.51.100.9 DST=10.0.2.15 PROTO=TCP SPT=51882 DPT=23 SYN

Es llegeix d'esquerra a dreta: va entrar per enp0s3, des de SRC, cap a DPT (port de destinació). La primera línia és el bot buscant l'aplicació al 8080; la segona, algú provant Telnet el 2026. Si qui apareix bloquejat és el teu propi servei legítim, ja saps quina regla falta.

L'informe a la Marta, amb l'estructura del curs —què protegeix i què no protegeix—:

Tallafocs aplicat a srv-tramontana el 18/08. Què protegeix: només són accessibles des de fora SSH (amb limitació d'intents) i HTTPS; la base de dades només accepta connexions de la xarxa interna; el port 8080 de l'aplicació ja no és abastable des d'Internet; la IP 203.0.113.44, amb 47 intents d'accés, està bloquejada automàticament 24 hores per fail2ban, i qualsevol altra que ho intenti ho estarà també. Què NO protegeix: no defensa d'una fallada a la mateixa aplicació web, que continua sent accessible pel port que ha d'estar obert; no impedeix res a qui tingui credencials vàlides; no detecta que ja ens hi hagin entrat (això s'aborda a la revisió de detecció); i no xifra el trànsit, que continua viatjant en clar fins que instal·lem el certificat. Pendent: xifratge TLS i treure la contrasenya de la base de dades del fitxer de configuració.

Advertiment de seguretat i compliment: en un entorn real, qualsevol canvi a les regles de tallafocs d'un sistema que tracta dades personals s'ha de planificar amb finestra de manteniment, quedar documentat i revisar-lo el responsable de seguretat; l'exposició de serveis a Internet forma part de l'anàlisi de riscos exigit pel RGPD. Les tècniques d'escaneig i prova s'apliquen exclusivament sobre sistemes propis o amb autorització escrita.

Errors Comuns i Consells

  • ufw enable abans de permetre SSH. L'error clàssic i el més car. Permetre sempre primer, habilitar després, i amb la consola de la VM oberta.
  • Barrejar ufw i /etc/nftables.conf. Dos conjunts de regles competint i un flush ruleset que esborra les de l'altre en cada arrencada. Tria'n un.
  • Bloquejar tot l'ICMP. Trenca el descobriment de MTU i provoca connexions que es pengen en transferències grans. Permet almenys destination-unreachable i time-exceeded.
  • Oblidar iif lo accept. Mitja màquina deixa de funcionar: túnels SSH, bases de dades per sòcol TCP local, processos que es parlen per 127.0.0.1.
  • Regles sense comment. D'aquí a sis mesos ningú no gosarà esborrar una regla que no sap per a què hi és, i el conjunt de regles només creixerà.
  • log sense limit rate. Un escaneig t'omple /var/log en minuts, i quedar-te sense disc és una caiguda autoinfligida. I no confiïs només en el tallafocs per al que és intern: l'aplicació hauria d'escoltar únicament a 127.0.0.1 de totes maneres.
  • Consell: guarda /etc/nftables.conf o la sortida d'ufw status numbered a git, i afegeix la comprovació que el tallafocs està actiu a revisio_salut.sh.

Exercicis

  1. La política completa des de zero. Escriu la seqüència exacta d'ordres ufw per aplicar la política de la taula de l'apartat 12 en una màquina remota, en l'ordre correcte, incloent-hi les comprovacions abans i després.
  2. Regla que ufw no expressa bé. La Marta demana que només portatil-luis (10.0.2.30) pugui accedir al 8080 per a proves, amb un màxim de 10 connexions noves per minut. Escriu la regla de nftables i explica per què ufw es queda curt.
  3. Autobloqueig. El Luis truca: no pot entrar per SSH des de 10.0.2.77 i diu que «el servidor l'ha fet fora». Diagnostica el problema, resol-lo i proposa la correcció permanent.

Solucions

1. Amb la consola de la VM oberta i una segona sessió SSH activa:

# Mesurar abans
$ sudo ufw status verbose > /root/ufw-abans.txt ; ss -tulpn | grep LISTEN
# Politiques per defecte
$ sudo ufw default deny incoming && sudo ufw default allow outgoing
$ sudo ufw default deny routed
# SSH PRIMER, sempre; despres la resta
$ sudo ufw limit 22/tcp comment 'SSH administracio'
$ sudo ufw allow 443/tcp comment 'HTTPS public'
$ sudo ufw allow from 10.0.2.0/24 to any port 5432 proto tcp comment 'PostgreSQL intern'
# Habilitar i verificar
$ sudo ufw enable && sudo ufw status numbered
$ sudo diff -u /root/ufw-abans.txt <(sudo ufw status verbose)

I la verificació que de debò tanca la feina, des de portatil-alumne: obrir una sessió SSH nova sense tancar l'anterior, i nmap -Pn -p 22,443,5432,8080 10.0.2.15 per comprovar que el 8080 apareix filtered. Fixa't que el 8080 no necessita cap regla: la política deny incoming ja el cobreix. En una llista blanca, el que no s'anomena queda prohibit.

2. La regla a nftables, dins de la cadena input i abans del registre final:

        ip saddr 10.0.2.30 tcp dport 8080 ct state new \
            limit rate 10/minute burst 5 packets accept

ufw es queda curt per dos motius: només ofereix limit, amb un llindar fix (6 connexions en 30 segons) que no es pot ajustar sense editar les seves plantilles internes, i no permet combinar en una sola regla origen concret, port, estat de connexió i tasa personalitzada. Aquí necessitem exactament això. L'alternativa dins d'ufw seria sudo ufw allow from 10.0.2.30 to any port 8080 proto tcp, que dona el control d'origen però no la limitació de tasa.

Detall important: ct state new fa que la tasa s'apliqui només a connexions noves. Sense ell, limitaries també els paquets d'una transferència en curs i provocaries talls aleatoris que semblarien un problema de xarxa.

3. Diagnòstic en tres ordres:

$ sudo fail2ban-client status sshd | grep 'Banned IP list'
   `- Banned IP list:   203.0.113.44 10.0.2.77
$ sudo journalctl -u fail2ban --since "-1h" | grep 10.0.2.77
fail2ban.actions [1204]: NOTICE  [sshd] Ban 10.0.2.77

El Luis ha fallat tres vegades en deu minuts —probablement amb una clau equivocada o sense carregar a l'agent— i la gàbia sshd l'ha bloquejat 24 hores. Desbloqueig immediat i correcció permanent:

$ sudo fail2ban-client set sshd unbanip 10.0.2.77
$ grep ignoreip /etc/fail2ban/jail.local
ignoreip  = 127.0.0.1/8 ::1 10.0.2.0/24

I aquí hi ha la lliçó de debò: ignoreip ja incloïa 10.0.2.0/24, així que si el bloqueig es va produir és perquè el fitxer es va editar sense recarregar el servei, o perquè la línia es va escriure a jail.conf en lloc de a jail.local i una actualització del paquet se la va endur. La correcció permanent és sudo fail2ban-client reload després de cada canvi, verificar amb sudo fail2ban-client get sshd ignoreip, i afegir aquella comprovació a revisio_salut.sh. La causa arrel de fons és que el Luis fa servir contrasenya on hauria de fer servir la seva clau ed25519: revisa el seu authorized_keys.

Conclusió

srv-tramontana ja no parla amb qualsevol. Té una política de llista blanca escrita, aplicada en l'ordre correcte i verificada des de fora amb nmap: SSH limitat, HTTPS obert, PostgreSQL restringit a la xarxa interna i el 8080 invisible des d'Internet a l'espera del servidor intermediari invers del Mòdul 8. Saps que sota d'ufw hi ha nftables i que sota de nftables hi ha netfilter; saps escriure un conjunt de regles inet complet amb estat de connexió, conjunts i limitació de tasa; has ajustat els sysctl que eviten suplantació, redireccions i inundacions SYN; i fail2ban bloqueja automàticament 203.0.113.44 i qui vingui darrere, sense bloquejar-te a tu. El primer dels tres incidents oberts queda tancat.

I ara la part incòmoda. Tot el que has muntat en aquestes tres lliçons és prevenció, i la prevenció falla: falla per un CVE que encara no té pedaç, per una credencial filtrada —com la d'aquella còpia amb permisos 644—, per un descuit en obrir una regla «només un moment» o perquè algú amb accés legítim fa una cosa que no hauria de fer. El dia que falli, el teu tallafocs no et dirà res: continuarà aplicant obedientment les regles mentre la connexió de l'atacant figura com a established. La pregunta deixa de ser «com impedeixo que hi entrin?» i passa a ser «com m'assabento que ja hi han entrat?». Això és la lliçó 06-04: Sistemes de Detecció d'Intrusions, on muntaràs AIDE per vigilar la integritat dels fitxers, posaràs auditd a seguir cada escriptura sobre app.conf, buscaràs els senyals de compromís als registres, passaràs Lynis al teu servidor i aprendràs el procediment de resposta a incidents — inclosa la regla que a ningú no li agrada sentir: un servidor compromès es reinstal·la, no es neteja.

Curs de Linux: De Principiant a Administrador de Sistemes

Mòdul 1: Introducció a Linux

Mòdul 2: Comandes Bàsiques de Linux

Mòdul 3: Habilitats Avançades en la Línia de Comandes

Mòdul 4: Scripting en Shell

Mòdul 5: Administració del Sistema

Mòdul 6: Xarxes i Seguretat

Mòdul 7: Temes Avançats

Mòdul 8: Projectes Pràctics

© Copyright 2026. Tots els drets reservats