sferencik
sferencik

Reputation: 3249

HttpRequest: inconsistent Scheme & Host properties

My ASP.NET Core 3.1 application runs in Kubernetes. The ingress (load balancer) terminates SSL and talks to the pod over plain HTTP.

Let's say the ingress is reachable at https://my-app.com:443, and talks to the pod (where my app is running) at http://10.0.0.1:80.

When handling a request, the middleware pipeline sees an HttpRequest object with the following:

This is weird:

At no point in handling the request is there a request coming to http://my-app.com. It's either https://my-app.com or http://10.0.0.1. The combination is inconsistent.

Other details

Digging deeper, the HttpRequest object has the following headers (among others) that show the reverse proxying in action:

Host: my-app.com
Referer: https://my-app.com/swagger/index.html
X-Real-IP: 10.0.0.1
X-Forwarded-For: 10.0.0.1
X-Forwarded-Host: my-app.com
X-Forwarded-Port: 443
X-Forwarded-Proto: https
X-Scheme: https

I'm guessing HttpRequest is using these to get hold of the original host (my-app.com rather than 10.0.0.1) but it doesn't do the same for the original scheme (https rather than http).

Q1: Is this expected, and if so, what is the rationale?

Q2: What's the best way to get at the original URL (https://my-app.com)? The best I've found so far was to check if the X-Scheme and X-Forwarded-Host headers were present (by inspecting HttpRequest.Headers) and if so, using those. However, it's a little weird having to go to the raw HTTP headers in the middleware pipeline.

Upvotes: 0

Views: 397

Answers (1)

Nepomucen
Nepomucen

Reputation: 6667

Q1: Is this expected, and if so, what is the rationale?

I would say yes, it's the expected behavior.

The 'Host.Value=my-app.com' of HttpRequest object is reflecting the request header field originated by client (web browser, curl, ...), e.g.:

curl --insecure -H 'Host: my-app.com' https://<FRONTEND_FOR_INGRESS-MOST_OFTEN_LB-IP>

which is set*[1] in location block for that server 'my-app.com' inside generated nginx.conf file:

                    ...
                    set $best_http_host                     $http_host;
                    # [1] - Set Host value 
                    proxy_set_header Host                   $best_http_host;
                    ...
                    # Pass the extracted client certificate to the backend
                    ...
                    proxy_set_header                        Connection        $connection_upgrade;             
                    proxy_set_header X-Request-ID           $req_id;
                    proxy_set_header X-Real-IP              $remote_addr;
                    proxy_set_header X-Forwarded-For        $remote_addr;
                    proxy_set_header X-Forwarded-Host       $best_http_host;
                    ...  

whereas 'http_host' variable is created based on following "ngx_http_core_module" core functionality:

$http_name - arbitrary request header field; the last part of a variable name is the field name converted to lower case with dashes replaced by underscores

So described behavior is not anyhow unique to ASP.NET Core 3.0, you see unknown Dictionary containing key/value pairs of custom headers set explicitly by nginx controller, accordingly to nginx ingress current configuration, that's it.

You can inspect current nginx controller's configuration by your self with following command:

kubectl exec -it po/<nginx-ingress-controller-pod-name> -n <ingress-controller-namespace> -- cat /etc/nginx/nginx.conf

Q2: What's the best way to get at the original URL (https://my-app.com)?

I would try with constructing it using Configuration snippet, this is by introducing another custom header, where you concatenate values.

Upvotes: 1

Related Questions