--[ Apache et la gestion des modules : application à l'intégration Apache/Tomcat ]-- 1. Introduction Cette brève aborde la gestion des modules dans le serveur Apache, dans les branches 1.3 et 2.0, et plus particulièrement sous l'angle des interférences entre les modules agissant sur l'URI d'une requête simple -- qu'il s'agisse de déterminer la ressource locale associée à cette URI, ou encore d'effectuer des opérations de filtrage (mod_security), de r[é]écriture (mod_rewrite) et, optionnellement, de relayage (mod_proxy, mod_jk). La configuration étudiée dans cette brève sera constituée d'un Apache associé à un conteneur de servlets/JSP Tomcat, par l'intermédiaire d'un connecteur AJP13 (mod_jk). Des opérations de réécriture et de filtrage seront effectuées au niveau du serveur Apache -- dont le fonctionnement sera, dans cette configuration, proche de celui d'un relais-inverse HTTP filtrant. 2. Interactions entre modules (Apache 1.3) 2.1. Fonctionnement des modules Le serveur HTTP Apache (http://httpd.apache.org) bénéficie d'une architecture modulaire, et chaque module additionnel peut intervenir au cours de la phase de traitement des requêtes transmises au serveur. Le traitement d'une requête HTTP suit approximativement le cheminement suivant : · Lecture de la requête, des en-têtes Détermination de l'hôte virtuel · Interprétation de l'URI Traduction en nom d'objet local : étape URI-to-Filename · Contrôle d'accès utilisateur (mod_auth.c par exemple) Authentification (AuthType) Autorisation (Require) · Contrôle d'accès (mod_access.c par exemple) Allow, deny · Détermination du type MIME de l'objet demandé · Mises au point (Fixup) · Envoi de la réponse au client · Journalisation Pour rappel, une requête HTTP prend la forme suivante : GET / HTTP/1.1. Host: localhost. User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031225 Firebird/0.7. Accept: text/xml,application/xml,application/xhtml+xml [...] Accept-Language: en-us,en;q=0.5. Accept-Encoding: gzip,deflate. Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7. Keep-Alive: 300. Connection: keep-alive. Le traitement s'effectue sur la base cette requête, de la socket TCP sous-jacente (adresses IP, ports TCP) voire de la session SSL/TLS négociée, le cas échéant (certificat client si présenté pour une authentification au niveau SSL/TLS, SESSIONID, protocole, triplet d'algorithmes etc.). À chacune de ces étapes, les différents modules sont successivement sollicités pour prendre en charge une étape du traitement d'une requête, suivant l'algorithme simplifié ci-dessous (extrait de mod_rewrite.c) : while(request or subrequest) foreach(stage #0...#9) foreach(module) (**) try to run hook Par défaut, l'ordre des modules est déterminé par leur ordre de compilation (modifiable via la directive « --permute-module ») : leur chargement est réalisé dans l'ordre inverse de l'ordre de compilation. Prenons le binaire httpd suivant : $ ./httpd -l Compiled-in modules: http_core.c mod_env.c mod_log_config.c mod_mime.c mod_status.c mod_info.c mod_dir.c mod_cgi.c mod_alias.c mod_rewrite.c mod_access.c mod_auth.c mod_proxy.c mod_so.c mod_setenvif.c mod_ssl.c mod_jk.c Dans le cas présent, l'ordre est donc le suivant : 1: mod_jk.c, 2: mod_ssl.c, 3: mod_setenvif.c ... 8: mod_rewrite.c ... Le module qui prend la main le premier est par conséquent mod_jk, et le dernier module appelé est mod_env.c, qui laisse finalement la main à http_core.c (qui ne peut d'ailleurs être compilé que de façon statique). La liste des modules chargés peut être modifiée et augmentée à l'exécution, via le fichier de configuration httpd.conf par la directive LoadModule du module mod_so (compilé statiquement) qui permet de déclarer les modules dynamiques (.so) disponibles. Le module mod_gzip est, par exemple (il s'agira du seul module dynamique présent dans cet exemple), ainsi chargé : LoadModule gzip_module libexec/mod_gzip.so Les modules sont, comme précédemment, chargés dans l'ordre inverse de leur déclaration -- et les modules déclarés par LoadModule prennent la main avant tout module compilé statiquement, par défaut. Ainsi, dans la configuration prise pour exemple, les modules successivement sollicités sont les suivants, après ajout de la directive LoadModule : 1. mod_gzip.c 2. mod_jk.c 3. mod_ssl.c 4. mod_setenvif.c 5. mod_so.c 6. mod_proxy.c 7. mod_auth.c 8. mod_access.c 9. mod_rewrite.c [...] Cette liste est vérifiable à l'aide du module server-info, autorisé uniquement localement, permettant de connaître la configuration du serveur à l'exécution : SetHandler server-info Order Deny,Allow Deny from all Allow from 127.0.0.1 La recherche des modules chargés (indiqués par le nom « Module Name ») est facilement obtenue, de même que leur ordre de chargement : $ w3m -dump http://127.0.0.1/server-info | grep "Module Name" Finalement, l'ordonnancement des modules statiques ou dynamiques (sans distinction) peut être modifié à l'exécution par la directive AddModule. Dans ce cas, le _dernier_ module ajouté est le _premier_ à prendre la main. La directive AddModule a pour fonction d'« empiler » les modules (modules dynamiques déclarés par LoadModule + modules statiques du binaire monolithique httpd). La directive AddModule doit être précédée de la directive ClearModuleList. Remarque : outre l'ordonnancement de modules, cette directive permet de ne pas activer, à l'exécution, des modules compilés statiquement (afin de ne pas recompiler le binaire httpd, typiquement). En conservant l'ordonnancement actuel (qui sera rectifié ultérieurement), la configuration à adopter serait par conséquent la suivante : 8< -------------------------------------------------------- # Chargement du module dynamique mod_gzip par mod_so (compile # statiquement pour initier le processus) LoadModule gzip_module libexec/mod_gzip.so # Reinitialisation de la liste des modules charges ClearModuleList # Empilement des modules a activer -- en commençant par le dernier AddModule mod_env.c AddModule mod_log_config.c AddModule mod_mime.c # AddModule mod_status.c AddModule mod_info.c AddModule mod_dir.c AddModule mod_cgi.c AddModule mod_alias.c AddModule mod_rewrite.c AddModule mod_access.c AddModule mod_auth.c AddModule mod_proxy.c AddModule mod_so.c AddModule mod_setenvif.c AddModule mod_ssl.c AddModule mod_jk.c AddModule mod_gzip.c 8< -------------------------------------------------------- La bonne compréhension du chargement des modules est cruciale pour obtenir une configuration exempte d'erreurs, le cas contraire pouvant typiquement conduire à des attaques par déni de service ou encore permettant d'accéder à des fichiers interprêtés en temps normal - dans le cas de mod_rewrite notamment. 2.2. Interférences entre modules : mod_jk et mod_rewrite Dans cette partie, on considère un serveur Apache communiquant avec un serveur Tomcat en AJP13, par l'intermédiaire du module mod_jk (1.x). Ce relais-inverse HTTP est susceptible d'effectuer une réécriture (voire du filtrage) sur les paramètres qu'il transmet au conteneur de servlets et JSP Tomcat -- typiquement pour éviter des URL du type "(%3f|?).jsp$". Le choix d'un connecteur AJP13 offre, par rapport au relayage HTTP, la possibilité de transmettre au serveur Tomcat les paramètres de session SSL/TLS, l'adresse IP du client initial etc. ; de plus les requêtes AJP sont effectuées sur des connexions TCP persistantes -- offrant un gain en performances certain par rapport à un relayage HTTP plus traditionnel. Pour résumer : il vaut mieux préférer la combinaison mod_jk + connecteur AJP1x à la combinaison mod_proxy + connecteur HTTP, pour de multiples et bonnes raisons. 2.2.1. Description du problème Considérons l'hôte virtuel suivant, configuré au niveau du serveur précédent (configuration respectant la syntaxe mod_jk 1.x) : [...] JkMount /appli/* ajp13 [...] Toute requête destinée à l'URI correspondant au motif « /appli/* » est transmise au serveur Tomcat, « directement », en AJP13. Dans la configuration actuelle, avec l'ordonnancement des modules vu précédemment, aucune réécriture n'est donc possible pour mod_rewrite : mod_jk prend la main _avant_ mod_rewrite (il s'agit d'un module tier, compilé a posteriori et par conséquent chargé en dernier lieu, car ajouté en fin de liste dans le fichier de configuration httpd.conf). Plus précisément, à l'examen des sources de ces modules, on constate une interférence au niveau de la phase de traduction de l'URI vers un nom de fichier (lors de l'étape dite de traduction « URI-to-Filename », d'après ce qui a été précédemment décrit) : Au niveau de mod_rewrite : NULL /* [#0] post read-request */ hook_uri2file, /* [#1] URI to filename translation */ NULL, /* [#2] header parser */ NULL, /* [#3] check access by host address */ NULL, /* [#4] validate user id from request */ NULL, /* [#5] check if the user is ok _here_ */ hook_mimetype, /* [#6] determine MIME type */ hook_fixup, /* [#7] pre-run fixups */ handler_table, /* [#8] MIME-typed-dispatched handlers */ NULL, /* [#9] log a transaction */ Au niveau de mod_jk : NULL /* [1] post read_request handling */ jserv_translate_handler, /* [2] filename-to-URI translation */ NULL, /* [3] header parser */ NULL, /* [4] check access by host address */ NULL, /* [5] check/validate user_id */ NULL, /* [6] check user_id is valid *here* */ jserv_type_match, /* [7] MIME type checker/setter */ NULL, /* [8] fixups */ NULL, /* [10] logger */ Les deux modules interviennent donc simultanément lors des phases « URI to filename translation ». Par défaut, si un des modules prend la main pour ce hook, aucun autre module lors de la même étape de traitement ne pourra intervenir (sauf artifice, qui sera abordé ultérieurement). Dans la configuration actuelle, toute URI de type « /appli/* » sera donc interceptée et traitée par mod_jk, et aucune réécriture ne sera dès lors envisageable par la suite par mod_rewrite. Il est recommandé par conséquent de charger le module mod_jk _avant_ mod_rewrite, via la directive AddModule, de sorte que mod_rewrite puisse réécrire les URI à destination du serveur Tomcat. Néanmoins, en accord avec ce qui a été vu précédemment, on comprend bien que mod_jk ne prendra plus la main sur ces requêtes, ce qui est d'autant plus gênant... Heureusement, une « astuce » de configuration permet de passer outre, et de permettre la manipulation d'une requête à la fois par mod_rewrite _puis_ par mod_jk. Ce réordonnancement se fait ainsi : 8< -------------------------------------------------------- ClearModuleList AddModule mod_env.c AddModule mod_log_config.c AddModule mod_mime.c AddModule mod_dir.c AddModule mod_cgi.c AddModule mod_alias.c AddModule mod_jk.c # <--- AddModule mod_rewrite.c # | AddModule mod_access.c # | AddModule mod_auth.c # | AddModule mod_proxy.c # | AddModule mod_so.c # | AddModule mod_setenvif.c # | AddModule mod_ssl.c # | # AddModule mod_jk.c # ---- AddModule mod_gzip.c 8< -------------------------------------------------------- En pratique, l'ordonnancement des modules standards est le résultat du travail de l'équipe de développement du projet Apache. Il est donc recommandé de déplacer le module tier mod_jk, et non le module standard mod_rewrite. Deux scénarii sont alors envisageables, et se distinguent par les flags mod_rewrite requis : 1. Interception d'un URI et réécriture par mod_rewrite, puis redirection interne vers une URI locale (classique) ; 2. Interception d'une URI et réécriture par mod_rewrite, _puis_ interprétation par mod_jk -- et par Tomcat, par extension. Ces cas sont traités dans les parties suivantes. 2.2.2. Exemple n°1 : indexation Tomcat L'exemple abordé ici sera celui de la désactivation (au niveau du serveur Apache) de l'indexation réalisée au niveau du serveur Tomcat : ----------------------------------------------------------------------- Directory Listing For / Filename Size Last Modified [...] Apache Tomcat/4.0.2 ----------------------------------------------------------------------- Cette page est générée par le serveur Tomcat. L'idée est donc d'effectuer une redirection interne de « ^/appli/$ » vers l'URI locale « /index.html » : ainsi, une requête sur https://192.168.0.1/appli/ aboutira sur la page index.html locale au serveur Apache, et non plus à la page d'indexation générée par le serveur Tomcat. La configuration peut se faire simplement de la façon suivante (après modification de l'ordre de chargement des modules, comme précédemment évoqué) : 8< -------------------------------------------------------- [...] RewriteEngine On RewriteLogLevel 3 RewriteLog /var/log/apache/rewrite.log RewriteRule ^/appli/$ /index.html [L] JkMount /appli/* ajp13 [...] 8< -------------------------------------------------------- Il est par ailleurs recommandé de privilégier les redirections internes aux redirections « externes » (caractérisées par le flag [R]). Dans les journaux, on obtiendrait alors : (2) init rewrite engine with requested uri /appli/ (3) applying pattern '^/appli/$' to uri '/appli/' (2) rewrite /appli/ -> /index.html (2) local path result: /index.html (2) prefixed with document_root to /appli/www/appli/htmldocs/index.html (1) go-ahead with /appli/www/appli/htmldocs/index.html [OK] Une ressource locale est servie pour /appli/. En revanche, les autres URI préfixées par /appli/ sont effectivement transmises au serveur Tomcat. 2.2.3. Exemple n°2 : filtrage sur la requête simple par mod_rewrite Dans ce second cas, mod_rewrite doit prendre la main lors de la phase de traduction « URI to filename », puis laisser la main à mod_jk sur l'URI récrite pour une _nouvelle _ phase de traduction « URI to filename ». Ce qui est problématique d'après ce qui a été précédemment vu : ce fonctionnement n'est initialement pas prévu par Apache, un seul module pouvant intervenir activement lors d'une étape donnée du traitement d'une URI. Cependant mod_rewrite dispose d'un flag [PT] (Pass Through) faisant que mod_rewrite répond par un DECLINED au noyau Apache (http_core.c), et laisse la main au handler du module suivant : mod_jk dans le cas qui nous intéresse. La configuration peut se faire de la façon suivante : 8< -------------------------------------------------------- [...] RewriteEngine On RewriteLogLevel 3 RewriteLog /var/log/apache/rewrite.log RewriteRule ^/appli/page1.html /appli/page2.html [PT] JkMount /appli/* ajp13 [...] 8< -------------------------------------------------------- Le résultat produit est le suivant : (2) init rewrite engine with requested uri /appli/page1.html (3) applying pattern '^/appli/$' to uri '/appli/page1.html' (3) applying pattern '^/appli/page1.html' to uri '/appli/page1.html' (2) rewrite /appli/page1.html -> /appli/page2.html (2) forcing '/appli/page2.html' to get passed through to next API URI-to-filename handler L'URI récrite « /appli/page2.html » est alors passée au handler « URI-to-filename » du module suivant immédiatement, et actif pour cette étape, autrement dit celui de mod_jk (qui va transmettre la requête ainsi récrite au serveur Tomcat). Cette réécriture pourrait consister en un filtrage de paramètres minimaliste. Le filtrage de paramètres par mod_rewrite souffre néanmoins d'une limitation : il peut uniquement être effectué sur la QUERY_STRING et sur des requêtes qui ne sont pas des sous-requêtes (la structure de sous-requête Apache, pour une sous-requête lancée suite à une redirection interne par exemple, comporte un champ QUERY_STRING vide), dans la mesure où mod_rewrite agit uniquement sur la requête simple et ses entêtes. Il n'est en particulier pas en mesure d'agir sur le corps des requêtes, autrement dit sur les paramètres passés par la méthode POST. Le module mod_security sera, à cet effet, évoqué dans la partie suivante. Un exemple de filtrage de paramètres est envisageable comme suit : 8< -------------------------------------------------------- [...] RewriteEngine On RewriteLogLevel 3 RewriteLog /var/log/apache/rewrite.log RewriteCond %{REQUEST_URI} ^/appli/myservlet$ RewriteCond %{QUERY_STRING} !^param1=[0-9a-zA-Z]{1,5}\¶m2=[0-9]{1,3}$ RewriteRule .* - [F] JkMount /appli/* ajp13 [...] 8< -------------------------------------------------------- Dans ce cas, les prototypes des paramètres sont explicitement définis par les expressions régulières de la seconde condition déclenchant la règle de réécriture. Si les paramètres passés ne respectent pas ce paramètre, un « forbidden » sera envoyé en réponse par le serveur Apache, dans cet exemple. Pour effectuer le test, on pourra par exemple utiliser le wrapper GET du toolkit LWP, extrêmement pratique pour réaliser ce type de test (de façon similaire, la commande POST permet de générer des requêtes dont les paramètres sont soumis par le corps du message, le calcul de la longueur des données envoyées étant géré par le programme). 3. Combinaison mod_jk/mod_rewrite/mod_security 3.1. Installation L'installation se fera sur la base de : - Apache 1.3.19 + mod_ssl 2.8.16, avec mod_rewrite compilé dynamiquement, et support du programme apxs(8) ; - Installation de mod_jk 1.2 et mod_security 1.7.4 a posteriori avec apxs(8) ; Tous les modules compilés le seront dynamiquement. - Installation du serveur Apache + mod_ssl : /usr/local/src/build > tar zxvf ../archives/apache_1.3.29.tar.gz /usr/local/src/build > tar zxvf ../archives/mod_ssl-2.8.16-1.3.29.tar.gz /usr/local/src/build > cd mod_ssl-2.8.16-1.3.29/ /usr/local/src/build/mod_ssl-2.8.16-1.3.29 > ./configure --with-apache=../apache_1.3.29/ /usr/local/src/build/mod_ssl-2.8.16-1.3.29 > cd ../apache_1.3.29/ /usr/local/src/build/apache_1.3.29 > SSL_BASE=SYSTEM ./configure --disable-module=userdir \ --disable-module=autoindex \ --disable-module=include \ --disable-module=cgi \ --disable-module=actions \ --disable-module=imap \ --disable-module=env \ --disable-module=negotiation \ --disable-module=asis \ --disable-module=alias \ --enable-module=ssl \ --enable-module=rewrite \ --enable-module=proxy \ --enable-shared=max \ --prefix=/usr/local/stow/apache13/ /usr/local/src/build/apache_1.3.29 > make /usr/local/src/build/apache_1.3.29 > make certificate /usr/local/src/build/apache_1.3.29 > sudo make install Au final, le binaire httpd comporte uniquement les modules http_core.c et mod_so.c compilés statiquement (httpd -l), strictement nécessaires au chargement des modules dynamiques. Remarque : mod_jk a une dépendance sur mod_dir. Il ne faut donc _pas_ désactiver complètement le module mod_dir, et le déclarer (via LoadModule) _avant_ mod_jk, sans pour autant l'activer via AddModule à l'éxecution... Quant à mod_setenvif, il est nécessaire pour modifier le comportement de mod_ssl suivant le navigateur utilisé (IE et les messages d'alerte SSL/TLS...). - Installation de mod_security 1.7.4 : Le module est téléchargeable depuis l'adresse suivante : http://www.modsecurity.org/ L'installation est réalisée avec apxs(8) : /usr/local/src/build > tar zxvf ../archives/mod_security-1.7.4.tar.gz /usr/local/src/build > cd mod_security-1.7.4 /usr/local/src/build/mod_security-1.7.4 > sudo /usr/local/stow/apache13/bin/apxs -cia apache1/mod_security.c Le module mod_security est alors activé dans httpd.conf (en fin de liste par défaut, ce qui n'est pas problématique, comme on le verra dans la partie suivante). - Installation de mod_jk (1.2) : Le module est téléchargeable depuis l'adresse suivante : http://jakarta.apache.org/site/sourceindex.cgi La compilation (avec apxs(8)) suit le processus : /usr/local/src/build > tar zxvf ../archives/jakarta-tomcat-connectors-jk-1.2-src-current.tar.gz /usr/local/src/build > cd jakarta-tomcat-connectors-jk-1.2.5-src ..ld/jakarta-tomcat-connectors-jk-1.2.5-src > cd jk/native ..ta-tomcat-connectors-jk-1.2.5-src/jk/native > ./configure --with-apxs=/usr/local/stow/apache13/bin/apxs ..ta-tomcat-connectors-jk-1.2.5-src/jk/native > sudo cp apache-1.3/mod_jk.so /usr/local/stow/apache13/libexec Au niveau de la configuration, s'appuyer sur ce qui a été vu dans les parties précédentes, au niveau de la déclaration (LoadModule) et de l'ordonnancement (AddModule). 3.2. Configuration Au niveau de la configuration Apache à proprement parler, on prendra soin de positionner les directives suivantes -- en tout premier lieu : ServerTokens Prod ServerSignature Off Par rapport à la configuration mod_rewrite/mod_jk, peu de choses sont à ajouter -- les étapes sur lesquelles le module mod_security intervient sont en effet les suivantes : module MODULE_VAR_EXPORT security_module = { STANDARD_MODULE_STUFF, sec_init, /* module initializer */ sec_create_dir_config, /* create per-dir config structures */ sec_merge_dir_config, /* merge per-dir config structures */ sec_create_srv_config, /* create per-server config structures */ NULL, /* merge per-server config structures */ sec_cmds, /* table of config file commands */ NULL, /* [#8] MIME-typed-dispatched handlers */ NULL, /* [#1] URI to filename translation */ NULL, /* [#4] validate user id from request */ NULL, /* [#5] check if the user is ok _here_ */ NULL, /* [#3] check access by host address */ NULL, /* [#6] determine MIME type */ sec_check_access, /* [#7] pre-run fixups */ sec_logger, /* [#9] log a transaction */ NULL, /* [#2] header parser */ sec_child_init, /* child_init */ NULL, /* child_exit */ NULL /* [#0] post read-request */ }; Autrement dit, mod_security intervient principalement lors de la phase de fix-up, et non pas sur la phase de traduction URI vers nom de fichier. Aucune interférence à déplorer par conséquent : toutes les URI, manipulées par mod_rewrite aussi bien que mod_jk, seront filtrées. La configuration des modules peut donc être la suivante : 8< --------------------------------------------------- # Declaration des modules LoadModule config_log_module libexec/mod_log_config.so LoadModule mime_module libexec/mod_mime.so # mod_status pour diagnostic : restriction sur 127.0.0.1 LoadModule status_module libexec/mod_status.so # mod_info - avec restriction idem LoadModule info_module libexec/mod_info.so # Declaration de mod_dir (dependance mod_jk 1.2) LoadModule dir_module libexec/mod_dir.so LoadModule jk_module libexec/mod_jk.so LoadModule rewrite_module libexec/mod_rewrite.so LoadModule access_module libexec/mod_access.so LoadModule auth_module libexec/mod_auth.so LoadModule proxy_module libexec/libproxy.so LoadModule setenvif_module libexec/mod_setenvif.so LoadModule ssl_module libexec/libssl.so LoadModule security_module libexec/mod_security.so # Chargement et ordonnancement a l'execution ClearModuleList AddModule mod_log_config.c AddModule mod_mime.c AddModule mod_status.c AddModule mod_info.c # Pas necessaire d'activer mod_dir # AddModule mod_dir.c AddModule mod_jk.c AddModule mod_rewrite.c AddModule mod_access.c AddModule mod_auth.c AddModule mod_proxy.c AddModule mod_so.c AddModule mod_setenvif.c AddModule mod_ssl.c AddModule mod_security.c 8< --------------------------------------------------- Un exemple de configuration minimaliste de mod_security suit, avec filtrage sur le corps des requêtes (méthode POST) à destination de la ressource /cgi-bin/printenv (des « sanity checks » sont également effectués : XSS, SQL Injection, plage de caractères autorisés de %20 à %FE -- cf ascii(7) et iso_8859_1(7) pour le détail) : 8< -------- à insérer au niveau global --------------- SecFilterEngine On SecAuditEngine On SecAuditLog logs/audit_log SecFilterScanPOST On SecFilterCheckURLEncoding On SecFilterCheckUnicodeEncoding On SecFilterForceByteRange 32 254 SecFilter /etc/passwd SecFilter "\.\./" SecFilter "<[[:space:]]*script" SecFilter "<(.|\n)+>" SecFilter "delete[[:space:]]+from" SecFilter "insert[[:space:]]+into" SecFilter "select.+from" SecFilterInheritance Off SecFilterSelective POST_PAYLOAD "!^login=[a-zA-Z]{8}&password=[0-9]{1,8}$" 8< --------------------------------------------------- La touche finale de cette installation sera sans aucun doute la mise en cage du démon via chroot(8). Pour ce faire : - Procéder manuellement. Cf le document de Denis Ducamp sur le sujet : http://www.hsc.fr/ressources/breves/chroot.html - Utiliser un programme type makejail(8), à titre d'exemple, automatisant le processus et fonctionnant sur la base de modèles : http://www.floc.net/makejail/ 4. Notes sur Apache 2.0 Dans Apache 2.0, l'administrateur pourra noter que la direction AddModule a disparu. L'ordonnancement des modules est défini dans le source même du module, et offre une bien meilleure granularité que celle permise par Apache 1.3 : l'ordonnancement n'est plus global (valable pour l'ensemble des hooks d'un module), il peut être défini pour _chacun_ des hooks posés par ce module. La fonction permettant à un module d'enregistrer ses handlers est la suivante : ap_hook_phase_name(function_name, predecessors, successors, position); Plus précisément : - « function_name » correspond au handler ; - « predecessors » et « successors » définissent respectivement les modules qui doivent intervenir avant et après le module courant, pour ce hook ; - « position » est plus générique, et peut prendre les valeurs HOOK_FIRST, HOOK_MIDDLE et HOOK_LAST. En pratique, il s'agit donc de définir la position globalement (avec la variable « position »), puis d'affiner avec les variables « predecessors » et « successors ». Dans une configuration type Apache 2.0/mod_jk2 (module tier), l'interférence entre mod_jk2 et mod_rewrite a lieu au niveau du hook translate_name, qui se disputent la priorité APR_HOOK_FIRST : - mod_jk2 : ap_hook_translate_name(jk2_translate,NULL,NULL,APR_HOOK_FIRST); - mod_rewrite : ap_hook_translate_name(hook_uri2file,NULL,NULL,APR_HOOK_FIRST); Dans la configuration par défaut, mod_jk2 prend la main avant mod_rewrite. Il faut donc corriger mod_jk2 de la façon suivante : --- mod_jk2.c.orig 2004-01-26 17:31:04.000000000 +0100 +++ mod_jk2.c 2004-01-26 17:30:48.000000000 +0100 @@ -808,11 +808,14 @@ static void jk2_register_hooks(apr_pool_t *p) { + static const char * const aszPre[]={ "mod_rewrite.c",NULL }; + ap_hook_handler(jk2_handler, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_post_config(jk2_post_config,NULL,NULL,APR_HOOK_MIDDLE); /* Force the mpm to run before us and set the * scoreboard image */ ap_hook_child_init(jk2_child_init,NULL,NULL,APR_HOOK_LAST); - ap_hook_translate_name(jk2_translate,NULL,NULL,APR_HOOK_FIRST); + // ap_hook_translate_name(jk2_translate,NULL,NULL,APR_HOOK_FIRST); + ap_hook_translate_name(jk2_translate, aszPre,NULL,APR_HOOK_FIRST); ap_hook_map_to_storage(jk2_map_to_storage, NULL, NULL, APR_HOOK_MIDDLE); } La technique du flag [PT] de mod_rewrite peut, dès lors, être employée pour réécriture des URI qui seront transmises au Tomcat -- de même avec le flag [L] pour le service au client des ressources locales. * Remarque : il est également envisageable, pour ne pas avoir à modifier mod_jk2.c, de jouer sur la directive LoadModule et de charger mod_jk2 _après_ (par opposition à Apache 1.3) mod_rewrite... : # Include /etc/apache2/mods-enabled/*.load [...] LoadModule rewrite_module /usr/lib/apache2/modules/mod_rewrite.so [...] LoadModule jk2_module /usr/lib/apache2/modules/mod_jk2.so La facilité de configuration permettant de charger les modules par la création de liens symboliques n'est en revanche plus exploitable. On pourra donc préférer la première solution proposée. Outre cette meilleure granularité (lorsqu'elle est exploitée), un des avantages indéniables de l'utilisation d'Apache 2.0 est la possibilité d'utiliser des filtres en sortie, permettant de faire de la réécriture des URL (liens) renvoyées au client, dans le corps des réponses (et non plus seulement dans l'entête 'Location:' des réponses -- comme le fait mod_proxy via la directive ProxyPassReverse). Un bon lien sur la question, qui n'aborde pas la problématique du filtrage, néanmoins : http://www.apacheweek.com/features/reverseproxies 5. Conclusion La configuration d'un serveur Apache dans une optique de réécriture et de filtrage d'URL n'est, finalement, pas immédiate (sans même entrer dans le détail de l'écriture des règles de filtrage) -- compte-tenu des interférences susceptibles de se produire entre les modules agissant lors d'une même étape de traitement des URL. Si l'utilisation des modules standards Apache (mod_proxy, mod_rewrite) est généralement sans surprise, dans la mesure où leur intégration est pensée pour les usages les plus communs, l'ajout de modules tiers demandera vraisemblablement une réflexion quant à leur insertion parmi les modules déjà activés. par Franck Davy (17/10/2003)