Impostare un firewall con uno script iptables

Da Guide@Debianizzati.Org.
Vai alla navigazione Vai alla ricerca

Introduzione

Questa guida non vuole essere il solito howto dove si spiega che in iptables ci sono le catene, le policy di default, quali sono e come funzionano, ma vuole essere una versione più pratica di un howto e spiegare come configurare un firewall per linux con le seguenti caratteristiche:

  1. policy di default: drop di tutti i pacchetti
  2. permettere solo ai servizi che ci interessano di essere accessibili dall’esterno
  3. permettere a certi servizi di essere accessibili solo dalla LAN

Descrizione delle regole

Dopo aver dichiarato alcune variabili passiamo alla pulizia delle chains e alla reinizializzazione dei contatori:

iptables -F #Cancellazione delle regole presenti nelle chains
iptables -X #Eliminazione delle chains non standard vuote
iptables -Z #Inizializzazione dei contatori (utile per il debugging)

Definiamo in seguito le policy di default per le 3 chains predefinite, settando tutto a DROP (in questo modo, tutto ciò che non è esplicitamente permesso è di fatto proibito!):

iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP

Le 2 policy built-in sono ACCEPT (che accetta tutti i pacchetti su una data chain) e DROP, che abbiamo già visto. Sono inoltre presenti 2 estensioni: LOG (relativa al modulo che si occupa del logging dell'attività del firewall) e REJECT (che ha fondamentalmente lo stesso effetto di DROP, ma risponde ai tentativi di connessione con un ICMP "port unreachable").
Infine, è possibile utilizzare altri due target speciali, RETURN e QUEUE, che però non approfondiremo.
Siamo finalmente giunti alle regole vere e proprie. Cominciamo accettando esplicitamente tutto il traffico, in uscita ed in entrata, sull'interfaccia di loopback. Si tratta di una scelta consigliata e assolutamente sicura, poichè il loopback non rappresenta un collegamento alla rete, ma viene utilizzato da alcune applicazioni per il loro correttto funazionamento:

iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

Come vediamo abbiamo specificato le due chains su cui agire (INPUT e OUTPUT), l'interfaccia relativa (lo) ed il target, ovvero la policy da seguire per i pacchetti che matchano la regola.
A questo punto vediamo all'opera una delle nuove funzionalità di iptables, il Rate Limiting, che ci permette di proteggerci dai SYN flood. Creando una nuova chain user-defined dove inviare TCP SYN, infatti, possiamo limitare il ratio di arrivo dei pacchetti ed evitare così attacchi di tipo Denial of Service (DoS), che mirano ad esaurire le risorse dei sistemi bersaglio:

iptables -N syn-flood
iptables -A INPUT -i $IFACE -p tcp syn -j syn-flood
iptables -A syn-flood -m limit limit 1/s limit-burst 4 -j RETURN
iptables -A syn-flood -j DROP

Quello che abbiamo fatto è creare una nuova chain user-defined chiamata "syn-flood", attraverso l'opzione -N. A questo punto abbiamo comunicato al Packet Filter di inviare tutti i pacchetti TCP con flag SYN settato (-p tcp syn) a tale chain e di limitare il ratio di arrivo di tali pacchetti.
Ora utilizziamo la Stateful Inspection per assicurarci che le nuove connessioni TCP siano dei pacchetti SYN e per rifiutare di conseguenza tutte quelle che non lo sono (possibili FIN scan o pacchetti malformati):

iptables -A INPUT -i $IFACE -p tcp syn -m state state NEW -j DROP

Infine passiamo a impostare le regole sui servizi offerti dal nostro server:

  1. Accesso pubblico al servizio
iptables -A INPUT -p tcp --dport 21 -m state --state NEW -j ACCEPT
  1. Accesso al servizio solo dalla nostra LAN
iptables -A INPUT -p tcp --dport 2605 -m state --state NEW -s 192.168.90.0/24 -j ACCEPT

Lo script

Creiamo quindi un nuovo file:

# nano /etc/iptables-firewall.sh

e diamogli questo contenuto, mettendo in pratica quanto visto nel paragrafo precedente:

#!/bin/sh

###########################
# Imposto alcune variabili
###########################

# Il path di iptables
IPT="/sbin/iptables"

# Interfaccia di rete esterna
IFACE=bond0


########################
# Un messaggio di avvio
########################

echo -n " Loading iptables rules..."


#####################################
# Pulisco la configurazione corrente
#####################################

# Cancellazione delle regole presenti nelle chains
$IPT -F
$IPT -F -t nat

# Eliminazione delle chains non standard vuote
$IPT -X

# Inizializzazione dei contatori (utile per il debugging)
$IPT -Z


###################################################
# Blocco tutto il traffico tranne quello in uscita.
# NOTA: per ragioni di sicurezza sarebbe opportuno
# bloccare anche il traffico in uscita e stabilire
# poi delle regole selettive
###################################################

$IPT -P INPUT DROP
$IPT -P FORWARD DROP
$IPT -P OUTPUT ACCEPT


##############################
# Abilito il traffico locale
##############################

$IPT -A INPUT -i lo -j ACCEPT
$IPT -A OUTPUT -o lo -j ACCEPT


#####################################################
# Imposto alcune regole per i pacchetti ICMP di ping
#####################################################

$IPT -A INPUT -p icmp --icmp-type echo-reply -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPT -A INPUT -p icmp --icmp-type echo-request -m limit --limit 5/s -m state --state NEW -j ACCEPT
$IPT -A INPUT -p icmp --icmp-type destination-unreachable -m state --state NEW -j ACCEPT
$IPT -A INPUT -p icmp --icmp-type time-exceeded -m state --state NEW -j ACCEPT
$IPT -A INPUT -p icmp --icmp-type timestamp-request -m state --state NEW -j ACCEPT
$IPT -A INPUT -p icmp --icmp-type timestamp-reply -m state --state ESTABLISHED,RELATED -j ACCEPT


###############################################
# Blocco le nuove connessioni senza SYN e
# mi proteggo dagli attacchi Denial of Service
###############################################

$IPT -N syn-flood
$IPT -A INPUT -i $IFACE -p tcp syn -j syn-flood
$IPT -A syn-flood -m limit limit 1/s limit-burst 4 -j RETURN
$IPT -A syn-flood -j DROP
$IPT -A INPUT -p tcp ! --syn -m state --state NEW -j DROP


#########################################################
# Consento il traffico delle connessioni gia' stabilite
#########################################################

$IPT -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT


#########################################################
# Regole sulle porte. Da modificare secondo le esigenze
# Per ogni regola nel commento viene indicato:
# 1) il numero della porta
# 2) il nome del servizio
# 3) il protocollo
# 4) il livello di accesso
#    - pubblico = accesso permesso a tutti
#    - LAN = accesso permesso solo ai client della LAN
#########################################################

# 21 - ProFTPD - FTP - pubblico
$IPT -A INPUT -p tcp --dport 21 -m state --state NEW -j ACCEPT

# 25 - Postfix - SMTP - pubblico
$IPT -A INPUT -p tcp --dport 25 -m state --state NEW -j ACCEPT

# 80/443 - Apache - HTTP - pubblico
$IPT -A INPUT -p tcp --dport 80 -m state --state NEW -j ACCEPT
$IPT -A INPUT -p tcp --dport 443 -m state --state NEW -j ACCEPT

# 110 - Dovecot - POP3 - pubblico
$IPT -A INPUT -p tcp --dport 110 -m state --state NEW -j ACCEPT

# 111 - Ulogd - Syslog Server - LAN
$IPT -A INPUT -p tcp --dport 111 -m state --state NEW -s 192.168.90.0/24 -j ACCEPT
$IPT -A INPUT -p tcp --dport 111 -m state --state NEW -s 10.0.0.0/24 -j ACCEPT
$IPT -A INPUT -p udp --dport 111 -m state --state NEW -s 192.168.90.0/24 -j ACCEPT
$IPT -A INPUT -p udp --dport 111 -m state --state NEW -s 10.0.0.0/24 -j ACCEPT

# 143 - Dovecot - IMAP - pubblico
$IPT -A INPUT -p tcp --dport 143 -m state --state NEW -j ACCEPT

# 667 - Darkstat - Statistiche - LAN
$IPT -A INPUT -p tcp --dport 667 -m state --state NEW -s 192.168.90.0/24 -j ACCEPT
$IPT -A INPUT -p tcp --dport 667 -m state --state NEW -s 10.0.0.0/24 -j ACCEPT

# 993 - Dovecot - IMAPs - pubblico
$IPT -A INPUT -p tcp --dport 993 -m state --state NEW -j ACCEPT

# 995 - Dovecot - POP3s - pubblico
$IPT -A INPUT -p tcp --dport 995 -m state --state NEW -j ACCEPT

# 1050/1051 - Zabbix - Monitor - LAN
$IPT -A INPUT -p tcp --dport 1050 -m state --state NEW -s 192.168.90.0/24 -j ACCEPT
$IPT -A INPUT -p tcp --dport 1050 -m state --state NEW -s 10.0.0.0/24 -j ACCEPT
$IPT -A INPUT -p tcp --dport 1051 -m state --state NEW -s 192.168.90.0/24 -j ACCEPT
$IPT -A INPUT -p tcp --dport 1051 -m state --state NEW -s 10.0.0.0/24 -j ACCEPT

# 1194 - OpenVPN - pubblico
$IPT -A INPUT -p tcp --dport 1194 -m state --state NEW -j ACCEPT
echo 1 > /proc/sys/net/ipv4/ip_forward

# 2000 - Sieve - Spam filter - localhost
# Non ha bisogno di configurazione

# 2293 - OpenSSH - SSH - pubblico
$IPT -A INPUT -p tcp --dport 2293 -m state --state NEW -j ACCEPT

# 2605 - BitMeter - Monitor - LAN
$IPT -A INPUT -p tcp --dport 2605 -m state --state NEW -s 192.168.90.0/24 -j ACCEPT
$IPT -A INPUT -p tcp --dport 2605 -m state --state NEW -s 10.0.0.0/24 -j ACCEPT

# 3306 - MySQL - localhost
# Non ha bisogno di configurazione

# 10000  Webmin - Monitor - LAN
$IPT -A INPUT -p tcp --dport 10000 -m state --state NEW -s 192.168.90.0/24 -j ACCEPT
$IPT -A INPUT -p tcp --dport 10000 -m state --state NEW -s 10.0.0.0/24 -j ACCEPT

# 10024/10025 - Amavis - localhost
# Non ha bisogno di configurazione


###############################################################
# Regole di sicurezza
# Block fragments and Xmas tree as well as SYN,FIN and SYN,RST
###############################################################

$IPT -A INPUT -p ip -f -j DROP
$IPT -A INPUT -p tcp --tcp-flags ALL ACK,RST,SYN,FIN -j DROP
$IPT -A INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
$IPT -A INPUT -p tcp --tcp-flags SYN,RST SYN,RST -j DROP


###############################
# Concludo lo script firewall
###############################

# echo -n "Iptables successfully configured."