Nginx SSL 事前読み取りで、サーバー名が抽出されないリクエストが散発的に発生する

Nginx SSL 事前読み取りで、サーバー名が抽出されないリクエストが散発的に発生する

私はnginx ストリームモジュールnginx を s3 の前の TCP リバース プロキシとして活用します。最近、追加のアップストリームに対応するロジックを追加する必要がありました。これを行うには、マップ変数 $ssl_preread_server_name を介して条件付きロジックを使用することにしました。ssl_prereadnginx が SSL を終了せずに ClientHello メッセージからサーバー名を抽出できるようにします。以下のロジックを確認できます。

map $ssl_preread_server_name $https_cname {
    s3.amazonaws.com https_s3_backend;
    aws-service-2.amazonaws.com aws-service-2-backend;
}
upstream https_s3_backend {
    server s3.amazonaws.com:443;
}
upstream aws_service_2_backend {
    server aws-service-2.amazonaws.com:443;
}

server {
    listen       443;
    proxy_pass $https_cname;
    ssl_preread on;
}

サーバー名が s3.amazonaws.com であるリクエストが届くと、そのリクエストは s3 に送信されます。サーバー名が aws-service-2.amazonaws.com であるリクエストが届くと、そのリクエストは aws-service-2 に送信されます。

これはほとんどの場合機能します。ただし、サーバー名なしで何らかの理由でリクエストがポート 443 の nginx サーバーにヒットしていることを示すエラーがエラー ログに表示されることがあります。

[error] ... no host in upstream "", client: x.x.x.x, server: 0.0.0.0:443

マップ ロジックにデフォルト ステートメントを追加すると、これらのエラーは解消されます。サーバー名が抽出されていない一部の s3 リクエストが届く理由は何でしょうか? 現在、リクエストがこれらの nginx ボックスに到達する唯一の方法は、誰かが s3 操作を実行することです。

答え1

私はAmazon S3に詳しくありませんが、問題はサーバー名を設定せずにリクエストが生成されることだと考えています(サーバー名の表示)。

同様の設定でまったく同じ問題を経験しましたが、たとえば、servername パラメータを明示的に設定せずに接続することで、OpenSSL v1.0.2p でこれを再現することができました。

openssl s_client -connect <mydomain>:<some_port> -showcerts

このリクエストでは、デフォルト サーバーの証明書のみが提供されるだけで、URL で指定したドメイン名は考慮されません。一方、servername パラメータを指定する場合は次のようになります。

openssl s_client -connect <mydomain>:<some_port> -showcerts -servername <mydomain>

.. リクエストは正しいドメインに送信され、正しい証明書が返されます。

curl または Web ブラウザー経由でまったく同じ Web サーバーにアクセスする場合、この問題は発生しません。Web ブラウザーと curl の実装では、バックグラウンドで URL からサーバー名を抽出して設定しているのに対し、openssl などの一部のクライアント側アプリケーションではサーバー名をオプションのパラメーターとして扱っているのではないかと思います。

したがって、あなたの場合は次のことをしなければならないと思います:

  • リクエストが生成された場所を確認する
  • サーバー名を設定するオプションがあるかどうかを確認します

関連情報