Logs iptables : Configurer votre firewall pour Splunk

Bonjour à tous, aujourd’hui on prépare le 3ème article de la série sur Splunk et je complète celui sur iptables. Et on va regarder comment configurer les logs iptables de manière à pouvoir les exploiter dans Splunk dans le prochain article.

Configurer les logs iptables

La méthode simple

Sur une Debian 9, par défaut iptables ne trace presque rien et le peu qu’il indique se trouve dans le fichier /var/log/messages avec tout le reste d’une partie des journaux système, complètement hétérogène. CE n’est vraiment pas idéal pour intégrer ça simplement dans Splunk. On va donc faire trois choses dans ce TP:

  1. Configurer iptables pour qu’il ajoute un préfixe sur toutes les lignes de log qu’il écrit ;
  2. indiquer à rsyslog que toute les lignes de logs commençant ce préfixe doivent être placée dans un fichier à part ; et
  3. Configurer un politique de log pour iptables sur note machine.

Et on va commencer par le point numéro deux. Créer un fichier /etc/rsyslog.d/iptables.conf avec votre éditeur préféré avec le contenu suivant :

:msg,contains,"ACTION=" /var/log/iptables.log
& stop

Avec cette configuration, toutes les lignes contenant le texte ACTION= seront placé dans le fichier /var/log/iptables.log. Il ne nous reste plus qu’à redémarrer rsyslog.

systemctl restart rsyslog

Pour ceux qui sont pas au point sur iptables je invite à lire attentivement mon article précédent sur le sujet : Configuration avancée du firewall iptables. On va maintenant indiquer à iptables d’ajouter notre préfixe à ses lignes de logs avec les options ci-dessous sur les règles que l’on veut journaliser :

--log-prefix "INPUT-DROP:" -j DROP

Le problème c’est que le -j LOG fait loguer iptables et passer à la règle suivante ne permet pas d’appliquer une autre action de type DROP ou ACCEPT. On doit donc soit dupliquer nos règles et pour chaque règle que l’on veut tracer avoir une copie de notre ligne ACCEPT ou DROP avec un LOG à la place. Exemple pour journaliser les connexions acceptées :

iptables -A INPUT -p tcp -m multiport --dports 22,80,443 -j LOG
iptables -A INPUT -p tcp -m multiport --dports 22,80,443 -j ACCEPT

La méthode des barbus

Ce mode est efficace pour des configuration simple d’iptables (genre accept/drop sur quelque ports TCP), en revanche pour ce que je vous ai montré la dernière fois avec plusieurs dizaine de règles sauvegarder ça va vite être le bazar dans votre configuration iptables. Mais, il existe une astuce dans iptables qui permet de réaliser sur une seule règle les deux actions LOG et ACCEPT (ou DROP). Pour cela on doit créer une chaine personnalisée qui fera ces deux actions, et sauter vers cette chaine au lieu des actions par défaut. Voilà un exemple de configuration simple qui permet de loguer toute les connexions acceptées :

iptables -P INPUT DROP
iptables -t filter -N LOG_N_ACCEPT
iptables -t filter -A LOG_N_ACCEPT -j LOG --log-level warning --log-prefix "ACTION=INPUT-ACCEPT "
iptables -t filter -A LOG_N_ACCEPT -j ACCEPT
iptables -A INPUT -p tcp -m multiport --dports 22,80,443 -j LOG_N_ACCEPT

Voilà pour la théorie, en pratique on je vous propose de reprendre ma configuration de l’article précédent et de l’ajuster pour tracer les paquets refusé et accepté et de loguer dans le champs ACTION= quelle table d’iptables a pris la décision sur le paquet. Exemple, en éditant le fichier de sauvegarde pour y ajouter les logs iptables :

*raw
:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:RAW_LOG_N_DROP - [0:0]
-A PREROUTING -i eth0 -p tcp -m multiport --dports 22,80,443 -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j CT --notrack
-A PREROUTING -i eth0 -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m multiport --dports 22,80,443 -m hashlimit --hashlimit-above 100/sec --hashlimit-burst 1000 --hashlimit-mode srcip --hashlimit-name syn --hashlimit-htable-size 2097152 --hashlimit-srcmask 24 -j RAW_LOG_N_DROP
-A RAW_LOG_N_DROP -j LOG --log-prefix "ACTION=DROP-RAW "
-A RAW_LOG_N_DROP -j DROP
COMMIT
# 
*mangle
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:PRE_LOG_N_DROP - [0:0]
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j PRE_LOG_N_DROP
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN FIN,SYN -j PRE_LOG_N_DROP
-A PREROUTING -p tcp -m tcp --tcp-flags SYN,RST SYN,RST -j PRE_LOG_N_DROP
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,RST FIN,RST -j PRE_LOG_N_DROP
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,ACK FIN -j PRE_LOG_N_DROP
-A PREROUTING -p tcp -m tcp --tcp-flags ACK,URG URG -j PRE_LOG_N_DROP
-A PREROUTING -p tcp -m tcp --tcp-flags PSH,ACK PSH -j PRE_LOG_N_DROP
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,RST,PSH,ACK,URG -j PRE_LOG_N_DROP
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j PRE_LOG_N_DROP
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,PSH,URG -j PRE_LOG_N_DROP
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,PSH,URG -j PRE_LOG_N_DROP
-A PREROUTING -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,RST,ACK,URG -j PRE_LOG_N_DROP
-A PREROUTING -s 224.0.0.0/8 -j PRE_LOG_N_DROP
-A PREROUTING -s 169.254.0.0/16 -j PRE_LOG_N_DROP
-A PREROUTING -s 172.16.0.0/12 -j PRE_LOG_N_DROP
-A PREROUTING -s 192.0.2.0/24 -j PRE_LOG_N_DROP
-A PREROUTING -s 192.168.0.0/16 -j PRE_LOG_N_DROP
-A PREROUTING -s 10.0.0.0/8 -j PRE_LOG_N_DROP
-A PREROUTING -s 0.0.0.0/8 -j PRE_LOG_N_DROP
-A PREROUTING -s 240.0.0.0/5 -j PRE_LOG_N_DROP
-A PREROUTING -s 127.0.0.0/8 ! -i lo -j PRE_LOG_N_DROP
-A PREROUTING -p icmp -j PRE_LOG_N_DROP
-A PREROUTING -f -j PRE_LOG_N_DROP
-A PRE_LOG_N_DROP -j LOG --log-prefix "ACTION=DROP-PREROUTING "
-A PRE_LOG_N_DROP -j DROP
COMMIT
# 
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
:LOG_N_DROP - [0:0]
:LOG_N_ACCEPT - [0:0]
:fail2ban-ssh - [0:0]
-A INPUT -i eth0 -p tcp -m multiport --dports 22,80,443 -m tcp -m state --state INVALID,UNTRACKED -j SYNPROXY --sack-perm --timestamp --wscale 7 --mss 1460
-A INPUT -i eth0 -p tcp -m tcp -m state --state INVALID -j LOG_N_DROP
-A INPUT -p tcp -m multiport --dports 22 -j fail2ban-ssh
-A INPUT -i eth0 -p tcp -m connlimit --connlimit-above 100 --connlimit-mask 32 --connlimit-saddr -j REJECT --reject-with icmp-port-unreachable
-A INPUT -m recent --rcheck --seconds 86400 --name portscan --mask 255.255.255.255 --rsource -j DROP
-A INPUT -m recent --remove --name portscan --mask 255.255.255.255 --rsource
-A INPUT -p tcp -m multiport --dports 25,445,1433,3389 -m recent --set --name portscan --mask 255.255.255.255 --rsource -j LOG_N_DROP
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m multiport --dports 22,80,443 -j LOG_N_ACCEPT
-A LOG_N_ACCEPT -j LOG --log-prefix "ACTION=ACCEPT-INPUT "
-A LOG_N_ACCEPT -j ACCEPT
-A LOG_N_DROP -j LOG --log-prefix "ACTION=DROP-INPUT "
-A LOG_N_DROP -j DROP
-A fail2ban-ssh -j RETURN
-A INPUT -j LOG --log-prefix "ACTION=DROP-POLICY "
COMMIT

N’oubliez pas que si une IP source génère trop de log vous pouvez toujours l’exclure de la règle de log (et uniquement celle-ci) avec les options suivantes :

! -s <NET/MASK> # exclure le subnet
-s <NET/MASK> -m limit --limit 10/min # limiter à 10 lignes identiques par minute et pour le subnet.

Notez qu’activer les logs avec iptables peut générer un peu de volume selon le degré d’exposition de votre serveur. Aussi, je vous conseille de spécifier une politique de logrotate spécifique; sinon ça va piquer un peu au niveau de l’espace disque. Pour cela, créer un fichier /etc/logrotate.d/iptables avec le contenu suivant :

/var/log/iptables.log
{
 rotate 7
 daily
 missingok
 notifempty
 delaycompress
 compress
 postrotate
   invoke-rc.d rsyslog reload > /dev/null
 endscript
}

Bonus : tracer les connexions en sorties

N’oubliez pas que vous pouvez aussi loguer les connexions que votre serveur établis avec l’extérieur. Il n’y a aucune règle dans notre table OUTPUT, donc une seule commande par protocole TCP/UDP suffit :

iptables -I OUTPUT -m state -p tcp --state NEW ! -s 127.0.0.1 ! -d 127.0.0.1 -j LOG --log-prefix "ACTION=OUTPUT-TCP "
iptables -I OUTPUT -m state -p udp -s 127.0.0.1 ! -d 127.0.0.1 -j LOG --log-prefix "ACTION=OUTPUT-UDP "

Encore une fois, selon l’utilisation de votre machine cela peut devenir très verbeux. Donc faite attention à ce que vous faite…

Fin et suite à venir…

Et voilà c’est tout pour aujourd’hui sur les logs iptables, ça devrait compléter les questions que j’ai eu sur l’article précédent sur iptables dans lequel je n’abordais presque pas les logs. Et pour la suite le prochain TP pour voir comment intégrer ces logs dans notre Splunk est en cours de rédaction. Spoiler alert ci-dessous :

Logs iptables

6 commentaires on “Logs iptables : Configurer votre firewall pour Splunk

  1. Merci pour cet article. Cependant j’ai un problème.

    Voici les commandes que je passe :

    # Tout accepter
    sudo iptables -t filter -P INPUT ACCEPT
    sudo iptables -t filter -P FORWARD ACCEPT
    sudo iptables -t filter -P OUTPUT ACCEPT
    sudo iptables -t nat -P PREROUTING ACCEPT
    sudo iptables -t nat -P POSTROUTING ACCEPT
    sudo iptables -t nat -P OUTPUT ACCEPT
    sudo iptables -t mangle -P PREROUTING ACCEPT
    sudo iptables -t mangle -P INPUT ACCEPT
    sudo iptables -t mangle -P FORWARD ACCEPT
    sudo iptables -t mangle -P OUTPUT ACCEPT
    sudo iptables -t mangle -P POSTROUTING ACCEPT
    # Remettre les compteurs à zéro
    sudo iptables -t filter -Z
    sudo iptables -t nat -Z
    sudo iptables -t mangle -Z
    # Supprimer toutes les règles actives et les chaînes personnalisées
    sudo iptables -t filter -F
    sudo iptables -t filter -X
    sudo iptables -t nat -F
    sudo iptables -t nat -X
    sudo iptables -t mangle -F
    sudo iptables -t mangle -X
    # ajout de chaines
    sudo iptables -t filter -N LOG_N_ACCEPT
    sudo iptables -t filter -A LOG_N_ACCEPT -j LOG –log-level info –log-prefix « ACTION=INPUT-ACCEPT  »
    sudo iptables -t filter -A LOG_N_ACCEPT -j ACCEPT

    sudo iptables -t filter -N LOG_N_DROP
    sudo iptables -t filter -A LOG_N_DROP -j LOG –log-level warning –log-prefix « ACTION=INPUT-DROP  »
    sudo iptables -t filter -A LOG_N_DROP -j DROP
    # Politique par défaut
    sudo iptables -P INPUT DROP
    sudo iptables -P FORWARD DROP
    sudo iptables -P OUTPUT ACCEPT
    # Faire confiance à nous-mêmes
    sudo iptables -A INPUT -i lo -j ACCEPT
    # Connexions établies
    sudo iptables -A INPUT -m state –state ESTABLISHED -j ACCEPT
    # SSH
    sudo iptables -A INPUT -p tcp -s 192.168.1.1 –dport 22 -j LOG_N_ACCEPT
    sudo iptables -A INPUT -p tcp -s 192.168.2.2 –dport 22 -j LOG_N_ACCEPT

    Avec ça pas de soucis. Par compte je voudrais logger tout les paquets refusés sur Drop dans la politique par défaut. Je remplace donc sudo iptables -P INPUT DROP par sudo iptables -P INPUT LOG_N_DROP et j’obtiens l’erreur suivante : iptables: Bad policy name. Run `dmesg’ for more information.

    Est ce que quelqu’un a une idée de comment je peux logguer ce qui est refusé par le comportement par défaut ?

    • Je ne pense pas que tu puisses mettre une politique par défaut sur une table « custom » (comme un LOG_N_DROP), à mon avis l’option -P n’accepte que DROP ou ACCEPT. D’ailleurs, après un coup de RTF(amous)M :
      « -P, –policy chain target
      Set the policy for the chain to the given target. See the section TARGETS for the legal targets. Only built-in (non-user-defined) chains can have policies, and neither built-in nor user-defined chains can be policy targets.
       » – https://linux.die.net/man/8/iptables

      Le plus simple à mon avis, c’est de terminer tes règles de firewall par une règle qui log avant d’appliquer la politique de ton filter/prerouting/etc. et donc juste avant que ta politique par défaut s’applique et drop le paquet, au final ce sera équivalent !

      sudo iptables -t filter -j LOG –log-level warning –log-prefix "ACTION=POLICY-DROP"

      • Merci Etienne.

        En effet en cherchant sur d’autres sites et forums, je suis arrivé à la même conclusion. Sur un policy, on ne peux mettre que du DROP ou ACCEPT ou pas une chaine custom.

        Du coup j’ai laissé un policy pour INPUT qui n’a plus aucun effet, juste pour être homogène avec la policy des FORWARD et OUTPUT, et tout à la fin de mon script j’ai ajouté une nouvelle règle qui attrape tout le INPUT pour le logguer et drop. J’ai bien pensé à laisser un beau commentaire dans le script pour indiquer aux collègues de laisser cette règle tout en bas, sinon on ne pourra plus jamais se connecter à la VM !

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.