Nginx SSL Preread Sporadically Gets Requests Where No Server Name Is Extracted

1

I am using the nginx stream module to leverage nginx as a tcp reverse proxy in front of s3. Recently, I needed to add logic to accommodate an additional upstream. To do this, I chose to make use of conditional logic via the map variable $ssl_preread_server_name. ssl_preread allows nginx to extract the server name from the ClientHello message without terminating SSL. You can see the logic below:

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

When a request comes in that has the server name s3.amazonaws.com the request is sent to s3. When a request comes in that has the server name aws-service-2.amazonaws.com, the request is sent to aws-service-2.

This works most of the time. But, sometimes there are errors in the error log that indicate that somehow requests are hitting the nginx servers on port 443 without any server name.

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

When I add in a default statement in the map logic, these errors go away. What are possible explanations for some s3 requests coming in with no server name extracted? The only way requests could hit these nginx boxes currently is if someone does an s3 operation.

Howard_Roark

Posted 2019-03-27T19:14:30.360

Reputation: 23

Answers

0

I am not familiar with Amazon S3 as such, but I think that the problem is that the requests are generated without setting the server name (see Server Name Indication).

I experienced the very same issue in a similar setup and was able to reproduce this for example in OpenSSL v1.0.2p by connecting without explicitly setting the servername parameter:

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

This request would just provide me with the certificate of the default server and not respect the domain name that I provided in the URL. On the other hand when specifying the servername parameter:

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

.. the request is sent to the right domain and the correct certificate is returned.

When accessing the very same web server with curl or via web browsers I do not observe this issue, I suspect the implementation in the web browser and curl are setting the server name by extracting it from the URL in the background whereas some client side applications such as openssl treat it as an optional parameter.

So in your case I guess you have to:

  • find out where the requests are generated
  • see if there is an option to set the server name

nethor.t

Posted 2019-03-27T19:14:30.360

Reputation: 16