5. Traduction d'adresses destination sur le routeur Hub

Dans cette partie, on doit compléter les règles de filtrage sur le routeur Hub en appliquant la même politique que sur les routeurs Spoke pour les flux traversants : tout ce qui n'est pas autorisé est interdit. En complément à cette politique par défaut, on doit aussi répondre à deux objectifs :

  • Autoriser le trafic provenant des routeurs Spoke vers l'Internet.

  • Autoriser l'accès aux services Web hébergés sur les conteneurs des réseaux d'hébergement des sites distants à l'aide de la traduction des adresses destination.

    Voici un exemple de correspondances de numéros de ports pour l'accès aux différents services web.

    Tableau 1. Correspondance entre numéro de port et service Web

    numéros de port Hub : http,https conteneur
    8010,8453 10.0.10.10
    fda0:7a62:a::a
    8011,8454 10.0.10.11
    fda0:7a62:a::b
    8012,8455 10.0.10.12
    fda0:7a62:a::c
    8020,8463 10.0.20.10
    fda0:7a62:14::a
    8021,8464 10.0.20.11
    fda0:7a62:14::b
    8022,8465 10.0.20.12
    fda0:7a62:14::c

Avant d'aborder les questions, on commence par afficher l'état courant du jeu de règles de filtrage sur le routeur Hub.

#!/usr/sbin/nft -f

flush ruleset

# Outbound interface
define RED_VLAN = enp0s1.360

table inet nat {
    chain postrouting {
        type nat hook postrouting priority 100;
        oifname $RED_VLAN counter masquerade
    }
}

table inet raw {
    chain rpfilter {
        type filter hook prerouting priority raw; policy accept;
        iifname $RED_VLAN fib saddr . iif oif 0 counter packets 0 bytes 0 drop
    }

    # ICMP Rate Limiting Rules
    chain icmpfilter {
        type filter hook prerouting priority raw; policy accept;
        icmp type echo-request limit rate 10/second burst 5 packets counter accept
        icmp type echo-request counter drop
    }
}

table inet filter {

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

        # Allow outbound new connections
        iifname "ppp*" ct state new counter accept

        # Allow established and related connections
        ct state established,related counter accept

        # Count dropped packets
        counter comment "count dropped packets"
    }
}

Q36.

Comment appliquer la politique par défaut, autoriser et enregistrer dans le mécanisme de suivi des états les flux traversants depuis les routeurs Spoke ?

Reprendre le jeu de règles de la Section 4, « Filtrage des flux réseaux traversant les routeurs Spoke » et adapter ce jeu au contexte du routeur Hub.

Il faut notamment choisir sur quelle(s) interface(s) la règle doit s'appliquer pour ne pas bloquer les flux entre routeurs Spoke.

Voici un exemple de règles basées sur l'utilisation des interfaces de raccordement des routeurs Spoke.

table inet filter {
    chain forward {
        type filter hook forward priority filter; policy drop;
        iifname "ppp*" ct state new counter packets 6 bytes 504 accept
        ct state established,related counter packets 18 bytes 1512 accept
        counter packets 0 bytes 0 comment "count dropped packets"
    }
}

Dans ce cas de figure le trafic entrant par les interfaces PPP est autorisé à traverser le routeur Hub.

Q37.

Comment valider l'utilisation de ces nouvelles règles à partir d'un routeur Spoke ?

Il suffit de lancer une mise à jour de catalogue de paquets dans les conteneurs hébergés sur un routeur Spoke.

On peut aussi utiliser la commande conntrack pour afficher la liste des enregistrements en cours sur le routeur Hub pendant les transactions des conteneurs.

Voici un exemple de trace qui montre que les flux initiés par les conteneurs sont correctement acheminés par le routeur Hub.

  • Côté routeur Spoke, on initie le trafic.

    for i in {0..2}
    do
        echo ">>>>>>>>>>>>>>>>> c$i"
        incus exec c$i -- apt update
    done
  • Côté routeur Hub, on relève “rapidement” la liste des enregistrements relatif à une adresse de conteneur.

    sudo conntrack -L -j 10.0.10.1
    tcp      6 36 TIME_WAIT src=10.0.10.10 dst=151.101.2.132 sport=39664 dport=80
        src=151.101.2.132 dst=192.168.104.130 sport=80 dport=39664 [ASSURED] mark=0 use=1

Q38.

Comment implanter les règles de traduction d'adresses IPv4 et IPv6 destination pour ouvrir l'accès aux services Web placés dans les conteneurs des réseaux d'hébergement des routeurs Spoke ?

Rechercher la chaîne présente par défaut à utiliser pour les traitements de traduction d'adresses et de ports destination dans la représentation graphique Packet Flow in Netfilter.

Une fois la chaîne identifiée, rechercher des exemples de règles de filtrage de type dnat et une adaptation au critères de redirection de ports définis dans le tableau ci-dessus.

Bien sûr, les adresses IPv4 et IPv6 des conteneurs hébergés sur les routeur Spoke doivent être modifiées en fonction du plan d'adressage du document Topologie Hub & Spoke avec le protocole PPPoE.

Le nom de chaîne recherchée est prerouting. En effet, la traduction d'adresse destination doit se faire avant la décision de routage des paquets IPv4 ou IPv6.

Voici un extrait du fichier /etc/nftables.conf qui ne comprend que les règles définies dans la table nat.

table inet nat {
    chain postrouting {
        type nat hook postrouting priority 100;
        oifname $RED_VLAN counter masquerade
    }

    chain prerouting {
        type nat hook prerouting priority dstnat; policy accept;
        # Spoke1
        iifname $RED_VLAN meta l4proto { tcp, udp } th dport { 8010, 8453 } \
            dnat ip to 10.0.10.10
        iifname $RED_VLAN meta l4proto { tcp, udp } th dport { 8010, 8453 } \
            dnat ip6 to fda0:7a62:a::a
        iifname $RED_VLAN meta l4proto { tcp, udp } th dport { 8011, 8454 } \
            dnat ip to 10.0.10.11
        iifname $RED_VLAN meta l4proto { tcp, udp } th dport { 8011, 8454 } \
            dnat ip6 to fda0:7a62:a::b
        iifname $RED_VLAN meta l4proto { tcp, udp } th dport { 8012, 8455 } \
            dnat ip to 10.0.10.12
        iifname $RED_VLAN meta l4proto { tcp, udp } th dport { 8012, 8455 } \
            dnat ip6 to fda0:7a62:a::c
        # Spoke2
        iifname $RED_VLAN meta l4proto { tcp, udp } th dport { 8020, 8463 } \
            dnat ip to 10.0.20.10
        iifname $RED_VLAN meta l4proto { tcp, udp } th dport { 8020, 8463 } \
            dnat ip6 to fda0:7a62:14::a
        iifname $RED_VLAN meta l4proto { tcp, udp } th dport { 8021, 8464 } \
            dnat ip to 10.0.20.11
        iifname $RED_VLAN meta l4proto { tcp, udp } th dport { 8021, 8464 } \
            dnat ip6 to fda0:7a62:14::b
        iifname $RED_VLAN meta l4proto { tcp, udp } th dport { 8022, 8465 } \
            dnat ip to 10.0.20.12
        iifname $RED_VLAN meta l4proto { tcp, udp } th dport { 8022, 8465 } \
            dnat ip6 to fda0:7a62:14::c
    }
}

Relativement à l'unique règle de la chaîne postrouting, il est nécessaire d'ajouter deux règles par destination en distinguant les protocoles IPv4 et IPv6. Dans le contexte de la maquette, il y a trois conteneurs hébergés sur chaque routeur Spoke. On doit donc ajouter 6 règles pour chacun d'eux.

Les règles de traduction d'adresses de la chaîne prerouting sont structurées de la façon suivante :

  • Une même règle traite les protocoles de couche transport TCP et UDP.

  • Les numéros de ports sont aussi regroupés. Par exemple : { 8010, 8453 }.

  • Relativement aux règles des autres parties du document, les protocoles IPv4 et IPv6 sont séparés et les adresses destination sont explicitement définies pour chaque routeur Spoke.

Q39.

Comment tester le ces nouvelles règles de traduction d'adresse destination sur le routeur Hub ?

Comme il s'agit de flux réseau entrants sur le routeur Hub, il faut nécessairement lancer les tests depuis le réseau d'infrastructure, c'est-à-dire le VLAN rouge.

La connexion au Shell de l'hyperviseur nous permet de lancer nos tests à destination de l'adresse du routeur Hub dans le réseau d'infrastructure, c'est-à-dire le VLAN rouge. Voici un exemple avec l'adresse définie dans le plan d'adressage de la maquette utilisée pour ce document.

wget http://192.168.104.130:8010
--2024-10-13 15:47:25--  http://192.168.104.130:8010/
Connexion à 192.168.104.130:8010…

Si l'adresse IPv4 et le numéro de port utilisés pour ce test sont corrects, cela ne suffit toutefois pas.

Q40.

Comment autoriser les flux de la traduction d'adresse destination à traverser le routeur Hub ?

Rechercher à nouveau le nom de la chaîne présente par défaut qui traite les flux réseau qui traversent le routeur Hub.

Une fois la chaîner identifiée, rechercher la syntaxe des règles qui admettent les premiers paquets de traitement de la traduction d'adresse destination dans le mécanisme de suivi des communications du système de filtrage.

C'est la chaîne forward qui nous intéresse ici. On a déjà créé des règles dans cette chaîne qui traitent les flux sortants du routeur Hub provenant des routeurs Spoke.

Voici un exemple de jeu de règles pour la chaîne forward adapté au plan d'adressage de la maquette.

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

        # Allow outbound new connections
        iifname "ppp*" ct state new counter accept

        # Allow inbound new connections to the web services hosted on spoke routers
        # Spoke1
        iifname $RED_VLAN ip daddr 10.0.10.10 meta l4proto { tcp, udp } \
            th dport { 8010, 8453 } ct state new counter accept
        iifname $RED_VLAN ip6 daddr fda0:7a62:a::a meta l4proto { tcp, udp } \
            th dport { 8010, 8453 } ct state new counter accept
        iifname $RED_VLAN ip daddr 10.0.10.11 meta l4proto { tcp, udp } \
            th dport { 8011, 8454 } ct state new counter accept
        iifname $RED_VLAN ip6 daddr fda0:7a62:a::b meta l4proto { tcp, udp } \
            th dport { 8011, 8454 } ct state new counter accept
        iifname $RED_VLAN ip daddr 10.0.10.12 meta l4proto { tcp, udp } \
            th dport { 8012, 8455 } ct state new counter accept
        iifname $RED_VLAN ip6 daddr fda0:7a62:a::c meta l4proto { tcp, udp } \
            th dport { 8012, 8455 } ct state new counter accept
        # Spoke2
        iifname $RED_VLAN ip daddr 10.0.20.10 meta l4proto { tcp, udp } \
            th dport { 8020, 8463 } ct state new counter accept
        iifname $RED_VLAN ip6 daddr fda0:7a62:14::a meta l4proto { tcp, udp } \
            th dport { 8020, 8463 } ct state new counter accept
        iifname $RED_VLAN ip daddr 10.0.20.11 meta l4proto { tcp, udp } \
            th dport { 8021, 8464 } ct state new counter accept
        iifname $RED_VLAN ip6 daddr fda0:7a62:14::b meta l4proto { tcp, udp } \
            th dport { 8021, 8464 } ct state new counter accept
        iifname $RED_VLAN ip daddr 10.0.20.12 meta l4proto { tcp, udp } \
            th dport { 8022, 8465 } ct state new counter accept
        iifname $RED_VLAN ip6 daddr fda0:7a62:14::c meta l4proto { tcp, udp } \
            th dport { 8022, 8465 } ct state new counter accept

        # Allow established and related connections
        ct state established,related counter accept

        # Count dropped packets
        counter comment "count dropped packets"
    }
}

Comme dans le cas de la chaîne prerouting, il est nécessaire de décrire le plus finement possible le premier flux autorisé à entrer dans le mécanisme de suivi des communication. Cela engendre un nombre important de règles même si on parvient à regrouper les deux protocoles de la couches transport et les numéros de ports.

Une fois ce jeu de règles implanté, ce n'est toujours pas suffisant pour accéder aux site web de chaque conteneur du réseau d'hébergement. On peut tout de même qualifier les règles à l'aide des compteurs et de l'affichage des enregistrements du suivi des communications. Voici un exemple.

On commence par lancer une requête qui ne parvient pas à charger la page web du service nginx.

wget http://192.168.104.130:8010
--2024-10-13 18:34:00--  http://192.168.104.130:8010/
Connexion à 192.168.104.130:8010… échec : Connexion terminée par expiration du délai d'attente.

Côté routeur Hub, on peut examiner les compteurs relatifs à la règle qui autorise l'accès au service Web du conteneur à l'adresse IPv4 10.0.10.10.

sudo nft list table inet filter | grep '10.0.10.10'
    iifname "enp0s1.360" ip daddr 10.0.10.10 meta l4proto { tcp, udp } th dport { 8010, 8453 }
        ct state new counter packets 22 bytes 1320 accept

L'affichage de la liste des enregistrements de suivi des communication au niveau du routeur Hub montre qu'aucune réponse à la requête n'a été vue avec la clé UNREPLIED.

 sudo conntrack -f ipv4 -L | grep "10.0.10.10"
conntrack v1.4.8 (conntrack-tools): 2 flow entries have been shown.
tcp      6 87 SYN_SENT src=172.16.0.6 dst=192.168.104.130 sport=48430 dport=8010
    [UNREPLIED] src=10.0.10.10 dst=172.16.0.6 sport=8010 dport=48430 mark=0 use=1

Q41.

Comment reconfigurer les services Web des conteneurs pour qu'ils soient en écoute sur les numéros de ports définis dans les règles de filtrage ci-dessus ?

On sait depuis l'installation des services nginx qu'ils sont tous en écoute sur le port 80. On doit donc reconfigurer ces mêmes services avec les numéros de ports définis dans le tableau donné au début de cette partie.

[Attention] Attention

Pour les besoins de nos tests, on se contente du protocole HTTP et on ne traite pas les ports HTTPS.

On doit réaliser deux tâches sur chaque routeur Spoke.

  • Définir le numéro de port en écoute pour chaque service nginx sur chaque conteneur.

  • Compléter la liste des ports autorisés dans les règles de filtrage Web.

Voici un exemple des traitements à réaliser sur le routeur Spoke1.

Pour reconfigurer les services Web, on lance un script avec comme celui-ci.

for i in {0..2}
do
    echo ">>>>>>>>>>>>>>>>> c$i"
    incus exec c$i -- \
        sh -c "sed -i 's/listen 80/listen $((8010 + i))/' /etc/nginx/sites-enabled/default"
    incus exec c$i -- \
        sh -c "sed -i 's/listen \[::\]:80/listen \[::\]:$(( 8010 + i))/' /etc/nginx/sites-enabled/default"
    incus exec c$i -- systemctl restart nginx
done

Pour la liste des ports autorisés, on complète la ligne des services Web de la chaîne forward de la table filter. Voici une copie de la table.

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

        # Allow outbound new connections
        oifname "ppp0" ct state new counter accept

        # Allow established and related connections
        ct state established,related counter accept

        # Allow specific inbound traffic
        # ICMP IPv4 + IPv6
        iifname "ppp0" meta l4proto {icmp, ipv6-icmp} ct state new counter accept
        # SSH
        iifname "ppp0" tcp dport 2222 ct state new counter accept
        # HTTP(S)
        iifname "ppp0" meta l4proto {tcp, udp} th dport \
            {80, 443, 8010, 8011, 8012, 8453, 8454, 8455} ct state new counter accept

        # Count dropped packets
        counter comment "count dropped packets"
    }
}

Pour terminer, les tests d'accès depuis l'hyperviseur sont maintenant concluants pour les protocoles IPv4 et IPv6.

for p in {0..2}
do
    wget -O /dev/null http://192.168.104.130:$((8010 + $p))
done
--2024-10-13 19:24:24--  http://192.168.104.130:8010/
Connexion à 192.168.104.130:8010… connecté.
requête HTTP transmise, en attente de la réponse… 200 OK
Taille : 615 [text/html]
Sauvegarde en : « /dev/null »

/dev/null  100%[===============================================>]     615  --.-KB/s    ds 0s

2024-10-13 19:24:24 (33,6 MB/s) — « /dev/null » sauvegardé [615/615]

--2024-10-13 19:24:24--  http://192.168.104.130:8011/
Connexion à 192.168.104.130:8011… connecté.
requête HTTP transmise, en attente de la réponse… 200 OK
Taille : 615 [text/html]
Sauvegarde en : « /dev/null »

/dev/null  100%[================================================>]     615  --.-KB/s    ds 0s

2024-10-13 19:24:24 (34,4 MB/s) — « /dev/null » sauvegardé [615/615]

--2024-10-13 19:24:24--  http://192.168.104.130:8012/
Connexion à 192.168.104.130:8012… connecté.
requête HTTP transmise, en attente de la réponse… 200 OK
Taille : 615 [text/html]
Sauvegarde en : « /dev/null »

/dev/null  100%[================================================>]     615  --.-KB/s    ds 0s

2024-10-13 19:24:24 (36,3 MB/s) — « /dev/null » sauvegardé [615/615]
for p in {0..2}
do
    wget -O /dev/null http://[2001:678:3fc:168::82]:$((8010 + $p))
done
--2024-10-13 19:50:30--  http://[2001:678:3fc:168::82]:8010/
Connexion à [2001:678:3fc:168::82]:8010… connecté.
requête HTTP transmise, en attente de la réponse… 200 OK
Taille : 615 [text/html]
Sauvegarde en : « /dev/null »

/dev/null  100%[================================================>]     615  --.-KB/s    ds 0s

2024-10-13 19:50:30 (33,5 MB/s) — « /dev/null » sauvegardé [615/615]

--2024-10-13 19:50:30--  http://[2001:678:3fc:168::82]:8011/
Connexion à [2001:678:3fc:168::82]:8011… connecté.
requête HTTP transmise, en attente de la réponse… 200 OK
Taille : 615 [text/html]
Sauvegarde en : « /dev/null »

/dev/null  100%[=================================================>]     615  --.-KB/s    ds 0s

2024-10-13 19:50:30 (39,0 MB/s) — « /dev/null » sauvegardé [615/615]

--2024-10-13 19:50:30--  http://[2001:678:3fc:168::82]:8012/
Connexion à [2001:678:3fc:168::82]:8012… connecté.
requête HTTP transmise, en attente de la réponse… 200 OK
Taille : 615 [text/html]
Sauvegarde en : « /dev/null »

/dev/null 100%[==================================================>]     615  --.-KB/s    ds 0s

2024-10-13 19:50:30 (42,4 MB/s) — « /dev/null » sauvegardé [615/615]

C'est gagné ! La traduction d'adresse destination au niveau du routeur Hub est validée.