私は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 などの一部のクライアント側アプリケーションではサーバー名をオプションのパラメーターとして扱っているのではないかと思います。
したがって、あなたの場合は次のことをしなければならないと思います:
- リクエストが生成された場所を確認する
- サーバー名を設定するオプションがあるかどうかを確認します