Назад | Перейти на главную страницу

Nginx селективный обратный прокси-сервер TLS на основе SNI

У меня есть система IoT-устройств за NAT, поэтому они недоступны из общедоступного Интернета (хотя это желательно). Чтобы преодолеть это, я привязал их к VPN, при этом один участник был открыт для публичного доступа в Интернет, чтобы действовать как шлюз. В VPN настроен внутренний домен, и у каждого члена сети есть поддомен на основе уникального идентификатора (давайте перейдем к MAC-адресу), например: 12a4f81ead4e.vpn.example.com

Я хочу создать обратный прокси на Gatway на запросы прокси, запускающие nginx.

Планируется создать DNS-запись для шлюза, *.gateway.com, и маршрутизировать (кхм, прокси) трафик в / из 12a4f81ead4e.gateway.com к 12a4f81ead4e.vpn.example.com. И поэтому конечному пользователю нужно будет просто ввести 12a4f81ead4e.gateway.com в свой браузер, чтобы получить доступ к своему устройству. Я бы хотел использовать nginx, так как на шлюзе уже запущен nginx для других целей.

Я ожидаю, что HTTP-запросы будут простыми и могут быть выполнены с помощью тщательно созданного nginx proxy_pass директива.

Но как насчет HTTPS-запросов? Насколько я понимаю, транзитная передача TLS на основе SNI теперь реализована nginx, но все примеры, которые я видел до сих пор, создают статическую карту для ... ну, сопоставления входящего SNI с целевым восходящим потоком:

stream {
  map $ssl_preread_server_name $selected_upstream {
    example.org upstream_1;
    example.net upstream_2;
    example.com upstream_3;
    default upstream_4;
  }
  upstream upstream_1 { server 10.0.0.1:443; }
  upstream upstream_2 { server 10.0.0.2:443; }
  upstream upstream_3 { server 10.0.0.3:443; }
  upstream upstream_4 { server 10.0.0.4:443; }
  server {
    listen 10.0.0.5:443;
    proxy_pass $selected_upstream;
    ssl_preread on;
  }
}

Проблема в том, что устройства динамически добавляются / удаляются из VPN, и я не хочу постоянно переписывать файлы конфигурации nginx. Если чтение карты из файла возможно, это шаг в правильном направлении, хотя я думаю, что nginx нужно будет перезагружать каждый раз, когда это изменяется, что вызывает проблемы с разрешениями, которые, конечно, можно обойти с помощью правил sudo, но не лучшее решение.

Также я хочу, чтобы прокси-запросы поступали в *.gateway.com, а остальные https-запросы отправляйте обычно к существующим vhosts. Если это вообще возможно, я бы хотел избежать прерывания SSL-соединения. Не очень сложное требование, но хотелось бы реализовать его таким образом, если это технически выполнимо. Также просто для удовольствия.

Я в порядке, внутренне слушая альтернативный порт для других хостов, я сделал что-то подобное для HTTP, когда хотел установить «глобальное» местоположение, и переместил все HTTP-хосты на порт 81 и реализовал универсальный виртуальный хост на порту. 80, который обслуживал "глобальное" местоположение, а все остальное проксировал на порт 81. :)

Итак ... Что мне нужно, это что-то вроде этого (явно не работает):

stream {
  map $ssl_preread_server_name $selected_upstream {
    (.*).gateway.com $1.vpn.example.com;
    default normal_serve;
  }

  upstream normal_serve { server 127.0.0.1:8443; }

  server {
    listen 0.0.0.0:443;
    proxy_pass $selected_upstream;
    ssl_preread on;
  }

  server {
    listen 127.0.0.1:8443;
    server_name other.website.com;

    (...)
  }
}

Это помогает:

stream {
  resolver 8.8.8.8;

  map $ssl_preread_server_name $selected_upstream {
    ~(.*).gateway.example.com $1.vpn.example.com:443;
    default 127.0.0.1:8443;
  }

  server {
    listen 0.0.0.0;
    proxy_pass $selected_upstream;
    ssl_preread on;
  }
}

http {
  resolver 8.8.8.8;
  server {
    listen 127.0.0.1:8443 ssl;
    (...)
  }
}