Horoa – La voie est libreLa voie est libre

Load balancing your FTP service

L’équilibrage de charge d’un protocole réseau est quelque chose de tout à fait courant de nos jours. Il y a beaucoup de façons de faire ça, notamment pour HTTP, et de façon général, pour tous les protocoles « mono-flux ».
Cependant, certains protocoles ne sont pas aussi simples que HTTP et nécessitent plusieurs connexions. C’est exactement le cas du protocole FTP.

Rappel: les modes FTP

Regardons d’un peu plus prêt le protocole FTP, afin de mieux comprendre comment nous pouvons en équilibrer la charge.
Pour qu’un client FTP fonctionne correctement, deux connexions doivent être ouvertes entre le client et le serveur:

  • Une connexion de contrôle
  • Une connexion de données

La connexion de contrôle est initiée par le client FTP sur le port TCP 21 sur le serveur. La connexion de données quant à elle peut être créée de différentes façons.

La première façon est via une session FTP « active ». Dans ce mode, le client envoie une commande « PORT » qui ouvre aléatoirement un de ses ports réseau et demande au serveur de se connecter à ce dernier en utilisant son port TCP 20 en tant que port source.
Ce mode est habituellement délaissé, voire même la configuration du serveur empêche son utilisation pour des raisons de sécurité (le serveur initiant la connexion de données au client).

Le deuxième mode FTP est le mode « passif ». Lors de l’utilisation du mode passif, un client envoie une commande « PASV » au serveur. En réponse, le serveur ouvre un port TCP et envoie le numéro de port et l’adresse IP dans la réponse PASV pour que le client sache quel socket utiliser. Les clients FTP modernes utilisent généralement ce mode en priorité s’il est pris en charge par le serveur.

Il existe un troisième mode qui est le mode «passif étendu». Il est très similaire au mode « passif » mais le client envoie une commande « EPSV » (au lieu de « PASV ») et le serveur répond avec le numéro du port TCP qui a été choisi pour la connexion de données uniquement (sans envoyer l’adresse IP adresse).

Concepts d’équilibrage de charge FTP & mise en oeuvre pratique

Donc, maintenant que nous savons comment FTP fonctionne, nous savons aussi que le FTP exige d’équilibrer les connexions de contrôle et les connexions de données . L’équilibreur de charge doit également s’assurer que les connexions de données sont envoyées au bon serveur de backend, soit celui qui a répondu à la commande client.

Equilibrage de charge FTP avec LVS / Keepalived

Keepalived est un système d’équilibrage de charge basé sur Linux. Il wrap la pile logicielle IPVS (également appelée LVS) du projet Linux-HA et offre des fonctionnalités supplémentaires telles que la surveillance de backend et la redondance VRRP.
Le schéma ci-dessous montre comment Keepalived procède avec l’équilibrage de charge FTP.

Il track la connexion de contrôle sur le port 21 et gère dynamiquement les connexions de données en utilisant un module de noyau Linux appelé « ip_vs_ftp ». Ce dernier inspecte la connexion de contrôle afin d’être au courant du port qui sera utilisé pour ouvrir le connexion de données .
Les étapes de configuration sont assez simples. Ci-dessous est un exemple pour un système Debian-like:

Installez d’abord le logiciel:
sudo apt-get install keepalived

Ensuite, créez un fichier de configuration à l’aide de l’exemple:
sudo cp /usr/share/doc/keepalived/samples/keepalived.conf.sample /etc/keepalived/keepalived.conf

Modifiez le fichier nouvellement créé afin d’ajouter un nouveau serveur virtuel et les serveurs backend associés:

virtual_server 192.168.0.39 21 {
delay_loop 6
lb_algo rr
lb_kind NAT
protocol TCP
real_server 10.1.2.101 21 {
weight 1
TCP_CHECK {
connect_port 21
connect_timeout 3
}
}
real_server 10.1.2.102 21 {
weight 1
TCP_CHECK {
connect_port 21
connect_timeout 3
}
}
}

L’exemple ci-dessus définit un serveur virtuel qui écoute sur le socket 192.168.0.39:21 . Les connexions envoyées à ce socket sont redirigées vers les serveurs backend en utilisant l’algorithme round-robin et après avoir « masqueradé » l’adresse IP source.
En outre, nous devons charger le helper FTP afin de suivre les connexions de données FTP:
echo 'ip_vs_ftp' >> / etc / modules

Il est important de noter que cette configuration tire parti d’un module du noyau qui lit le contenu des trames FTP. Cela signifie qu’elle ne fonctionne pas lorsque le protocole FTP est sécurisé en utilisant SSL / TLS

Cas du FTP/TLS

Lorsque la session FTP est chiffrée (de bout en bout il s’entend) il n’est pas possible pour un proxy ou un load balancer de tracker la session afin d’anticiper les ouvertures de ports pour le canal d’échange de données.
Il est donc préférable dans ce cas de réserver des ensembles de ports pour chacun des serveurs de backend. Cette technique est plus contraignante mais permet de contourner la problématique imposée par le chiffrement.

Fondamentalement, nous allons diviser l’équilibrage de charge en plusieurs parties:

  • contrôle de connexion équilibrage de charge
  • l’équilibrage des connexions de données pour chacun des serveurs de backend

Donc, si nous avons 2 serveurs de backend – comme le montre le schéma ci-dessous – nous allons créer 3 pools de connexion d’équilibrage de charge (appelons-le comme ça pour l’instant).

Pré-requis
  • Le serveur FTP doit donc permettre de spécifier les ports à utiliser pour le mode passif.
    Par exemple, ProFTPd utilise les paramètres de configuration ci-dessous: PassivePorts 20010 20020

    Evidemment nous devrons voir un paramétrage différent sur les autres serveurs, avec des plages de ports qui ne se chevauchent pas.

  • Il est important de noter que si vous utiliser un système de NAT devant votre serveur FTP, celui doit alors permettre de spécifier l’adresse IP externe. Par exemple, ProfTPd utilise le paramètre de configuration ci-dessous:MasqueradeAddress 192.168.0.39

Si vous avez du NAT en place mais que votre serveur FTP ne permet pas de spécifier l’adresse IP renvoyée dans une réponse PASV, alors vous pouvez toujours essayer de forcer votre client FTP à utiliser EPSV au lieu de PASV, même si la connexion est en IPv4. Malheureusement la plupart des clients ne le permettent pas.

En effet la réponse à la commande PASV retourne à la fois un port mais aussi une adresse IP. Si votre server FTP ne connais pas l’IP utilisez par le client pour se connecter au serveur et que le load-balancer ne peut pas assurer cette translation d’adresse dans la réponse (car le flux est chiffré) alors la commande risque d’échouer. Lorsque cela se produit le client peut s’authentifier sur le serveur mais il ne peut pas lister le contenu des répertoires.
La commande EPSV en revanche ne retourne qu’un numéro de port et le client doit ré-utiliser l’IP qui,sert à établir la connexion au serveur quelque soit l’IP réelle du serveur.

Equilibrage de charge FTP/TLS avec Keepalived

Cette méthode, pour peu qu’elle respecte les pré-requis énonces plus haut devrait fonctionner avec FTPs (SSL wrapper) & FTP/TLS

Il n’est pas possible avec IPVS de spécifier un ensemble de port dans la configuration de l’outil, à moins bien sûr de créer un « virtual_server » pour chaque port ce qui serait fastidieux (un peu comme les moutons – n’hésitez pas à commenter si vous avez trouvé la référence 😉 ) et particulièrement inefficace. En revanche il est possible d’utiliser une fonctionnalité géniale d’iptables: le packets mangling (ou marquage de paquets). On va ici demander au noyau Linux de marquer les paquets relatifs à la connexion FTP/TLS (à partir des numéros de ports) et de leur appliquer une marque. On pourra alors référencer cette marque dans la configuration au lieu de référencer un socket ou un ensemble de sockets.

On doit donc tout d’abord créer les règles de marquages. Dans notre example nous aurions donc:

sudo iptables -t mangle -A PREROUTING -p tcp --sport 1024: --dport 20000:20009 -j MARK --set-mark 0x1
sudo iptables -t mangle -A PREROUTING -p tcp --sport 1024: --dport 20010:20019 -j MARK --set-mark 0x2

On ajoute ensuite les directives suivantes à la configuration précédentes dans /etc/keepalived/keepalived.conf:


virtual_server fwmark 1 {
delay_loop 6
lb_algo rr
lb_kind NAT
protocol TCP

real_server 10.1.2.101 {
TCP_CHECK {
connect_port 21
connect_timeout 3
}
}
}

virtual_server fwmark 2 {
delay_loop 6
lb_algo rr
lb_kind NAT
protocol TCP

real_server 10.1.2.102 {
TCP_CHECK {
connect_port 21
connect_timeout 3
}
}
}

Equilibrage de charge FTP/TLS avec HAProxy

Cette méthode, pour peu qu’elle respecte les pré-requis énonces plus haut devrait fonctionner avec FTPs (SSL wrapper) & FTP/TLS

HAProxy est un équilibreur de charge moderne et largement utilisé. Il offre des fonctionnalités similaires à Keepalived et bien d’autres. Néanmoins HAProxy n’est pas capable de tracker les connexions de données en relation avec la session FTP globale. Pour cette raison, nous devons tromper le protocole FTP afin d’assurer la cohérence de la connexion dans la session.

On installe d’abord HAProxy:
sudo apt-get install haproxy

HAProxy intègre la notion de « frontends » et de « backends ». Les frontends permettent de définir des sockets spécifiques (ou ensemble de sockets) qui peuvent être liés à différents backends.
Nous pouvons donc utiliser la configuration ci-dessous:


frontend alfControlChannel
bind *:21
default_backend alfPool

frontend alf1DataChannel
bind *:20000-20009
default_backend alf1

frontend alf2DataChannel
bind *:20010-20019
default_backend alf2

backend alfPool
server alf1 10.1.2.101 check port 21 inter 20s
server alf2 10.1.2.102 check port 21 inter 20s

backend alf1
server alf1 10.1.2.101 check port 21 inter 20s

backend alf2
server alf2 10.1.2.102 check port 21 inter 20s

Dans cet exemple, le frontend qui gère la connexion de contrôle (alfControlChannel) envoie alternativement des requêtes à tous les serveurs backend (alfPool). Chaque serveur (alf1 & alf2) négocie un socket de transfert de données sur un frontend différent (alf1DataChannel & alf2DataChannel). Chacun de ces frontend transmettra la connexion de données au seul backend correspondant (alf1 ou alf2), ce qui rend l’équilibrage de charge cohérent.
Et le tour est joué!

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *