Sommaire
Déploiement de l’IPv6 sur Spirio.fr
Introduction
Cela fait des années que l’on entend parler de l’adressage par IPv6 : pour certains, c’est une évolution naturelle, pour d’autres, une transition complexe à éviter. Personnellement, je n’ai jamais eu besoin d’avoir cette compétence au niveau professionnel, je l’ai donc remise à « demain », qui l’a remise à « plus tard », qui l’a remise à « un jour », et qui l’a remise à « jamais ». Des années plus tard, après une longue après-midi pluvieuse en mars, je me suis dit « Allez, c’est maintenant ! ».
Dans cet article, vous allez voir la liste des modifications que j’ai dû effectuer sur l’infrastructure pour rendre spirio.fr et ses services accessible en IPv6. A ma grande surprise, cela s’est avéré simple pour la plupart des services. Seul AdGuardHome a nécessité que je comprenne un peu mieux le fonctionne du protocole IPv6 et de l’implémentation dans Nftables de la gestion de l’IPv6. Bonne lecture 😃
Disclaimer
Je ne suis pas un expert réseau, ni un expert tout cours d’ailleurs. J’ai modifié les différentes configurations pour que la fonctionne, il existe probablement de meilleure façon de faire.
Les grands changements IPv6
N’ayant que peu de connaissance en IPv6, je me suis au début tourné vers un LLM pour m’aider à rédiger cette section. J’ai au final abandonné, car le texte qu’il m’a donné me semblait vide et peu qualitatif. A la place, si vous souhaitez en savoir plus sur ces grands changements, je vous invite consulter ces sites :
- https://www.juniper.net/fr/fr/research-topics/what-is-ipv4-vs-ipv6.html
- https://aws.amazon.com/fr/compare/the-difference-between-ipv4-and-ipv6
que je trouve bien fait, je compte sur vous pour revenir finir de lire l’article. 😆
Activation de l’adressage IPv6 sur le serveur
Première étape, on regarde la connectivité du serveur, et notamment le fait qu’une adresse IPv6 soit rattachée à une interface et que celle-ci réponde au ping.
ip a
2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether
altname enp0s3
inet 37.59.122.154/32 metric 100 scope global dynamic ens3
valid_lft 52261sec preferred_lft 52261sec
inet6 2001:41d0:305:2100::b5fa/128 scope global
valid_lft forever preferred_lft forever
OVH attribue une adresse IP par défaut à tous ces VPS. On peut voir que l’adresse IPv6 attribuée à l’interface publique est 2001:41d0:305:2100::b5fa. Vérifions maintenant si la connectivité depuis l’extérieur est fonctionnelle.
ping 2001:41d0:305:2100::b5fa
PING 2001:41d0:305:2100::b5fa(2001:41d0:305:2100::b5fa) 56 data bytes
64 bytes from 2001:41d0:305:2100::b5fa: icmp_seq=1 ttl=48 time=12.9 ms
64 bytes from 2001:41d0:305:2100::b5fa: icmp_seq=2 ttl=48 time=13.2 ms
Le serveur répond, good ! Petite information utile à savoir, si votre machine ne possède pas d’adresse IPv6, vous ne pourrez pas requêter un serveur en IPv6. Assurez-vous bien d’avoir une interface avec adresse IPv6 routable.
La configuration pare-feu
Initialement, je n’ai pas eu à faire de modification sur le pare-feu Nftables qui est déployé sur le serveur. Les règles présentes dans la section « table inet filter » s’appliquent à la fois pour l’adressage IPv4 et IPv6. Les seules modifications que j’ai dû effectuer concernaient le NAT prerouting et le postrouting pour le DNS AdGuardHome que j’héberge sur le serveur.
Afin que les requêtes DNS arrivent bien au conteneur, j’ai mis en place du NAT sur ports 53 TCP/UDP et TCP:853 vers l’adresse IP du conteneur Podman. Je ne pense pas que cela la bonne façon de faire, mais c’était la plus simple et efficace au vu de l’historique. Dans Nftables, les tables ne peuvent être à la fois en IPv4 et en IPv6. J’ai créé une table spécifique à l’adressage IPv6 afin que les paquets qui arrivent sur les ports 53 TCP/UDP et 853 UDP soient directement nattés vers l’adresse IPv6 du conteneur podman AdGuardHome. Cela nous donne cette configuration à ajouter à Nftables
adguardhome= fd00:10:xx::x
table ip6 nat {
chain prerouting {
type nat hook prerouting priority 0; policy accept;
# AdguardHome DNS IPv6 nat
iifname ens3 ip6 daddr $spirio.frAAAA udp dport 53 dnat $adguardhome:53
iifname ens3 ip6 daddr $spirio.frAAAA tcp dport 53 dnat $adguardhome:53
iifname ens3 ip6 daddr $spirio.frAAAA tcp dport 853 dnat $adguardhome:853
}
chain postrouting {
type nat hook postrouting priority 100; policy accept;
oifname ens3 ip6 saddr $spirio.frAAAA masquerade
}
}
Nftables comprend les adresses IPv6 dans le format standard ainsi qu’entouré de crochet. Je trouve que lorsqu’il est fait mention d’un port pour du NAT par exemple, on gagne en lisibilité à les mettre. Ce qui donne par exemple, fd00:10:xx::x:53 qui devient [fd00:10:xx::x]:53.
Le reverse Proxy HTTPD
Les modifications ne sont pas nécessaires, Apache HTTPD avec la configuration par défaut sous Debian, écoute en IPv4 et IPv6 ainsi que les VirtualHosts. Merci à la personne pour son commentaire !
On va maintenant regarder du côté du reverse proxy. De base, celui-ci n’écoute qu’en IPv4. Comme on souhaite maintenir la connectivité IPv4, on va lui demander de gérer à la fois le protocole IPv4 et IPv6. J’utilise HTTPD de la fondation Apache. Je l’utilise plus par habitude qu’autre chose, à choisir, je m’orienterai plus vers Nginx car il semble plus performant aujourd’hui. Pour ce qui est en capacité à écouter à IPv6, Apache HTTPD permet en modifiant le VirtualHost d’écouter à la fois en IPv4 et en IPv6. Voici les modifications à effectuer.
<VirtualHost *:80>
# Devient
<VirtualHost *:80 [::]:80>
<VirtualHost *:443>
# Devient
<VirtualHost *:443 [::]:443>
# Redémarrage du serveur
sudo systemctl restart apache2
Vérifions que le logiciel HTTPD écoute bien en IPv6.
ss -6plantu|grep apache2
tcp LISTEN 0 511 *:443 *:* users:(("apache2",pid=365186,fd=6),("apache2",pid=365185,fd=6),("apache2",pid=365128,fd=6),("apache2",pid=354280,fd=6))
tcp LISTEN 0 511 *:80 *:* users:(("apache2",pid=365186,fd=4),("apache2",pid=365185,fd=4),("apache2",pid=365128,fd=4),("apache2",pid=354280,fd=4))
Apache HTTPD opère en tant que reverse proxy et redirige les requêtes IPv4 et IPv6 vers des conteneurs Podman qui tournent en IPv4. La question qui se pose désormais est de savoir si Apache HTTPD est capable de convertir une requêtes en IPv6 vers un conteneur en IPv4. La réponse est oui ! 🥳 Cela signifie la quasi-totalité des services proposés par spirio.fr fonctionnent en IPv6 désormais. Ils fonctionnent, oui, mais l’adresse IPv6 qui leur est attribuée est-elle annoncée ?
La modification des enregistrements DNS
Spirio.fr et ses services étaient jusqu’alors annoncés uniquement en IPv4. Concrétement, cela signifie que le serveur DNS ne répondait que pour les requêtes DNS de type A. Afin qu’ils soient accessibles en IPv6, il est nécessaire d’ajouter une entrée DNS de type AAAA au domaine et sous-domaines afin que lorsqu’une requête DNS de type AAAA les concernent, l’adresse IPv6 du serveur soit retourné.
Afin de simplifier la gestion des adresses IP, j’utilise un enregistrement de type CNAME. Cela permet de n’avoir à spécifier l’adresse IP qu’une seule fois et d’avoir des liens symboliques vers ce seul enregistrement, ici l’enregistrement server. Factuellement, les requêtes DNS de tous les types d’enregistrements DNS sont transmises à l’adresse IP du CNAME.
# Enregistrements déjà présents
server 3600 IN A 37.59.122.154
dns 60 IN CNAME server.spirio.fr.
geoquest 3600 IN CNAME server.spirio.fr.
it-tools 3600 IN CNAME server.spirio.fr.
omnitools 3600 IN CNAME server.spirio.fr.
pdf 3600 IN CNAME server.spirio.fr.
# Enregistrement ajoutés pour permettre le fonctionnement en IPv6
3600 IN AAAA 2001:41d0:305:2100::b5fa
server 3600 IN AAAA 2001:41d0:305:2100::b5fa
Une fois l’enregistrement des modifications réalisées et les enregistrements DNS propagés à la plupart des résolveurs publiques, les requêtes DNS de type AAAA pour spirio.fr et ses services répondront l’adresse IPv6 spécifier. Vérifions en requêtant le résolveur 9.9.9.9 de Quad9.
dig +short @9.9.9.9 spirio.fr AAAA dns.spirio.fr AAAA geoquest.spirio.fr AAAA it-tools.spirio.fr AAAA pdf.spirio.fr AAAA
2001:41d0:305:2100::b5fa
server.spirio.fr.
2001:41d0:305:2100::b5fa
server.spirio.fr.
2001:41d0:305:2100::b5fa
server.spirio.fr.
2001:41d0:305:2100::b5fa
server.spirio.fr.
2001:41d0:305:2100::b5fa
On récupère bien l’adresse en IPv6 ainsi que le CNAME pour les sous-domaines. Cela fonctionne. 👍
AdGuardHome
Contrairement aux autres services hébergés sur https://spirio.fr, les requêtes IPv6 DNS TCP:53/UDP:53 et UDP:853 sont nattés directement vers le conteneur AdGuardHome. Cela nécessite que le conteneur ait une adresse IPv6 et écoute sur les ports TCP:53/UDP:53 et TCP:853.
Podman
Le déploiement des Podman se base sur des fichiers de configuration Quadlet. Chaque conteneur a un réseau qui lui est propre et qui l’isole des autres conteneurs. En IPv4, il existe différentes plages réseaux non-adressables sur internet.
| RFC 1918 name | IP address range | Number of addresses | Largest CIDR block (subnet mask) | Host ID size | Mask bits | Classful descriptionNote 1(https://en.wikipedia.org/wiki/Private_network#cite_note-3) |
|---|---|---|---|---|---|---|
| 24-bit block | 10.0.0.0 – 10.255.255.255 | 16777216 | 10.0.0.0/8 (255.0.0.0) | 24 bits | 8 bits | single class A network |
| 20-bit block | 172.16.0.0 – 172.31.255.255 | 1048576 | 172.16.0.0/12 (255.240.0.0) | 20 bits | 12 bits | 16 contiguous class B networks |
| 16-bit block | 192.168.0.0 – 192.168.255.255 | 65536 | 192.168.0.0/16 (255.255.0.0) | 16 bits | 16 bits | 256 contiguous class C networks |
source Wikipedia Il existe la même chose en IPv6.
| RFC 4193 Block | Prefix/L | Global ID (random) | Subnet ID | Number of addresses in subnet |
|---|---|---|---|---|
| 48 bits | 16 bits | 64 bits | ||
| fd00::/8 | fd | xx:xxxx:xxxx | yyyy | 18446744073709551616 |
source Wikipedia Ce qui donnera par exemple comme adresse de réseau : fd00:10:0::/64 et comme adresse IPv6 pour le conteneur : fd00:10:0::2/64.
Modifions maintenant le fichier .network afin d’activer l’adressage IPv6 et lui attribuer l’adresse réseau IPv6.
[Unit]
Description=Adguardhome Container Network
[Network]
Subnet=10.80.00.1/24
DisableDNS=true
IPv6=true
Subnet=fd00:10:80::/64
[Install]
WantedBy=default.target
Modifions maintenant le fichier .container afin d’activer l’adressage IPv6 et lui attribuer l’adresse réseau IPv6.
# adguardhome.container
...
[Container]
IP6=fd00:10:80::2
...
Il ne reste plus qu’à recharger la configuration, redémarrer le conteneur et vérifier qu’il dispose bien d’une interface IPv6.
sudo systemctl daemon-reload
sudo systemctl restart adguardhome
podman inspect adguardhome|grep GlobalIPv6Address
"GlobalIPv6Address": "",
"GlobalIPv6Address": "fd00:10:80::2",
podman network inspect systemd-adguardhome|grep ipnet
"ipnet": "10.80.0.1/24",
"ipnet": "fd00:10:80::1/64",
Configuration d’AdGuardHome
Initialement, j’avais configuré AdGuardHome afin qu’il écoute sur l’interface du conteneur, à savoir 10.80.0.2. AdGuardHome peut écouter sur plusieurs interface, la documentation l’explique très bien. Initialement, je l’avais configuré pour écouter spécifiquement sur l’interface avec l’adresse IP du conteneur. Au lieu d’ajouter l’interface IPv6, ce qui fonctionne, j’ai préféré mettre l’adresse 0.0.0.0 qui permet d’écouter sur toutes les interfaces. Cela simplifie la configuration et la rend plus résiliente aux changements d’adresses IP du conteneur. Ce qui nous donne :
# AdGuardHome.yaml
bind_hosts:
- 10.80.0.2
# Devient
bind_hosts:
- 0.0.0.0
On redémarre le conteneur AdGuardHome puis on regarde si le conteneur écoute bien sur les deux interfaces en IPv4 et en IPv6.
sudo systemctl restart adguardhome
# IPv4
nmap 10.80.0.2 -p 53,443,853
PORT STATE SERVICE
53/tcp open
443/tcp open https
853/tcp open domain-s
nmap 10.80.0.2 -p U:53
53/udp open domain
# IPv6
nmap -6 fd00:10:80::1 -p 53,443,853
PORT STATE SERVICE
53/tcp open
443/tcp open https
853/tcp open domain-s
nmap -sU -6 fd00:10:80::1 -p 53
53/tcp open
Vérifications de la résolution DNS
On va maintenant vérifier que le résolveur DNS fonctionne et répond aux requêtes DNS en TCP/UDP/DOH/DOT.
# Résolution DNS en UDP:53 en IPv6
dig -6 +short @2001:41d0:305:2100::b5fa google.fr A
172.217.22.35
# Résolution DNS en TCP:53 en IPv6
dig -6 +short +tcp @2001:41d0:305:2100::b5fa google.fr A
172.217.22.35
# Résolution DNS en DOH TCP:443 en IPv6
kdig +short @2001:41d0:305:2100::b5fa +tls-ca +tls-host=dns.spirio.fr google.fr
172.217.22.35
# Résolution DNS en DOT TCP:853 en IPv6
dig -6 +short +tls @2001:41d0:305:2100::b5fa google.fr A
172.217.22.35
Cela fonctionne. 🥳
Conclusion
Les services accessibles sur https://spirio.fr répondent désormais aux requêtes en IPv6 ! Il existe surement d’autres actions à réaliser afin que tout soit conforme, mais comme le mieux est l’ennemi du bien, je pense m’arrêter là pour le moment. Fait rigolo, j’ai passé plus de temps à rédiger cet article qu’à mettre en place l’adressage en IPv6. J’espère que cet article vous aura plu. Au plaisir de lire vos commentaires.
Spirio
Répondre à Anonyme Annuler la réponse