web-dev-qa-db-fra.com

Comment puis-je utiliser HAproxy avec SSL et obtenir des en-têtes X-Forwarded-For ET dire à PHP que SSL est utilisé?

J'ai la configuration suivante:

(internet) ---> [  pfSense Box  ]    /-> [ Apache / PHP server ]
                [running HAproxy] --+--> [ Apache / PHP server ]
                                    +--> [ Apache / PHP server ]
                                     \-> [ Apache / PHP server ]

Pour les requêtes HTTP, cela fonctionne très bien , les requêtes sont très bien distribuées sur mes serveurs Apache. Pour les demandes SSL, j'ai eu HAproxy distribuer les demandes en utilisant TCP équilibrage de charge, et cela a fonctionné cependant puisque HAproxy n'a pas agi comme un proxy, il n'a pas ajouté le X-Forwarded-For En-tête HTTP et les serveurs Apache/PHP ne connaissaient pas la véritable adresse IP du client.

J'ai donc ajouté stunnel devant HAproxy, lisant que stunnel pourrait ajouter le X-Forwarded-For En-tête HTTP. Cependant, le paquet que j'ai pu installer dans pfSense n'ajoute pas cet en-tête ... aussi, cela tue apparemment ma capacité à utiliser les requêtes KeepAlive , que j'aimerais vraiment garder. Mais le plus gros problème qui a tué cette idée était que Stunnel convertissait les requêtes HTTPS en requêtes HTTP simples, donc PHP ne savait pas que SSL était activé et tentait de rediriger vers le site SSL.

Comment puis-je utiliser HAproxy pour équilibrer la charge sur un certain nombre de serveurs SSL, permettant à ces serveurs de connaître à la fois l'adresse IP du client et de savoir que SSL est utilisé ? Et si possible, comment le faire sur mon serveur pfSense?

Ou devrais-je laisser tomber tout cela et utiliser simplement nginx?

20
Josh

Vous n'avez pas besoin de tout laisser tomber, vous pouvez simplement utiliser nginx devant haproxy pour le support SSL, en gardant toute votre configuration d'équilibrage de charge. Vous n'avez même pas besoin d'utiliser nginx pour HTTP si vous ne le souhaitez pas. Nginx peut transmettre à la fois X-Forwarded-For et un en-tête personnalisé indiquant que SSL est utilisé (et les informations de certificat client si vous le souhaitez). Extrait de configuration Nginx qui envoie les informations requises:

proxy_set_header SCHEME $scheme;      # http/https
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header CLIENT_CERT $ssl_client_raw_cert;
17
Ochoto

Pour mémoire, comme ce fil est souvent mentionné concernant HAProxy + SSL, HAProxy prend en charge SSL natif des deux côtés depuis 1.5-dev12. Ainsi, avoir X-Forwarded-For, HTTP keep-alive ainsi qu'un en-tête indiquant au serveur que la connexion a été établie via SSL est aussi simple que ce qui suit:

listen front
    bind :80
    bind :443 ssl crt /etc/haproxy/haproxy.pem
    mode http
    option http-server-close
    option forwardfor
    http-request set-header X-Forwarded-Proto https if { ssl_fc }
    server srv1 1.1.1.1:80 check ...
    ...

Je suis sûr qu'au moment où vous avez trouvé quelque chose de différent, mais au moins les nouveaux visiteurs auront la solution facile maintenant :-)

37
Willy Tarreau

Pour tous ceux qui trouvent cette question, j'ai suivi les conseils d'Ochoto et utilisé nginx. Voici les étapes spécifiques que j'ai utilisées pour que cela fonctionne sur mon routeur pfSense :

  1. À l'aide de l'interface Web de pfsense, j'ai installé pfsense package PfJailctl et le package "jail_template" sous Système> Packages pour pouvoir créer une prison FreeBSD sous laquelle compiler et installer nginx sur le système pfsense.

  2. J'ai configuré une prison pour mon serveur nginx sous Services> Prisons , donnant à la nouvelle prison le même nom d'hôte et la même adresse IP que l'alias IP virtuel que j'avais HAproxy en cours d'exécution. J'ai lié la prison à l'interface WAN. J'ai utilisé le modèle de prison par défaut et activé unionfs plutôt que nullfs.

  3. Une fois la prison démarrée, je me suis connecté à la boîte pfsense et j'ai exécuté jls pour trouver le numéro de la prison. J'ai ensuite couru jexec 1 sh pour obtenir un Shell à l'intérieur de la prison. De là, j'ai configuré les ports BSD et installé nginx en utilisant:

    portsnap extract
    portsnap fetch update
    cd /usr/ports/www/nginx
    make install clean
    
  4. J'ai ensuite configuré nginx pour écouter sur le port 443 et transmettre toutes les demandes à HAproxy sur le port 80, y compris la véritable IP et l'état SSL dans les en-têtes HTTP. Ma usr/local/etc/nginx/nginx.conf ressemble à:

    worker_processes  1;
    
    events {
        worker_connections  2048;
    }
    
    http {
        upstream haproxy {
            server 209.59.186.35:80;
        }
    
        server {
            listen       443;
            server_name  my.Host.name default_server;
            ssl                  on;
            ssl_certificate      my.crt;
            ssl_certificate_key  my.key;
            ssl_session_timeout  5m;
    
            ssl_protocols  SSLv3 TLSv1;
            ssl_ciphers  HIGH:!aNULL:!MD5;
            ssl_prefer_server_ciphers   on;
    
            location / {
                proxy_pass http://haproxy;
    
                proxy_set_header Host $Host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    
                proxy_set_header X-Forwarded-Proto https;
            }
        }
    
    }
    
  5. J'ai ensuite modifié mon PHP application pour détecter le X-Forwarded-Proto En-tête HTTP:

    function usingSSL()
    {
        return (
           (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on' )
            || (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])
                   && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https' ));
    }
    

La configuration finale est donc:

(internet) ---> [ -> nginx -> haproxy -]--> (pool of Apache servers)
                [    (pfSense server)  ]
12
Josh

Ma configuration pour une version 1.5-dev-17 de haproxy:

global
        log 127.0.0.1   local0
        log 127.0.0.1   local1 notice
        #log loghost    local0 info
        maxconn 4096
        #chroot /usr/share/haproxy
        user haproxy
        group haproxy
        daemon
        #debug
        #quiet

defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        option  http-server-close
        retries 3
        option redispatch
        fullconn 1000        
        maxconn 1000
        timeout queue 600s
        timeout connect 5s
        timeout client 600s
        timeout server 600s

frontend http-in
        bind *:80
        bind *:443 ssl crt /usr/local/etc/ssl/certs
        reqadd X-Forwarded-Proto:\ https if { ssl_fc }
        default_backend varnish-ha
        option forwardfor
backend varnish-ha
  server hafront1 10.1.69.1:6081  minconn 100 maxqueue 10000

Il utilise le ssl_fc ACL. Veuillez noter que le option http-server-close une partie est très importante.

7
greg0ire

HAProxy ne peut pas toucher un backend SSL sans utiliser le raw TCP, perdant X-Forwarded-For, mais, vous pourriez potentiellement rechiffrer le trafic avec un stunnel d'écoute pour le transit backend. Moche, cependant.

J'aime mieux l'approche d'Ochoto, avec une mise en garde: nginx est un équilibreur de charge parfaitement capable; si vous l'utilisez, je dirais l'utiliser pour tout. Proxy votre HTTPS entrant pour charger des backends HTTPS équilibrés - et de cette façon, il n'y a pas besoin d'en-têtes personnalisés pour les informations SSL (sauf si vous avez besoin du certificat client).

5
Shane Madden

J'ai implémenté une solution l'année dernière pour intégrer HAProxy à pfSense de manière à exploiter toutes les fonctionnalités de HAProxy et à maintenir une bonne isolation avec pfSense. Il s'agit donc d'une option viable pour les environnements de production . SSL est terminé sur HAProxy . J'ai installé HAProxy dans une prison dans pfSense en utilisant ezjail et Ports Collection . De cette façon, il est très facile de maintenir les deux composants indépendamment. Et vous pouvez installer la version que vous souhaitez. J'ai commencé avec 1.5-dev13. Et depuis, cela fonctionne parfaitement pour moi. J'ai documenté le tout ici.

Installation de HAProxy sur pfSense

BTW Willy, merci beaucoup pour cet excellent produit.

2
Dinesh Sharma