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:
- Configurer iptables pour qu’il ajoute un préfixe sur toutes les lignes de log qu’il écrit ;
- indiquer à rsyslog que toute les lignes de logs commençant ce préfixe doivent être placée dans un fichier à part ; et
- 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 :
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 !
Avec plaisir !
petite coquille : LOG_N_IPS-ACCEPT versus LOG_N_ACCEPT
Coquille corrigée depuis un moment d’ailleurs, merci de la remontés d’infos.