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:
Scheme == "http"Host.Value == "my-app.com"IsHttps == FalseThis is weird:
Scheme (and IsHttps), it seems the HttpRequest object describes the forwarded request from the ingress to the pod, the one that goes over plain HTTP. However, why isn't Host.Value equal to 10.0.0.1 in that case?HttpRequest is trying to be clever and represent the original request, the one to the ingress, why doesn't it show "https" along with "my-app.com"?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.
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: httpsI'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.
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.confQ2: 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.