Http Redirect port loss in K8S Ingress environment
Recently, I found a problem: the application lost the original port when returning Http Redirect. For example, we visit http://IP-A:Port -A/app/delete, this url will respond to 302, but the response header Location returned by it has lost the port. The correct result should be as follows: http://IP-A:Port -A/app/index returns: http://IP-A/app/index , lost the port.
Basic information
Our deployment is as follows:
Deployed Nginx Ingress and exposed the Nginx Ingress Service by NodePort
Ingress with App configured
In fact, the above are not all servers. Two K8S services are not servers but VIPs. Please refer to the article K8S - Using Source IP for details http://IP-A:Port -When A/app/delete, the request runs through these servers from left to right.
By the way, the above NAT Server is an ordinary server. We use it to make PAT so that our Nginx Ingress can be accessed by the Internet.
observation
We use the Echo Server mentioned earlier to observe the request header passed to the Echo Server when accessing the Echo Server through Ingress: http://IP-A:Port -A/echo server gets these interesting Request header:
host=IP-A:Port-A
x-original-uri=/echo-server
x-forwarded-for=IP-B
x-forwarded-host=IP-A:Port-A
x-forwarded-port=80 x-forwarded-proto=http
Then directly access the Echo Server Svc and find that there is no x - * Request header mentioned above. So it is suspected that the problem lies in these headers.
Terminology
Tell me what these heads mean.
X-forwarded-for, when the client accesses the proxy, the client's IP address.
The reason why this is the IP address of the K8S node is that Nginx Ingress thinks that the request is from the K8S node (take a good look at the previous K8S - Using Source IP article). Before this, NAT was unknown.
X-forwarded-host refers to the original host that the client accesses when accessing the proxy.
X-forwarded-proto: When the client accesses the proxy, it accesses the original http scheme.
X-forwarded-port: the port that the client accesses when accessing the proxy.
X-original uri, no authoritative data can be found.
Note that the first three are factual standards, which are included in MDN. x-forwarded-port and x-original uri seem to be private extensions.
experiment
Find a handy Http Request tool (I use Postman), remember to turn off Follow Redirect, and then simulate Nginx requests (that is, bring/remove/modify the value of the x - * header mentioned above) to directly request the App Svc.
It is found that x-forwarded-port is the key to the response header location, that is, if x-forwarded-port=Port-A, the location will bring the correct port.
Analysis
How to construct the Redirect url
It can be inferred that the app uses the host and x-forwarded - * headers to construct the redirect url.
In the Java Servlet API, when describing HttpServletResponse # sendRedirect, it is mentioned that the returned URL must be Absolute URL.
Tomcat's org. apache. catalina. connector The toAbsolute method of the Response is responsible for constructing the Absolute URL.
How does it know which port to use? This is related to RemoteIPVave. If you are interested, you can consult the relevant documents.
The above only describes how Tomcat constructs the redirect url, but this method is not standard. Different containers have their own implementations. After all, the Java Servlet API does not specify how to construct the Absolute URL.
I also wrote an article on related topics before, "The reverse proxy uses the https protocol, the background tomcat uses http, and the solution to using the wrong protocol when redirecting". You can have a look.
Why x-forwarded-port is 80
Then the question arises. I clearly visited IP-A: Port-A. Why does Nginx get a value of 80?
This is because in the front section of the entire request link: NAT Server>K8S Node>Nginx Ingress Svc all work in Layer 4. It can be considered that everything they do is NAT. The Nginx Ingress Pod does not know the ports of these servers/network nodes, so it can only give its own port 80 (the port in the container) to the x-forwarding port.
You can see the Nginx Ingress configuration file about this logic:
kubectl -n kube-system exec -it -- cat /etc/nginx/nginx.conf
terms of settlement
Take x-forwarded-port when requesting (unreliable)
View the Nginx Ingress configuration file. It is found that if the initial request is made with an x-forward port, it can be changed to the following values. However, there are two problems:
You can't add this header when accessing through the browser
This header is generally added by a reverse proxy, that is, there must be a reverse proxy before our Nginx Ingress
So this method is not good.
Modify the code of tomcat (unreliable)
Although you can modify the code of tomcat to get the port from the x-forward-host/host header, this is unrealistic.
Modify the port of the NAT Server to 80 (reliable)
This method is reliable. As long as the port of the NAT Server is changed to 80, there is no problem.
In fact, if you directly access the K8S node (NodePort mode), you also need to set the NodePort to 80. Remember that? Nginx Ingress cannot know the port of the upper NAT.
In a word, the URL you originally requested cannot be a port other than 80, it must be http://some-ip/app Can only.
Basic information
Our deployment is as follows:
Deployed Nginx Ingress and exposed the Nginx Ingress Service by NodePort
Ingress with App configured
In fact, the above are not all servers. Two K8S services are not servers but VIPs. Please refer to the article K8S - Using Source IP for details http://IP-A:Port -When A/app/delete, the request runs through these servers from left to right.
By the way, the above NAT Server is an ordinary server. We use it to make PAT so that our Nginx Ingress can be accessed by the Internet.
observation
We use the Echo Server mentioned earlier to observe the request header passed to the Echo Server when accessing the Echo Server through Ingress: http://IP-A:Port -A/echo server gets these interesting Request header:
host=IP-A:Port-A
x-original-uri=/echo-server
x-forwarded-for=IP-B
x-forwarded-host=IP-A:Port-A
x-forwarded-port=80 x-forwarded-proto=http
Then directly access the Echo Server Svc and find that there is no x - * Request header mentioned above. So it is suspected that the problem lies in these headers.
Terminology
Tell me what these heads mean.
X-forwarded-for, when the client accesses the proxy, the client's IP address.
The reason why this is the IP address of the K8S node is that Nginx Ingress thinks that the request is from the K8S node (take a good look at the previous K8S - Using Source IP article). Before this, NAT was unknown.
X-forwarded-host refers to the original host that the client accesses when accessing the proxy.
X-forwarded-proto: When the client accesses the proxy, it accesses the original http scheme.
X-forwarded-port: the port that the client accesses when accessing the proxy.
X-original uri, no authoritative data can be found.
Note that the first three are factual standards, which are included in MDN. x-forwarded-port and x-original uri seem to be private extensions.
experiment
Find a handy Http Request tool (I use Postman), remember to turn off Follow Redirect, and then simulate Nginx requests (that is, bring/remove/modify the value of the x - * header mentioned above) to directly request the App Svc.
It is found that x-forwarded-port is the key to the response header location, that is, if x-forwarded-port=Port-A, the location will bring the correct port.
Analysis
How to construct the Redirect url
It can be inferred that the app uses the host and x-forwarded - * headers to construct the redirect url.
In the Java Servlet API, when describing HttpServletResponse # sendRedirect, it is mentioned that the returned URL must be Absolute URL.
Tomcat's org. apache. catalina. connector The toAbsolute method of the Response is responsible for constructing the Absolute URL.
How does it know which port to use? This is related to RemoteIPVave. If you are interested, you can consult the relevant documents.
The above only describes how Tomcat constructs the redirect url, but this method is not standard. Different containers have their own implementations. After all, the Java Servlet API does not specify how to construct the Absolute URL.
I also wrote an article on related topics before, "The reverse proxy uses the https protocol, the background tomcat uses http, and the solution to using the wrong protocol when redirecting". You can have a look.
Why x-forwarded-port is 80
Then the question arises. I clearly visited IP-A: Port-A. Why does Nginx get a value of 80?
This is because in the front section of the entire request link: NAT Server>K8S Node>Nginx Ingress Svc all work in Layer 4. It can be considered that everything they do is NAT. The Nginx Ingress Pod does not know the ports of these servers/network nodes, so it can only give its own port 80 (the port in the container) to the x-forwarding port.
You can see the Nginx Ingress configuration file about this logic:
kubectl -n kube-system exec -it
terms of settlement
Take x-forwarded-port when requesting (unreliable)
View the Nginx Ingress configuration file. It is found that if the initial request is made with an x-forward port, it can be changed to the following values. However, there are two problems:
You can't add this header when accessing through the browser
This header is generally added by a reverse proxy, that is, there must be a reverse proxy before our Nginx Ingress
So this method is not good.
Modify the code of tomcat (unreliable)
Although you can modify the code of tomcat to get the port from the x-forward-host/host header, this is unrealistic.
Modify the port of the NAT Server to 80 (reliable)
This method is reliable. As long as the port of the NAT Server is changed to 80, there is no problem.
In fact, if you directly access the K8S node (NodePort mode), you also need to set the NodePort to 80. Remember that? Nginx Ingress cannot know the port of the upper NAT.
In a word, the URL you originally requested cannot be a port other than 80, it must be http://some-ip/app Can only.
Related Articles
-
A detailed explanation of Hadoop core architecture HDFS
Knowledge Base Team
-
What Does IOT Mean
Knowledge Base Team
-
6 Optional Technologies for Data Storage
Knowledge Base Team
-
What Is Blockchain Technology
Knowledge Base Team
Explore More Special Offers
-
Short Message Service(SMS) & Mail Service
50,000 email package starts as low as USD 1.99, 120 short messages start at only USD 1.00