I'm running k8s with nginx ingress. It's pointing https://www.example.com/app at some pod with rewrite "/app" to "/", app listen 80 and serves "/":
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
labels:
app: example
name: example
namespace: default
spec:
rules:
- host: www.example.com
http:
paths:
- backend:
serviceName: app
servicePort: 80
path: /app
- backend:
serviceName: app
servicePort: 80
path: /app/
tls:
- hosts:
- www.example.com
secretName: example-tls
If i'm going to https://www.example.com/app request passed to pod and pod responded with another URL (/content for example), and my browser shows me https://www.example.com/content - it's 404, because there is no ingress rule for "/content". AFAIK nginx can rewrite response with sub_filter. Another way is to develop app with some configurable path prefix. Also i can use base_url, but only with html. But is there simple way to pass prefix in return, so if pod return "/content" nginx rewrites it to https://www.example.com/app/content
Thank you.
But is there simple way to pass prefix in return, so if pod return "/content" nginx rewrites it to https://www.example.com/app/content
No, there is no simple way to make it by Ingress rules.
It is possible by Nginx itself, but not implemented in Nginx-Ingress.
I highly recommend you to return the right path from the application.
Related
I have a pod that exposes an HTTP service.
This pod has some HTTP endpoints which are available under /accounts.
My goal is to access this sub-path via accounts.example.com.
For example if the url accounts.example.com/test is requested, the nginx ingress should route the request to /accounts/test on my pod.
In the nginx ingress documentation I cannot find a use-case with examples like this.
You should use rewrite to accomplish your request.
https://kubernetes.github.io/ingress-nginx/examples/rewrite/
Here is an example:
Focus on this line: path: /something(/|$)(.*)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
name: rewrite
namespace: default
spec:
rules:
- host: rewrite.bar.com
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /something(/|$)(.*)
Look on the different annotations for the re-write:
When I use nginx as ingress controller for my k8s cluster, specifying an ingress rule automatically creates corresponding configurations in the /etc/nginx/conf.d/ files of nginx pod.
So, it configures proxy_pass directive there to relevant upstream/backend service. And it is http.
For this ingress rule for my service:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: my-ingress
# annotations:
# nginx.org/redirect-to-https: "false"
# #nginx.ingress.kubernetes.io/ssl-passthrough: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- test.myapp.com
secretName: test-tls-secret
rules:
- host: test.myapp.com
http:
paths:
- backend:
serviceName: myui
servicePort: 80
- path: /api/
backend:
serviceName: myapp
servicePort: 88
By default, it automatically creates this directive for backend in nginx configuration:
proxy_pass http://default-my-ingress-test.myapp.com-myapp-88;
But instead, i need it to be https like this:
proxy_pass https://default-my-ingress-test.myapp.com-myapp-88;
Then only my application will work as that backend accepts https requests only.
Is there any way to modify that proxy_pass directive for a particular backend service for this purpose, using any annotations or something like that via Ingress resource?
EDIT:
Is there any annotation like that available?
Or Is there any option that I could handle it with a sidecar container in the same pod with the actual myapp container?
I had a similar requirement very recently where the backend pods expected the request on https.
What you'd need is ssl-passthrough feature of nginx controller. You need to start the nginx ingress controller with flag --enable-ssl-passthrough. This can be passed as a command line argument to the nginx deployment.
Thereafter, the ingress resource needs to be deployed with the following annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
nginx.ingress.kubernetes.io/secure-backends: "true"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
to instruct the controller to send TLS connections directly to the backend.
how do I achieve something similar to this.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
ingress.kubernetes.io/rewrite-target: /c/{word-maching-wildcard}
name: some-route
namespace: prod
spec:
rules:
- host: "*.example.com" # {hello}.example.com -> hello.example.com/hello
http:
paths:
- backend:
serviceName: svc
servicePort: 8080
path: /
Is there any way to capture the matching word in the subdomain and append it in the path before routing to the upstream service.
From the official doc:
Regular expressions and wild cards are not supported in the
spec.rules.host field. Full hostnames must be used.
See: nginx-ingress-matching.
However I have found similar problem which advice to write your own controller that writes out an nginx config that uses $http_host in the appropriate proxy_pass or redirect lines.
Read more: wildcard-url-mapping.
I have setup as below:
One kubernetes cluster with nginx ingress for deployment A. Ingress to deployment has configuration for host example.com. I want abc.com to point to example.comusing CNAME but its always throwing SSL error.
If I understand you correctly you need to use Rewrite annotations.
See the example below:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
name: rewrite
namespace: default
spec:
rules:
- host: rewrite.bar.com
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /something(/|$)(.*)
In this ingress definition, any characters captured by (.*) will be
assigned to the placeholder $2, which is then used as a parameter in
the rewrite-target annotation. For example, the ingress definition
above will result in the following rewrites:
- rewrite.bar.com/something rewrites to rewrite.bar.com/
- rewrite.bar.com/something/ rewrites to rewrite.bar.com/
- rewrite.bar.com/something/new rewrites to rewrite.bar.com/new
Please let me know if that helped.
EDIT:
More options:
create additional Ingresses
use HTTP (80) and generate SSL certificates
Use case
I deployed the nginx ingress controller in my Kubernetes cluster using this helm chart:
https://github.com/helm/charts/tree/master/stable/nginx-ingress
I created an ingress resource for my frontend serving webserver and it is supposed to redirect from non-www to the www version. I am using SSL as well.
The problem
When I visit the www version of my website everything is fine and nginx serves the page using my Lets Encrypt SSL certificate (which exists as secret in the right namespace). However when I visit the NON-www version of the website I get the failing SSL certificate page in my Browser (NET::ERR_CERT_AUTHORITY_INVALID) and one can see the page is served using the Kubernetes ingress fake certificate. I assume that's also the reason why the redirect to the www version does not work at all.
This is my ingress resource (actual hostnames have been redacted):
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
creationTimestamp: 2018-10-03T19:34:41Z
generation: 3
labels:
app: nodejs
chart: nodejs-1.0.1
heritage: Tiller
release: example-frontend
name: example-frontend
namespace: microservices
resourceVersion: "5700380"
selfLink: /apis/extensions/v1beta1/namespaces/microservices/ingresses/example-frontend
uid: 5f6d6500-c743-11e8-8aaf-42010a8401fa
spec:
rules:
- host: www.example.io
http:
paths:
- backend:
serviceName: example-frontend
servicePort: http
path: /
tls:
- hosts:
- example.io
- www.example.io
secretName: example-frontend-tls
The question
Why doesn't nginx use the provided certificate on the non-www version as well?
Looks like you fixed the issue for receiving an invalid certificate by adding an additional rule.
The issue with the redirect looks like it's related to this and it's not fixed as of this writing. However, there is a workaround as described on the same link:
nginx.ingress.kubernetes.io/configuration-snippet: |
if ($host = 'foo.com' ) {
rewrite ^ https://www.foo.com$request_uri permanent;
}
I fixed it by adding the non www version to the rules. The redirect still doesn't work, but the page is served using the correct SSL certificate though.
- host: example.io
http:
paths:
- backend:
serviceName: example-frontend
servicePort: http
path: /