Contexte

Si vous suivez mes péripéties sur Xwitter, vous savez que je suis en train de migrer le CNI de mon cluster Kubernetes de Calico vers Cilium.

Avec Cilium, je déclare des adresses IP virtuelles dans mon réseau qui ne sont pas associées à un hôte, mais à un service.

L2 Announce

Ainsi, lorsqu’une machine de mon réseau cherche l’adresse 192.168.1.129 dans mon LAN, elle va envoyer une requête ARP pour demander qui possède cette adresse. C’est à ce moment que Cilium va répondre et donner l’adresse MAC de l’hôte qui héberge le service.

➜  ~ arp -an
? (192.168.1.129) at dc:a6:32:ac:11:01 [ether] on wlp2s0
? (192.168.1.204) at dc:a6:32:ac:11:01 [ether] on wlp2s0

Mon noeud cluster possède l’IP 192.168.1.204 mais répond aux requêtes ARP cherchant l’IP 192.168.1.129.

Jusque là tout va bien.

Je met en place un service de type LoadBalancer redirigeant le port 80 et 443 vers Istio. Celui-ci se voit attribuer l’adresse IP 192.168.1.130.

Istio (et donc l’IP 192.168.1.130) est alors un point d’entrée pour accéder à mes services.

Je souhaite alors ouvrir les ports 80 et 443 de ma Livebox pour pouvoir accéder à mes services depuis l’extérieur.

Qu’est-ce qui pourrait mal se passer ?

Et là, c’est le drame !

LiveBox IHM

La Box me demande de sélectionner un appareil pour ouvrir le port.

En quoi est-ce un problème ? me direz-vous. Et bien : l’IP 192.168.1.130 n’est liée à aucun appareil de mon réseau.

cat même

S’en suit alors une série de recherches sur le net pour trouver une solution à mon problème.

L’UPnP

Le but de l’UPnP est de permettre à des périphériques de se connecter aisément et de simplifier la mise en œuvre de réseaux à la maison (partages de fichiers, communications, divertissements) ou dans les entreprises. UPnP le permet en définissant et en publiant les protocoles de commande UPnP au-dessus des standards de communication d’Internet. - Wikipedia

Dans la pratique, l’UPnP peut permettre à un appareil de demander à la Box d’ouvrir un port pour lui. Normalement, c’est un protocole à désactivé pour des raisons de sécurité mais on va dire que c’est pour la bonne cause.

Tailscale utilise l’UPnP pour ouvrir un port sur la Box. Je me suis donc dit que je pouvais faire pareil.

Je télécharge donc un client UPnP (sudo pacman -S miniupnpc) et après une intense recherche dans le man-page, j’écris la commande magique pour un premier test.

➜  ~ upnpc -a 192.168.1.147 4567 1234 TCP
upnpc : miniupnpc library test client, version 2.2.5.
 (c) 2005-2023 Thomas Bernard.
Go to http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
for more information.
List of UPNP devices found on the network :
 desc: http://192.168.1.1:60000/c71aba4/gatedesc1.xml
 st: urn:schemas-upnp-org:device:InternetGatewayDevice:1

Found valid IGD : http://192.168.1.1:60000/c71aba4/upnp/control/WANIPConn1
Local LAN ip address : 192.168.1.147
ExternalIPAddress = redacted
InternalIP:Port = 192.168.1.147:4567
external redacted:1234 TCP is redirected to internal 192.168.1.147:4567 (duration=0)

Je vais sur ma Livebox pour vérifier que le port est bien ouverte … Miracle ! C’est le cas !

UPnP

Plus qu’à faire la même commande sur le port 80 et 443 sur l’IP 192.168.1.130 et le tour est joué !

➜  ~ upnpc  -a 192.168.1.130 80 80 TCP
upnpc : miniupnpc library test client, version 2.2.5.
 (c) 2005-2023 Thomas Bernard.
Go to http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
for more information.
List of UPNP devices found on the network :
 desc: http://192.168.1.1:60000/c71aba4/gatedesc1.xml
 st: urn:schemas-upnp-org:device:InternetGatewayDevice:1

Found valid IGD : http://192.168.1.1:60000/c71aba4/upnp/control/WANIPConn1
Local LAN ip address : 192.168.1.147
ExternalIPAddress = redacted
AddPortMapping(80, 80, 192.168.1.130) failed with code 606 (Action not authorized)

Ah … C’est pas gagné. Il me faut une autre solution.

La solution “Facile” : le proxy

Je me suis dit que je pouvais utiliser un appareil de mon réseau pour ouvrir le port et rediriger le trafic. Littéralement : installer un HAProxy sur une machine de mon réseau.

Mais je n’ai pas envie de maintenir un HAProxy pour rien. Mon lab est volontairement minimaliste et je ne veux pas ajouter de composant inutile.

Je ne peux pas non-plus utiliser mes noeuds Kubernetes car ils sont sur Talos, un OS minimaliste qui ne permet pas d’installer des paquets.

Idem pour une DMZ, je ne veux pas en mettre une en place pour mon petit lab.

Machine virtuelle ponctuelle

Une solution “possible” est d’installer une machine virtuelle pour lui attribuer l’IP 192.168.1.130 et ouvrir les ports 80 et 443 sur cette machine. Une fois que les ports sont ouverts, je stoppe la machine virtuelle et les ports devraient rester ouverts.

J’ai commencé à mettre en place cette solution. J’ai récemment fait un article sur LXC, et je pourrais très-bien créer un conteneur. C’est une solution scriptable et plutôt rapide à mettre en place.

Mais qu’est-ce que c’est Overkill pour un simple port !

Je commence à scripter la création d’un conteneur LXC en réfléchissant à une solution plus simple.

La solution du désespoir

En continuant mon script, Je tente des choses au hasard et je décide d’ouvrir le code source de la page de configuration de la Livebox.

Désespoir

Je… Je vois une balise select listant les appareils de mon réseau, mais également les IPs de ces appareils.

Puis-je réellement choisir l’IP de mon choix en modifiant le code source de la page ? Le backend va-t-il vérifier que l’IP est bien dans la liste ?

Verdict : Je peux choisir l’IP de mon choix.

Victoire ! Je peux enfin ouvrir les ports 80 et 443 de mon IP virtuelle !

Conclusion

Je ne sais pas si je dois être fier ou honteux de cette solution. Mais elle fonctionne et c’est tout ce qui compte, j’en veux quand même un peu à Orange de ne pas avoir prévu ce cas d’usage.

Ce n’est pas la première fois que je dois me battre avec ma Livebox. J’ai déjà eu des problèmes avec le DHCP et le DNS. Peut-être qu’un jour, je remplacerai ma Livebox par une solution plus libre et permisive (Je rêve d’un PFSense à la maison).