Proxy inverso de paso a través de TLS selectivo de Nginx basado en SNI

Proxy inverso de paso a través de TLS selectivo de Nginx basado en SNI

Tengo un sistema de dispositivos IoT detrás de una NAT, por lo que no se puede acceder a ellos desde la Internet pública (aunque es deseable). Para superar esto, los vinculé a una VPN, con un miembro expuesto a la Internet pública para actuar como puerta de enlace. La VPN tiene un dominio interno configurado y cada miembro de la red tiene un subdominio basado en una ID única (vamos con la dirección MAC), así:12a4f81ead4e.vpn.example.com

Deseo crear un proxy inverso en las Gatwaysolicitudes de proxy, ejecutando nginx.

El plan es crear un registro DNS para la puerta de enlace *.gateway.comy enrutar (ejem, proxy) el tráfico que va hacia/ 12a4f81ead4e.gateway.comdesde 12a4f81ead4e.vpn.example.com. Y así, el usuario final sólo tendría que escribir 12a4f81ead4e.gateway.comen su navegador para acceder a su dispositivo. Me gustaría usar nginx, ya que la puerta de enlace ya ejecuta nginx para otros fines.

Espero que las solicitudes HTTP sean fáciles y se puedan realizar con una proxy_passdirectiva nginx cuidadosamente diseñada.

Pero ¿qué pasa con las solicitudes HTTPS? Hasta donde tengo entendido, nginx ahora implementa el paso de TLS basado en SNI, pero todos los ejemplos que he visto hasta ahora crean un mapa estático para... bueno, mapean el SNI entrante a un objetivo ascendente:

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;
  }
}

El problema es que los dispositivos se agregan/eliminan dinámicamente de la VPN y no quiero reescribir los archivos de configuración de nginx todo el tiempo. Si es posible leer el mapa desde un archivo, es un paso en la dirección correcta, aunque creo que nginx debería recargarse cada vez que cambie, lo que plantea problemas de permisos, que podrían evitarse con reglas sudo, por supuesto, pero no con la mejor solución.

Además, solo quiero enviar por proxy las solicitudes que llegan *.gateway.comy enviar otras solicitudes https normalmente a los vhosts existentes. Si es posible, me gustaría evitar cancelar la conexión SSL. Realmente no es un requisito difícil, pero me gustaría implementarlo de esa manera si es técnicamente factible. También sólo por diversión.

Estoy bien escuchando internamente en un puerto alternativo para los otros vhosts, hice algo similar para HTTP cuando quería establecer una ubicación "global", moví todos los vhosts HTTP al puerto 81 e implementé un vhost general en el puerto. 80 que sirvió a la ubicación "global" y envió todo lo demás al puerto 81. :)

Entonces... Lo que necesitaría sería algo como esto (obviamente no funciona):

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;

    (...)
  }
}

Respuesta1

Esto funciona:

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;
    (...)
  }
}

información relacionada