How does the connection between CloudFront and one EC2 origin works using HTTPS?

Viewed 950

Let's assume we have a domain example.com pointing to an EC2 instance, that allows HTTPS and HTTP (redirection to HTTPS) traffic.

This instance has a WordPress instance running under Nginx.

We have a certificate for the domain example.com, not self-signed, a Comodo certificate.

We want to add CloudFront to the full example.com, so we create a CDN between the user and the EC2 instance.

We could use the site example.com with/without CDN, by having two endpoints serving the same content (example.com and origin.example.com). 
 Without CDN:

User -> example.com -> Route 53 pointing directly to instance IP (that has the Comodo certificate).

With CDN

User -> example.com -> Route 53 pointing to ALIAS CDN -> CDN pull from origin origin.example.com

origin.example.com will have the same content than example.com (both Nginx hosts pointing the same), and there we should allow only traffic from the CDN, but this is a different topic.

To achieve this, we create another endpoint, origin.example.com, with a self-signed certificate (using let's encrypt), placed in the same server (same IP address).

The idea is to send the traffic from the CDN to origin.example.com, and from there fetch the content.

This CDN has its own example.com SSL certificate generated by Amazon and has as origin origin.example.com. It also has the Host header whitelisted, and the CNAME origin.example.com added.

Everything works as expected. If you visit example.com, you get the content from the CDN.

The problem? If you check the instance logs (bot example.com and origin.example.com are set in the same EC2 instance), the CDN is NOT calling origin.example.com, as it would be expected, it is calling ALWAYS example.com. How is it possible?

I set Logs for the CloudFront, and in this logs are like:

2019-01-10 15:35:47 MAD50 27633 83.59.32.239 GET xxxxxx.cloudfront.net /mycontent/ 200 https://example.com/lalala - - Miss 5o…nX1hEbw== example.com https 566 0.140 - TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256 Miss HTTP/2.0 - -

I think this is due to the Host whitelisted field.

So, looks like the CloudFront sends the request to origin.example.com, but the Host header is set to example.com. So Nginx, somehow, parses the value in the example.com virtual host (as it is shown in the Logs, where you can see that the traffic comes from Amazon CloudFront). What is wrong here?

How CloudFront performs the connection?

What I am missing?

Thanks!

1 Answers

Your setup is behaving as expected.

When the Host header is whitelisted for forwarding, CloudFront still connects to the origin using the Origin Domain Name for the DNS lookup, but the Host header is not changed to match the Origin Domain Name as it is by default -- instead, it is copied from the original request sent by the browser, because that is (essentially) the purpose of whitelisting this header. (Whitelisting a header also adds the header to the cache key for the request, so requests where only the incoming Host header differs will be considered distinct when that header is whitelisted.) If not whitelisted, then the Host header sent to the origin is set by CloudFront to the value of Origin Domain Name.

For HTTPS from CloudFront to the Origin, CloudFront sets the SNI (during TLS negotiation with the origin) to the value it has chosen for the Host header using the rules, above, and requires the origin server to return a certificate matching that value.

This means that if the Host header is not whitelisted, then the origin server must have a certificate matching the Origin Domain Name, but if the Host header is whitelisted in the settings of the Cache Behavior that is handling a request, then CloudFront requires your origin server to supply a certificate matching the incoming Host header, not the Origin Domain Name.

If the appropriate rule is not matched, the request fails with 502 Bad Gateway, because CloudFront considers the origin to be misconfigured since the connection is not secure when there is a certificate mismatch.

What CloudFront does with request headers that are not whitelisted depends on the specific header. Many (such as Referer) are dropped from the request, but some (like Host and User-Agent) are rewritten, and others (like Content-Length) pass through anyway. The default actions are based on the purpose of the header, and these rules are designed for correct behavior and optimal caching.

Related