Configuration avancée d’Apache en tant que Reverse Proxy pour une application Web interne


Cet article détaille la configuration d’Apache en tant que reverse proxy pour une application web interne sécurisée. Ce processus implique plusieurs étapes pour garantir une communication fluide et sécurisée entre les clients et le serveur backend.

Contexte

L’application web interne est hébergée sur un serveur backend avec une adresse IP interne. L’objectif est de configurer Apache pour servir de reverse proxy, permettant aux utilisateurs d’accéder à l’application via une URL publique sécurisée.

Qu’est-ce qu’un Reverse Proxy ?

Un reverse proxy agit comme un intermédiaire entre les clients (utilisateurs) et les serveurs backend. Il reçoit les requêtes des clients et les transmet aux serveurs appropriés. Le reverse proxy permet de masquer les adresses IP des serveurs backend et, éventuellement, de répartir la charge de trafic, et d’appliquer des politiques de sécurité. C’est un élément standard pour la sécurisation d’une application, on peut, par ailleurs, imaginer implémenter un WAF (comme mod_security) pour sécuriser le plus possible les requêtes afin d’éviter toute compromission du serveur finale.

Schéma Explicatif

[ Utilisateur ] <--> [ Reverse Proxy (Apache) - https://monapp.mondomaine.com (192.168.1.10:443) ] <--> [ Serveur Backend (https://192.168.1.20:8443) ]

Configuration Détailée du Reverse Proxy

192.168.1.10 est l’adresse IP interne du reverse proxy.

Configuration du VirtualHost

<VirtualHost 192.168.1.10:443>
    ServerName monapp.mondomaine.com

    ## Racine du vhost
    DocumentRoot "/var/www/html"

    ## Répertoires
    <Directory "/var/www/html">
        Options Indexes FollowSymLinks MultiViews
        AllowOverride None
        Require all granted
    </Directory>

    ## Journaux
    ErrorLog "/var/log/httpd/monapp_error_ssl.log"
    ServerSignature Off
    CustomLog "/var/log/httpd/monapp_access_ssl.log" combined

    ## Règles d'en-têtes de requêtes
    RequestHeader set X-Forwarded-For "%{REMOTE_ADDR}s"
    RequestHeader set X-Forwarded-Proto "https"

    ## Directives de proxy SSL
    SSLProxyEngine On           # Active le moteur de proxy SSL pour gérer les connexions HTTPS
    SSLProxyVerify none         # Désactive la vérification des certificats SSL du serveur en amont
    SSLProxyCheckPeerCN off     # Désactive la vérification du nom commun (CN) du certificat SSL
    SSLProxyCheckPeerName off   # Désactive la vérification du nom du certificat SSL

    ## Règles de proxy
    ProxyRequests Off
    ProxyPreserveHost Off

    ## Détecter les requêtes XHR et définir une variable d'environnement
    SetEnvIf X-Requested-With "XMLHttpRequest" xhr_request

    ## Définir l'en-tête Host vers le serveur upstream uniquement pour les requêtes XHR
    RequestHeader set Host 192.168.1.20 env=xhr_request

    ## Directives Proxy Pass
    ProxyPass / https://192.168.1.20:8443/
    ProxyPassReverse / https://192.168.1.20:8443/

    ## Directives SSL
    SSLEngine on                # Active le moteur SSL pour ce virtual host
    SSLCertificateFile "/etc/ssl/mescertificats/mondomaine.com.crt"      # Chemin vers le fichier du certificat SSL
    SSLCertificateKeyFile "/etc/ssl/mescertificats/mondomaine.com.key"   # Chemin vers la clé privée SSL
    SSLCertificateChainFile "/etc/ssl/mescertificats/mondomaine.com.crt" # Chemin vers le fichier de la chaîne de certificats SSL

    ## Activer le moteur de réécriture
    RewriteEngine on

    # Support WebSocket
    RewriteCond %{HTTP:Upgrade} =websocket [NC]
    RewriteRule /(.*) wss://192.168.1.20:8443/$1 [P,L]

    # Appliquer un filtre de substitution pour divers types MIME
    <Location />
        SubstituteMaxLineLength 10M
        AddOutputFilterByType SUBSTITUTE text/html text/css text/javascript application/javascript application/json
        Substitute "s|https://192.168.1.20:8443|https://monapp.mondomaine.com|ni"

        # Autoriser toutes les méthodes HTTP
        <Limit GET POST PUT DELETE PATCH OPTIONS>
            Require all granted
        </Limit>
    </Location>

    # Paramètres de proxy inverse
    ProxyPassReverseCookieDomain 192.168.1.20 monapp.mondomaine.com
    ProxyPassReverseCookiePath / /
</VirtualHost>

Explications des Directives

  1. ProxyRequests Off : Désactive la fonctionnalité de proxy ouvert, assurant qu’Apache n’est pas utilisé comme un proxy direct par des clients externes.
  2. ProxyPreserveHost Off : Désactive la préservation de l’en-tête Host d’origine, permettant au serveur backend de traiter correctement les requêtes authentifiées.
  3. RequestHeader set Host 192.168.1.20 env=xhr_request : Modifie l’en-tête Host uniquement pour les requêtes XHR, ce qui permet de « duper » l’application finale en lui faisant croire que les requêtes proviennent directement de l’IP interne 192.168.1.20.
  4. SSLProxyEngine On et SSLProxyVerify none : Activent le proxy SSL et désactivent la vérification des certificats, étant donné que le certificat du serveur final est autosigné, pour les connexions HTTPS.
  5. ProxyPass / https://192.168.1.20:8443/ et ProxyPassReverse / https://192.168.1.20:8443/ : Configurent le routage des requêtes vers le serveur backend.
  6. RewriteCond et RewriteRule : Gèrent les connexions WebSocket.
  7. Substitute : Réécrit les URLs dans les réponses pour assurer que les liens et les ressources utilisent l’URL publique.
  8. ProxyPassReverseCookieDomain et ProxyPassReverseCookiePath : Réécrivent les cookies pour qu’ils soient corrects du point de vue des clients.

Tester la Configuration

Pour tester la configuration, utilisez curl pour simuler des requêtes et vérifier les réponses :

curl -k -v -X PUT "https://monapp.mondomaine.com/api/test" \
    -H "Accept: application/json, text/plain, */*" \
    -H "Content-Type: application/json" \
    -H "Cookie: JSESSIONID=example_cookie; XSRF-TOKEN=example_token" \
    -H "X-Requested-With: XMLHttpRequest" \
    -d '{"key":"value"}'

Résultats

Après l’application de cette configuration finale et le redémarrage d’Apache, les requêtes étaient correctement routées via le reverse proxy, et les réponses du serveur backend étaient manipulées comme prévu.

Conclusion

La configuration d’Apache en tant que reverse proxy pour une application web sécurisée nécessite une attention particulière aux en-têtes HTTP, à la gestion des cookies, et aux règles de réécriture. Ce processus implique souvent plusieurs essais et ajustements afin d’obtenir une configuration stable et fonctionnelle, surtout quand l’application n’a pas été prévue pour ce type d’usage.