Utiliser Apache ProxyPass pour accèder à des serveurs cachés derrière un hôte de Masquage

ArticleCategory: [Choose a category for your article]

System Administration

AuthorImage:[Here we need a little image form you]

[Photo of the Author]

TranslationInfo:[Author and translation history]

original in en Atif Ghaffar 

en to fr Jean Peyratout 

AboutTheAuthor:[A small biography about the author]

Je vis et travaille en Suisse en tant que webmestre et administrateur Unix. Parmi mes passions on peut compter Linux, Unix, Perl, Apache et les logiciels libres GPL. Plus de détails sur moi sur ma homepage.

Abstract:[Here you write a little summary]

J'ai un petit réseau local chez moi avec Linux utilisant le Masquage IP et un firewall. Bien que chaque machine de mon réseau puisse avoir accès à toute l'information sur l'Internet, seule la machine qui fait le masquage d'IP est accessible depuis l'Internet. Dans mon dernier article sur Apache, je vous ai montré comment recycler des adresses IP. Dans cet article-ci j'expliquerai comment faire pour qu'un serveur Web derrière un firewall puisse être accessible sur l'Internet sans changer les règles de votre firewall ni compromettre la sécurité. Nous verrons dans cet article comment utiliser l'instruction ProxyPass de Apache pour atteindre ce but. Cet article s'adresse à des administrateurs système ou à des gens qui montent un réseau local de taille petite à moyenne, à la maison ou au travail.

ArticleIllustration:[This is the title picture for your article]

[logo Apache]

ArticleBody:[The article body]

Le problème avec le Masquage IP (IP masquarading)

Pendant longtemps, sur mon réseau local, le routeur (la machine qui faisait le masquage d'IP et le firewall) tenait aussi les rôles de serveur Web, serveur de courrier, serveur FTP, serveur DNS, etc.
Un jour j'ai eu besoin de fournir du contenu web depuis une autre machine qui se trouvait derrière le firewall.
Je voulais également permettre l'accès à des documents depuis une machine SGI IRIX qui se trouvait derrière le réseau (un serveur d'images vidéo en continu). Cette machine avait l'accès complet à l'Internet, mais les usagers ne pouvaient pas s'y connecter depuis l'extérieur. Bien que je n'aie pas l'intention de mettre cette machine IRIX sur le réseau, il fallait quand même que l'on puisse se connecter au service web disponible sur cette machine.

J'avais un problème du même genre au travail avec un réseau similaire et un firewall.
Chaque fois que quelqu'un souhaitait qu'un serveur Web en développement soit disponible depuis l'Internet pour des besoins de démonstration, il fallait changer les règles du firewall et attribuer à la machine une adresse IP extérieure, compromettant ainsi la sécurité du réseau.

Apache à la rescousse : ProxyPass

Après avoir envisagé plusieurs solutions j'en ai installé une avec Apache et son instruction ProxyPass.
ProxyPass requiert mod_proxy pour être compilé avec votre serveur Apache ou chargé en tant que module.
Voici la définition de ProxyPass tirée du manuel d'Apache :

ProxyPass

Syntaxe : ProxyPass <path> <url>
Valeur par défaut : Aucune
Contexte : config serveur, hôte virtuel
Override : Non applicable
Statut : Base
Module : mod_proxy
Compatibilité : ProxyPass n'est disponible qu'à partir des versions d'Apache 1.1 et ultérieures.

Cette instruction permet de "mapper" des serveurs distants dans l'espace du serveur local ; le serveur local ne fonctionne pas comme un proxy au sens habituel, mais apparaît comme un miroir du serveur distant ;  <path> est le nom d'un chemin local virtuel ; <url> est une URL partielle pour le serveur distant.

Supposons que le serveur local a l'adresse http://wibble.org/  ;  alors

   ProxyPass /mirror/foo/ http://foo.com/
provoquera la conversion interne d'une requête locale à <http://wibble.org/mirror/foo/bar> en une requête proxy à <http://foo.com/bar>.

Un exemple réel

"Mapper" le serveur vidéo interne au serveur web externe.
Réseau interne : hometranet.home 192.168.1.0/255.255.255.0
(dans le genre internet, intranet, extranet, j'ai appelé mon réseau domestique "hometranet")
Réseau externe : developer.ch 193.192.254.50

Serveur vidéo (interne) tournant sur l'hôte cam.hometranet.home
servant de la vidéo depuisl'URL http://cam.hometranet.home:5555/cams/sony/stream
et aussi des images d'un appareil à http://cam.hometranet.home:5555/cams/sony/image.

Je souhaitais voir le contenu des ces URL's en visitant
http://mozilla.developer.ch/stream et http://mozilla.developer.ch/image
Ceci peut être facilement fait en utilisant l'instruction ProxyPass depuis Apache en ajoutant simplement les lignes suivantes au fichier httpd.conf ou srm.conf

ProxyPass /video http://cam.hometranet.home:5555/cams/sony/stream
ProxyPass /video http://cam.hometranet.home:5555/cams/sony/stream

Maintenant, après le redémarrage du serveur Web (si mod_proxy est disponible), http://mozilla.developer.ch/image répond depuis le serveur Web nommé cam.
Pour le visiteur sur le site c'est totalement transparent, et presque* aucune sécurité n'est perdue par cette méthode.
*Je dis "presque" car la sécurité totale n'existe pas sur l'Internet :)

Mapper des serveurs virtuels

L'astuce de ProxyPass peut être employée pour "mapper" un hôte virtuel dans son intégralité sur une machine différente.
Par exemple : docs.sun.developer.ch mappé sur solsparc.hometranet.home

NameVirtualHost 193.192.254.50
<VirtualHost 193.192.254.50>
     ServerName sun.docs.developer.ch
     ProxyPass / http://solsparc.hometranet.home/
     TransferLog /net/www/logs/sun.docs.access
     ErrorLog    /net/www/logs/sun.docs.errror
</VirtualServer>
Vous pouvez aussi faire suivre aux hôtes en utilisant leur adresse IP.
<VirtualHost 193.192.254.50>
     ServerName sun.docs.developer.ch
     ProxyPass / http://192.168.1.7/
     TransferLog /net/www/logs/sun.docs.access
     ErrorLog    /net/www/logs/sun.docs.errror
</VirtualServer>

Mises en garde

Étant donné que votre serveur Web principal envoie des requêtes aux serveurs Web internes au nom de vos utilisateurs, vous ne pouvez pas faire de logging (traçage dans un fichier "log") commode sur l'hôte cible, vous devez plutôt faire un log de toutes les requêtes sur l'hôte source.
Dans le cas cité plus haut je fais un log des entrées sur l'hôte principal sun.docs.developer.ch
au lieu de solsparc.hometranet.home

Voici les résultats du logging sur sun.docs.developer.ch (fictif) :

197.0.22.3 - - [05/Nov/1999:22:09:04 +0100] "GET /index.html HTTP/1.0" 304 -
187.0.45.67 - - [05/Nov/1999:22:09:04 +0100] "GET /navi.html HTTP/1.0" 304 -
177.0.5.45 - - [05/Nov/1999:22:09:04 +0100] "GET /entrees.html HTTP/1.0" 304 -
227.0.9.67 - - [05/Nov/1999:22:09:15 +0100] "GET /complets.html HTTP/1.0" 304 -
137.0.7.23 - - [05/Nov/1999:22:09:19 +0100] "GET /menu_poisson.html HTTP/1.0" 200 841
193.192.245.73 - - [05/Nov/1999:22:09:25 +0100] "GET /volailles.html HTTP/1.0" 304 -
192.167.0.1 - - [05/Nov/1999:22:09:44 +0100] "GET /agneau.html HTTP/1.0" 304 -                                                            
Et les résultats du logging sur solsparc.hometranet.home
192.168.1.1 - - [05/Nov/1999:22:09:04 +0100] "GET /index.html HTTP/1.0" 304 -
192.168.1.1 - - [05/Nov/1999:22:09:04 +0100] "GET /navi.html HTTP/1.0" 304 -
192.168.1.1 - - [05/Nov/1999:22:09:04 +0100] "GET /entrees.html HTTP/1.0" 304 -
192.168.1.1 - - [05/Nov/1999:22:09:15 +0100] "GET /complets.html HTTP/1.0" 304 -
192.168.1.1 - - [05/Nov/1999:22:09:19 +0100] "GET /menu_poisson.html HTTP/1.0" 200 841
192.168.1.1 - - [05/Nov/1999:22:09:25 +0100] "GET /volailles.html HTTP/1.0" 304 -
192.168.1.1 - - [05/Nov/1999:22:09:44 +0100] "GET /agneau.html HTTP/1.0" 304 -
192.168.1.1 - - [05/Nov/1999:22:09:56 +0100] "GET /desserts_ind.html HTTP/1.0" 304 -
192.168.1.1 - - [05/Nov/1999:22:10:00 +0100] "GET /cocktails.html HTTP/1.0" 304 -
192.168.1.1 - - [05/Nov/1999:22:10:10 +0100] "GET /cgi-bin/commande.cgi HTTP/1.0" 200 2146        

Le même raisonnement s'applique aux listes de contrôle d'accès (ACLs, access control list) basées sur le nom ou sur l'IP.
Si vous souhaitez interdire certains hôtes ou certaines adresses IP, ou bien autoriser l'accès de certaines adresses IP à des zones particulières, alors ceci doit être fait sur le serveur principal (celui qui est accessible à distance) au lieu du serveur local.
De plus, vous ne pouvez pas utiliser de restrictions aux utilisateurs basées sur l'instruction Directory (répertoire).
À la place vous pouvez employer l'instruction Location ou Files ou FilesMatch.
L'exemple qui suit concerne certaines d'entre elles. Exemple:
<VirtualHost 193.192.254.50>
     ServerName sun.docs.developer.ch
     #cette règle n'autorise que les utilisateurs du domaine good.host.com
     <Location /private>
          order deny,allow
          deny from all
          allow from good.host.com
     </Location>
     #interdit le monopole de Microsoft par le biais de son aide à la navigation uncool.
     BrowserMatch MSIE uncool_browser
     <Location /coolpages>
         order allow,deny
         allow from all
         deny from env=uncool_browser
     </Location>
     #n'autorise que les seuls utilisateurs qui sont dans votre fichier passwd.httpd
     <Location /coolpages>
         AuthName "only for registered users"
         AuthType Basic
         AuthUserFile "/etc/httpd/passwd.httpd"
         <Limit GET>
              require valid-user
         </Limit>
     </Location>

     ProxyPass / http://192.168.1.7/
     TransferLog /net/www/logs/sun.docs.access
     ErrorLog    /net/www/logs/sun.docs.errror
</VirtualServer>

Autres ressources

(en anglais  )
[Apache mod_proxy documentation]
http://www.apache.org/docs/mod/mod_proxy.html
[Apache name-based Virtual Host Support]
http://www.apache.org/docs/vhosts/name-based.html
[Apache Virtual Host documentation]
http://www.apache.org/docs/vhosts/index.html