Sécurité
Réseau
Firewall

Sécuriser IPv6 avec nftables : exemple de configuration

2 juillet 2025

10 min de lecture

nftables remplace iptables en offrant une syntaxe plus moderne et performante. Ce guide vous montre comment mettre en place un firewall robuste pour IPv6, avec des règles de base, protection contre les menaces courantes et persistance.

Pourquoi IPv6 nécessite un firewall dédié

L'une des différences cruciales entre IPv4 et IPv6 : il n'y a pas de NAT en IPv6. Chaque machine possède une adresse publique routée sur le réseau. Cela signifie :

  • Vos machines internes sont directement exposées au trafic entrant
  • Le firewall n'est plus optionnel, c'est un élément critique de sécurité
  • Vous ne pouvez pas compter sur l'obscurité pour vous protéger
  • Les règles de filtrage doivent être explicites et bien pensées

Prérequis

  • Linux avec nftables (Debian/Ubuntu: sudo apt install nftables)
  • Accès root ou sudo pour gérer les règles firewall

1. Qu'est-ce que la table inet ?

nftables utilise le concept de tables pour organiser les règles. La table inet est particulièrement puissante car elle unifie IPv4 et IPv6 dans une seule table. Cela signifie :

  • Une seule place pour gérer les règles communes
  • Pas de duplication de logique entre IPv4 et IPv6
  • Meilleure maintenabilité et moins de bugs

Les alternatives (tables ip et ip6 séparées) fonctionnent mais créent de la redondance.

2. Configuration complète : /etc/nftables.conf

Créez ou éditez /etc/nftables.conf avec la configuration suivante :

#!/usr/sbin/nft -f

table inet filter {
    chain input {
        type filter hook input priority 0;
        policy drop;

        # Loopback - accepter tout le trafic local
        iif lo accept

        # Établir les connexions existantes
        ct state established,related accept

        # Invalider les paquets cassés
        ct state invalid drop

        # ICMPv6 - NDP (Neighbor Discovery Protocol) - OBLIGATOIRE pour IPv6
        # Sans NDP, IPv6 ne fonctionne simplement pas
        ip6 nexthdr icmpv6 icmpv6 type {
            nd-neighbor-solicit,
            nd-neighbor-advert,
            nd-router-solicit,
            nd-router-advert,
            nd-redirect
        } accept

        # Erreurs ICMPv6 essentielles
        ip6 nexthdr icmpv6 icmpv6 type {
            destination-unreachable,
            packet-too-big,
            time-exceeded,
            parameter-problem
        } accept

        # Echo Request/Reply (ping) - optionnel
        ip6 nexthdr icmpv6 icmpv6 type { echo-request, echo-reply } accept

        # Rate limiting contre les attaques volumétriques
        # Limiter à 10 paquets par seconde par source
        limit rate 10/second accept

        # SSH avec protection rate limiting
        tcp dport 22 limit rate 15/minute accept

        # HTTP/HTTPS
        tcp dport { 80, 443 } accept

        # DNS (optionnel, si ce serveur sert de resolver)
        udp dport 53 accept
        tcp dport 53 accept

        # Par défaut : tout ce qui n'est pas accepté est droppé
        # (défini par la politique ci-dessus)
    }

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

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

3. NDP : le cœur du fonctionnement IPv6

Le Neighbor Discovery Protocol est à IPv6 ce que l'ARP est à IPv4, mais en plus critique. Sans accepter les paquets NDP, votre connectivité IPv6 cessera simplement de fonctionner.

Les types NDP essentiels :

TypeRôle
nd-router-solicit"Où est le routeur ?"
nd-router-advertRéponse du routeur avec ses configurations
nd-neighbor-solicit"Qui a cette adresse IPv6 ?" (résolution d'adresse)
nd-neighbor-advertRéponse : "C'est moi !"
nd-redirectOptimisation du routage (attention : peut être spoofée)

Important : Accepter nd-redirect a un coût de sécurité. Sur un réseau de confiance, c'est OK ; sur un réseau hostile, envisagez de le bloquer.

4. Politique de filtrage : drop vs reject

  • policy drop : silencieusement ignorer les paquets non acceptés (pas de réponse)
  • policy reject : envoyer une réponse "connexion refusée" (révèle un firewall actif)

drop est généralement préféré car il rend plus difficile le scanning de port. Vous pouvez quand même logger les drops si nécessaire.

5. Activer et vérifier nftables

Appliquez la configuration et vérifiez qu'elle fonctionne :

sudo systemctl enable --now nftables
sudo nft list ruleset

Vérifiez également la connectivité :

# Tester IPv6 via ping
ping6 -c 2 2001:4860:4860::8888  # Google's IPv6 DNS

# Voir les stats des règles
sudo nft list ruleset counters

6. Protection contre le scanning et les attaques

Rate limiting

Le rate limiting ralentit les attaques automatisées :

# Limiter les connexions SSH à 15 par minute par adresse IP
tcp dport 22 limit rate 15/minute accept

# Limiter le trafic ICMP global
limit rate 10/second accept
Filtrage des paquets invalides
# Invalider et logger les paquets cassés
ct state invalid log prefix "Invalid packet: " drop

Les adresses link-local (fe80::/10) sont locales au segment. Les paquets IPv6 avec des adresses link-local comme source ne devraient jamais venir d'Internet :

# Bloquer les paquets avec source link-local (IP spoofing)
ip6 saddr fe80::/10 drop

7. Règles spécifiques par service

SSH sécurisé

Accepter SSH mais avec rate limiting strict :

# TCP port 22 avec limite de connexions
tcp dport 22 limit rate 15/minute ct state new accept
Web (HTTP/HTTPS)
# HTTP (80) et HTTPS (443)
tcp dport { 80, 443 } ct state new accept
DNS

Si ce serveur fait office de résolveur DNS :

# DNS sur UDP et TCP
udp dport 53 accept
tcp dport 53 accept

8. Persistance : sauvegarder votre configuration

Après avoir validé vos règles, sauvegardez-les :

sudo nft list ruleset > /etc/nftables.conf
sudo systemctl restart nftables

Vérifiez que nftables se relance correctement au démarrage :

sudo systemctl enable nftables

9. Monitoring et debugging

Voir les paquets droppés en temps réel
sudo nft monitor
Compter les matches par règle
sudo nft list ruleset counters
Ajouter du logging

Modifiez votre configuration pour logger les paquets rejetés :

# Dans la chaîne input, avant le drop final
log prefix "INPUT_DROP: " drop

Puis consultez les logs :

sudo journalctl -u nftables -f

10. Bonnes pratiques de sécurité IPv6

  1. Bloquer tout par défaut, n'ouvrir que le strict nécessaire
  2. Accepter les types NDP (nd-neighbor-solicit, nd-neighbor-advert, nd-router-solicit, nd-router-advert)
  3. Rate limiter le SSH et autres services sensibles
  4. Filtrer les link-local en entrée (pas de source fe80::/10)
  5. Logger les paquets invalides pour détecter les attaques
  6. Tester votre configuration avec ping6, curl, nmap avant de la déployer
  7. Versionner votre configuration dans un gestionnaire de versions (git)

11. Protection contre les Router Advertisements malveillants

Les Router Advertisements (RA) sont des messages critiques pour IPv6 : ils annoncent la présence d'un routeur et les préfixes disponibles. Un attaquant peut envoyer des RA malveillants pour :

  • Rediriger le trafic vers son propre routeur
  • Injecter des préfixes IPv6 malveillants
  • Créer une situation d'homme au milieu
Désactiver les RA non authentifiés

Si votre réseau est contrôlé et que vous ne dépendez que d'un routeur de confiance, vous pouvez bloquer les RA en provenance d'autres sources :

# Accepter les RA uniquement du routeur connu (remplacez par votre gateway)
ip6 saddr fe80::1 icmpv6 type nd-router-advert accept

# Bloquer tous les autres RA
ip6 nexthdr icmpv6 icmpv6 type nd-router-advert drop
Utiliser SLAAC sécurisé (DNSSEC, SAVI)
  • DNSSEC : signer les enregistrements DNS pour valider les routeurs
  • SAVI (Source Address Validation Improvement) : protocole pour vérifier que l'adresse source est légitime

Mais attention : ces mesures complexifient la configuration. Pour la plupart des cas, accepter les RA standards depuis le routeur suffit.

12. Filtrage par préfixe IPv6 (/64)

Un réseau IPv6 classique utilise un /64 (18,446,744,073,709,551,616 d'adresses !). Vous pouvez filtrer les paquets basés sur le préfixe :

# Accepter le trafic entrant uniquement du préfixe 2001:db8:1:1::/64
ip6 saddr 2001:db8:1:1::/64 accept

# Bloquer les paquets provenant d'autres préfixes non autorisés
ip6 saddr != 2001:db8:1:1::/64 drop

Cas d'usage : Si vous avez une zone DMZ avec des serveurs en 2001:db8:1:100::/64, vous pouvez accepter leur trafic et bloquer tout le reste.

Lister ses préfixes actifs

Pour voir vos préfixes IPv6 actuels :

ip -6 addr show
# Cherchez le préfixe après "inet6" (exemple : 2001:db8:1:1::1/64)
Exemple : DMZ IPv6 avec préfixes distincts
#!/usr/sbin/nft -f

table inet filter {
    chain input {
        type filter hook input priority 0;
        policy drop;

        iif lo accept
        ct state established,related accept

        # Accepter le trafic de la DMZ (préfixe interne)
        ip6 saddr 2001:db8:1:100::/64 tcp dport { 80, 443 } accept

        # Accepter le trafic d'admin depuis une source connue
        ip6 saddr 2001:db8:1:200::1 tcp dport 22 accept

        # NDP - essentiel
        ip6 nexthdr icmpv6 icmpv6 type {
            nd-neighbor-solicit, nd-neighbor-advert,
            nd-router-solicit, nd-router-advert
        } accept
    }

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

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

Cette approche est utile pour les serveurs avec plusieurs interfaces ou des réseaux multi-segments.

13. Exemple complet avec logging

Voici une configuration plus robuste avec logging :

#!/usr/sbin/nft -f

table inet filter {
    chain input {
        type filter hook input priority 0;
        policy drop;

        iif lo accept
        ct state established,related accept
        ct state invalid log prefix "INVALID: " drop

        # Bloquer les link-local en entrée (IP spoofing)
        ip6 saddr fe80::/10 log prefix "LINK_LOCAL_SPOOF: " drop

        # NDP - OBLIGATOIRE
        ip6 nexthdr icmpv6 icmpv6 type {
            nd-neighbor-solicit, nd-neighbor-advert,
            nd-router-solicit, nd-router-advert
        } accept

        # Erreurs ICMP
        ip6 nexthdr icmpv6 icmpv6 type {
            destination-unreachable, packet-too-big,
            time-exceeded, parameter-problem
        } accept

        # Ping
        ip6 nexthdr icmpv6 icmpv6 type { echo-request, echo-reply } accept

        # Services
        tcp dport 22 limit rate 15/minute ct state new accept
        tcp dport { 80, 443 } ct state new accept
        udp dport 53 accept
        tcp dport 53 accept

        # Tout le reste est dropé (par policy)
    }

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

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

14. Ressources et suites

Pour approfondir vos connaissances :

15. Conclusion

Avec nftables et IPv6, vous obtenez un firewall moderne, performant et transparent. Les règles que nous avons vues suivent le principe du Least Privilege : bloquer tout, accepter seulement ce dont vous avez besoin. Testez toujours votre configuration avant de la déployer en production, car une mauvaise règle peut vous couper l'accès SSH !

Récapitulatif des points clés :

  • IPv6 nécessite un firewall car il n'y a pas de NAT
  • La table inet unifie IPv4 et IPv6
  • NDP est obligatoire pour que IPv6 fonctionne
  • Rate limiting et logging sont vos meilleurs alliés
  • Validez votre config avec nft list ruleset et des tests de connectivité avant de rebooter
Besoin d'aide sur ce sujet ?

Notre équipe d'experts est là pour vous accompagner dans vos projets d'infrastructure et d'infogérance.

Contactez-nous

Articles similaires