Передача имени из SNI на upstream-серверы может потребоваться в том случае, если бэкэнд-приложение жестко завязано на имени сервиса. В этом случае необходимо изменить ряд настроек по умолчанию на Nginx
Если вам интересна тематика Debian и связанных с ним приложений, рекомендую обратиться к тегу Debian на моем блоге.
Передача имени ресурса из SNI
В статье Несколько сертификатов на Nginx я рассматривал процесс настройки обратного прокси Nginx таким образом, чтобы он раскидывал запросы к разным ресурсам, каждый из которых имеет свое уникальное имя и свой отдельный сертификат. В этой статье я расскажу об одном нюансе работы данного механизма.
Предлагаю ознакомиться с другими статьями про Nginx на моем блоге:
Приятного чтения!
Теория
Несмотря на то, что Nginx распределяет запросы пользователей по бэкэнд-серверам исходя из имени ресурса в SNI, на бэкэнды он этот параметр по умолчанию не передает. То есть, бэкэнд вероятнее всего увидит обращение по его собственному ip-адресу, а не красивый fqdn. Все бы ничего, но для некоторых сервисов (например Windows Server WAP) такое поведение может быть нежелательным и они будут обрывать соединение (RST, ACK) сразу после TLS Client Hello от Nginx. Вот как это выглядит в WireShark:
Полный вывод сессии в текстовом формате:
1 2 3 4 5 |
1 0.000000 192.168.1.2 192.168.1.51 TCP 74 33176 → 443 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=26906684 TSecr=0 WS=32 2 0.000102 192.168.1.51 192.168.1.2 TCP 74 443 → 33176 [SYN, ACK] Seq=0 Ack=1 Win=8192 Len=0 MSS=1460 WS=256 SACK_PERM=1 TSval=84293549 TSecr=26906684 3 0.000288 192.168.1.2 192.168.1.51 TCP 66 33176 → 443 [ACK] Seq=1 Ack=1 Win=29216 Len=0 TSval=26906685 TSecr=84293549 4 0.000481 192.168.1.2 192.168.1.51 TLSv1 242 Client Hello 5 0.000549 192.168.1.51 192.168.1.2 TCP 54 443 → 33176 [RST, ACK] Seq=1 Ack=177 Win=0 Len=0 |
Если включить дебаг в Nginx, то можете получать подобные сообщения:
1 |
2018/09/24 22:36:11 [error] 3699#3699: *1 peer closed connection in SSL handshake (104: Connection reset by peer) while SSL handshaking to upstream, client: 10.0.1.70, server: sts.bissquit.com, request: "GET /adfs/ls/idpinitiatedsignon.htm HTTP/1.1", upstream: "https://10.16.1.51:443/adfs/ls/idpinitiatedsignon.htm", host: "sts.bissquit.com" |
В нем содержится как причина разрыва соединения – peer closed connection in SSL handshake (104: Connection reset by peer) while SSL handshaking to upstream – так и конечный URL, который дошел до бэкэнд-сервера – https://10.16.1.51:443/adfs/ls/idpinitiatedsignon.htm. Итого, наша задача – передавать на upstream-серверы имя ресурса, по которому изначально обращается клиент.
Настройки
Первой и самой главной опцией, разрешающей передачу имени ресурса на upstream-серверы, является proxy_ssl_server_name 1. Необходимо выставить её в значение on и определить имя ресурса в директиве proxy_pass. Выглядеть это будет следующим образом (это первый вариант):
1 2 3 4 5 6 7 8 |
... upstream sts.bissquit.com { server 10.16.1.51:443; } ... proxy_pass https://sts.bissquit.com; proxy_ssl_server_name on; |
Второй вариант заключается в переопределении имени ресурса в нужной вам секции конфигурации Nginx. Для этого нужны параметры:
- proxy_ssl_name 2 – переопределяет имя сервера;
- proxy_set_header 3 – переопределяет необходимые поля заголовка запроса. В нашем случае понадобится заголовок Host.
В моем случае устанавливать нужное имя ресурса логично в секции location {}. Итак, получаем:
1 2 3 4 5 6 |
location / { proxy_pass https://testlab; proxy_ssl_server_name on; proxy_ssl_name sts.bissquit.com; proxy_set_header Host sts.bissquit.com; } |
Как итог – сервис работает нормально.