SNI に基づく Nginx 選択的 TLS パススルー リバース プロキシ

SNI に基づく Nginx 選択的 TLS パススルー リバース プロキシ

私は NAT の背後に IoT デバイスのシステムを持っているため、パブリック インターネットからはアクセスできません (望ましいことですが)。これを克服するために、それらを VPN に接続し、1 つのメンバーをパブリック インターネットに公開してゲートウェイとして機能させました。VPN には内部ドメインが設定されており、ネットワークの各メンバーには、次の図のように、一意の ID (ここでは MAC アドレスを使用) に基づくサブドメインがあります。12a4f81ead4e.vpn.example.com

Gatwaynginx を実行して、リクエストをプロキシするためにリバース プロキシを作成したいと考えています。

計画としては、ゲートウェイ の DNS レコードを作成し、 との間のトラフィックを にルーティング (プロキシ) することです。*.gateway.comそのため、エンド ユーザーは、ブラウザーに入力するだけでデバイスにアクセスできます。ゲートウェイでは既に他の目的で nginx が実行されているため、nginx を使用したいと思います。12a4f81ead4e.gateway.com12a4f81ead4e.vpn.example.com12a4f81ead4e.gateway.com

HTTP リクエストは簡単に実行でき、慎重に作成された nginx ディレクティブで実行できると思いますproxy_pass

しかし、HTTPS リクエストはどうでしょうか? 私の理解する限りでは、SNI に基づく TLS パススルーは現在 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 リクエストは通常​​どおり既存の vhost にサーバします。可能であれば、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;

    (...)
  }
}

答え1

これはうまくいきます:

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

関連情報