Причины различного поведения обратного прокси Apache с SSL и без него - PullRequest
0 голосов
/ 06 мая 2020

Я работал над локальным обратным прокси-сервером, который направляет трафик c между двумя локальными Apache установками (каждая из которых запускает другую версию mod_wsgi, что является причиной раздвоения). Я хочу, чтобы этот обратный прокси работал независимо от того, являются ли запросы HTTP или HTTPS.

Однако при использовании SSL заголовок ответа Location не изменяется (должным образом) ProxyPassReverse.

Ниже приведены определения VirtualHost для HTTP и HTTPS трафика c, соответственно:

<VirtualHost *:80>
        # Proxy traffic for Version 6 with an alias of: 6x/
        ProxyPass /6x/ http://localhost:10090/
        ProxyPassReverse /6x/ http://localhost:10090/

        # Proxy traffic for previous versions with aliases of: 5x/, 4x/, and /
        ProxyPass /5x/ http://localhost:10080/
        ProxyPassReverse /5x/ http://localhost:10080/
        ProxyPass /4x/ http://localhost:10080/
        ProxyPassReverse /4x/ http://localhost:10080/
        ProxyPass / http://localhost:10080/
        ProxyPassReverse / http://localhost:10080/
</VirtualHost>
<IfModule mod_ssl.c>
        <VirtualHost *:443>
                ServerName snakeoil.us.com

                ProxyPreserveHost on
                ProxyRequests off
                SSLEngine on
                SSLProxyEngine on
                SSLProxyVerify none
                SSLProxyCheckPeerCN off
                SSLProxyCheckPeerName off
                SSLProxyCheckPeerExpire off

                SSLCertificateFile /etc/ssl/certs/snakeoil.crt
                SSLCertificateKeyFile /etc/ssl/certs/snakeoil.key
                SSLCertificateChainFile /etc/ssl/certs/bundle-client.crt

                # Proxy traffic for Version 6 with an alias of: 6x/
                ProxyPass /6x/ https://localhost:10453/
                ProxyPassReverse /6x/ https://localhost:10453/

                # Proxy traffic for previous versions with aliases of: 5x/, 4x/, and /
                ProxyPass /5x/ https://localhost:10443/
                ProxyPassReverse /5x/ https://localhost:10443/
                ProxyPass /4x/ https://localhost:10443/
                ProxyPassReverse /4x/ https://localhost:10443/
                ProxyPass / https://localhost:10443/
                ProxyPassReverse / https://localhost:10443/
        </VirtualHost>
</IfModule>

Когда я получаю доступ к URL http://snakeoil.us.com/6x/snk610/index, заголовок местоположения возвращается как: Location: http://snakeoil.us.com/6x/snk610/index.

Однако, когда я обращаюсь к URL-адресу https://snakeoil.us.com/6x/snk610/index, заголовок местоположения возвращается как: Location: https://snakeoil.us.com/snk610/index, что приводит к 404, поскольку только один из двух локальных экземпляров Apache (связанный с маршрутом 6x) proxied распознает псевдоним snk610 (и в данном случае это не тот экземпляр, на который маршрутизируется).

Суть в том, что определение HTTP VirtualHost в обязательном порядке передает запросы прокси между двумя локальными экземплярами Apache . Однако в определении HTTPS VirtualHost нет, и мне непонятно, что вызывает это несоответствие.

1 Ответ

0 голосов
/ 06 мая 2020

Удалось найти решение. Оглядываясь назад, это должно было быть более очевидным.

На экземплярах Apache, на которые проксируются, я изменил формат access_log на следующий:

LogFormat "%h %l %u %t \"%r\" %>s %b   -->   ResponseLocation: '%{Location}o'" common

Это вызывает исходящий ответ местоположение для регистрации.

Вот вывод из Apache экземпляра HTTP (к которому проксируется):

[snake6x@test1 httpd6x]$ grep "ResponseLocation: 'http" logs/access_log
::1 - - [06/May/2020:15:43:25 -0400] "GET /snk610 HTTP/1.1" 301 233   -->   ResponseLocation: 'http://localhost:10090/snk610/index'
::1 - - [06/May/2020:15:43:30 -0400] "GET /snk610/index HTTP/1.1" 302 247   -->   ResponseLocation: 'http://localhost:10090/snk610/login?params=&message=&redirect_to=index'
::1 - - [06/May/2020:15:43:32 -0400] "POST /snk610/auth?redirect_to=index&params= HTTP/1.1" 302 204   -->   ResponseLocation: 'http://localhost:10090/snk610/index'

Из приведенного выше вы можете видеть, что заголовок местоположения ответа выглядит как и ожидалось, то есть ProxyPassReverse должен иметь возможность успешно произвести замену.

И наоборот, вот вывод экземпляра Apache HTTPS (проксируется на):

[snake6x@test1 httpd]$ grep "ResponseLocation: 'http" logs/ssl_request_log
[06/May/2020:19:53:38 +0000] ::1 "GET /snk610 HTTP/1.1" 240 2645788   -->   ResponseLocation: 'https://snakeoil.us.com/snk610/index'
[06/May/2020:19:56:21 +0000] ::1 "GET /snk610/index HTTP/1.1" 254 2682899   -->   ResponseLocation: 'https://snakeoil.us.com/snk610/login?params=&message=&redirect_to=index'
[06/May/2020:19:56:23 +0000] ::1 "POST /snk610/auth?redirect_to=index&params= HTTP/1.1" 240 752392   -->   ResponseLocation: 'https://snakeoil.us.com/snk610/index'

Из выше, вы можете видеть, что имя сервера было заменено именем входящего хоста в заголовке местоположения ответа. Это было причиной того, что ProxyPassReverse не мог заменить исходящее имя хоста (на обратном прокси-сервере).

Я решил эту проблему, явно обновив заголовок исходящего местоположения на проксируемом сервере на:

    # Since this server has a proxy immediately in front of it, we need the outgoing
    # location to match the incoming location. However, the ServerName tag will
    # cause the incoming location to be changed to include the ServerName, which will
    # cause the upstream ProxyPassReverse to fail to update the outgoing location
    # properly.
    #
    # This Header modification replaces the outgoing ServerName with the incoming
    # name.
    #
    # FIXME: There is surely a better way to do this with a variable that contains
    # the incoming host
    Header edit Location ^https://snakeoil.us.com:443 https://localhost:10453
    Header edit Location ^https://snakeoil.us.com https://localhost:10453
...