ingress nginx - proxy to external URL - nginx

I search (since many days ...) How to use Ingress Nginx in order to use External url as backend.
Yes I use Service object with externalName. I also test many many directive in nginx without succes...
The goal is simple:
user can resolv and join only my public URL (url-public.com & url-public-2.com)
I want to send request to external backend than is out of my control and cluster (url-ext.com)
My ingress can resolv url-ext.com, user cannot. Of course, url-ext.com have here proper certificat and is expose as HTTPS ;).
Nota : My ingress expose 2 url, but I don't think this is important.
My Code :
Service :
kind: Service
apiVersion: v1
metadata:
name: external-eip
namespace: external-url
spec:
type: ExternalName
externalName: url-ext.com
Ingress :
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: external-eip
namespace: external-url
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
nginx.ingress.kubernetes.io/upstream-vhost: "url-ext.com"
nginx.ingress.kubernetes.io/configuration-snippet: |
# more_clear_input_headers "Host" "X-Forwarded-Host";
more_set_input_headers 'Host: url-ext.com';
proxy_set_header Host url-ext.com;
spec:
rules:
- host: url-public.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: external-eip
port:
number: 443
- host: url-public-2.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: external-eip
port:
number: 443
Result (curl or Browser access ) :
<html>
<head><title>504 Gateway Time-out</title></head>
<body>
<center><h1>504 Gateway Time-out</h1></center>
<hr><center>nginx</center>
</body>
</html>
And Ingress Log :
2021/08/06 21:44:45 [error] 10873#10873: *2914631 upstream timed out (110: Operation timed out) while connecting to upstream, client: 10.203.65.14, server: url-public.com, request: "GET / HTTP/2.0", upstream: "https://10.203.64.5:443/", host: "url-ext.com"
10.203.64.5 is the real IP of url-ext.com.
And, curl https://10.203.64.5:443/ -k -v -H "Host: url-ext.com" work.
Don't ask me "why using this annotation", I don't know :p many Google search and many test ...
So, what is the correct ingress configuration for using externalName, when this externalName is (probably) under RP also ?
Nota : Rewrite and other redirect not work, because it rewrite user location and I don't want it. User canno't acces and resolv url-ext.com, only url-public.com.
Br, Thanks

Reply to my self. The problem was my Ingress (and all my K8S cluster) is under HTTP Squid proxy.
I have mounted all env variable for proxy but it seems the Ingress container doesn't use it ...
So, to get it working, I allow my cluster to outbound 80/443 ports to the destination.
You just need this annotation:
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
nginx.ingress.kubernetes.io/upstream-vhost: "url-ext.com"
But, if any of you know how to setup my Ingress to use my HTTP proxy, I will need it.
br

Related

How to configure Ingress backend to work exclusively with TLSv1.3

I have an ingress (nginx) that proxies to an application exposing 8443 (SSL) with a self-signed certificate. It works all fine in http but in https I get the following error:
2022/10/31 18:04:28 [error] 39#39: *1855 SSL_do_handshake() failed (SSL: error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version:SSL alert number 70) while SSL handshaking to upstream, client: 127.0.0.1, server: _, request: "GET /web-service/ HTTP/2.0", upstream: "https://10.2.1.37:8443/web-service/", host: "localhost:8443"
After a little bit of research I established that my web-service is only supporting:
"TLSv1.3" and "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256:TLS_AE"
I curled in and indeed if I use anything else than explicitly TLSv1.3 I get a similar error. I also force the web service to downgrade to TLSv1.2 and it works but obviously that's not great.
Is there a way to configure the ingress nginx backend configuration to only use TLSv1.3 and these protocols in the ingress itself.
Something like ssl_protocols TLSv1.3; but as an annotation at the backend level? I tried a snippet but it does not seem to be applied at the right level.
Here is my current code:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hello-world-ingress2
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "false"
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
nginx.ingress.kubernetes.io/secure-backends: "true"
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/auth-tls-verify-client: "off"
nginx.ingress.kubernetes.io/rewrite-target: /web-service/$1
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /web-service/(.*)
pathType: Prefix
backend:
service:
name: my-web-service
port:
number: 8443
Seems you need to add configMap to change the default behavior.
See at the end of following link:
https://kubernetes.github.io/ingress-nginx/user-guide/tls/#default-tls-version-and-ciphers
So apparently there is no solution at the writing this but to downgrade the backend to TLS v1.2. See open ticket https://github.com/kubernetes/ingress-nginx/issues/8257

Kubernetes Nginx Ingress - Rewrite Dynamic URL

Here i have kubernetes running on minikube and it has 2 services backend and frontend. And i have installed ingress addon for minikube.
I wanted to rewrite whenever the frontend request the path url is /users/{user-id} it goes to backend service with the same url dynamically.
Let say the request is /users it rewrite to backend service to /users, /users/1 it goes to /users/1.
I tried to read nginx manual found some special expression i don't understand.
This is my ingress configuration.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-be
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /users/$1
spec:
ingressClassName: nginx
rules:
- host: backend
http:
paths:
- path: /users/(.*)
pathType: Prefix
backend:
service:
name: backend
port:
number: 5000
My configuration seems fine when the request is /users/{users-id} but when the request is /users, my ingress won't redirect me to '/users' in backend service.
When i tested with curl, this is the output.
curl http://backend/users/3
{"id":3,"name":"Sofia","email":"sofia#gmail.com","gender":"Female","createdAt":"2022-04-05T15:46:46.000Z","updatedAt":"2022-04-05T15:46:46.000Z"}%
curl http://backend/users
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>
What am i missing here?
Thank you in advance for your help!
Update!
Andreas in the comment suggest me to use /users/ and it works!
Then i decided to modified my ingress configuration.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-be
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /users/$2
spec:
ingressClassName: nginx
rules:
- host: backend
http:
paths:
- path: /users(/|$)(.*)
pathType: Prefix
backend:
service:
name: backend
port:
number: 5000

Can you set backend-protocol per rule in k8s nginx ingress?

I have a kubernetes cluster setup with two services set up.
Service1 links to Deployment1 and Service2 links to Deployment2.
Deployment1 serves pods which can only be connected to using http.
Deployment2 serves pods which can only be connected to using https.
Using kubectl port-forward and exec'ing into pods I know the services and deployments are responding as they should, connectivity internally between the services is working fine.
I have an nginx ingress setup to allow external connections to both services. The services should only be connected to using https and any incoming connections that are http need to be redirected to https. Here is the ingress setup:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: master-ingress
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/ssl-redirect: "true"
cert-manager.io/cluster-issuer: "letsencrypt-production"
spec:
tls:
- secretName: tls-secret-one
hosts:
- service1.domain.com
- service2.domain.com
rules:
- host: "service1.domain.com"
http:
paths:
- path: /
backend:
serviceName: service1
servicePort: 60001
- host: "service2.domain.com"
http:
paths:
- path: /
backend:
serviceName: service2
servicePort: 60002
Here is the problem. With this yaml I can connect to service1 (http backend) with no issues but connecting to service2 (https backend) results in a 502 Bad Gateway.
If I add the annotation ' nginx.ingress.kubernetes.io/backend-protocol: "https" ' the connectivity switches. I can no longer connect to service1 (http backend) but can connect to service2 (https backend)
I can understand why the switch does this, but my question is:
Can you set the backend-protocol per rule in an nginx-ingress ?
It's not possible to set backend protocol per rule in a single ingress. To achieve what you want you can create two different ingress one for service1 and another one for service2 and annotate the ingress for service1 with http and ingress for service2 with https.

Nginx Ingress - how to set redirect to external site if there is no matching route?

beginner here. I am currently trying to configure Ingress to do two things - if the fibonacci route exists, redirect to the function and pass the parameter, if the route doesn't exist, redirect to another website and attach the input there.
So, for example, there are two basic scenarios.
https://xxx.amazonaws.com/fibonacci/10 -> calls fibonacci function with parameter 10 (that works)
https://xxx.amazonaws.com/users/jozef -> calls redirect function which redirects to https://api.github.com/users/jozef
I think the service doing the redirect is written correctly, it looks like this.
kind: Service
apiVersion: v1
metadata:
name: api-gateway-redirect-service
spec:
type: ExternalName
externalName: api.github.com
ports:
- protocol: TCP
targetPort: 443
port: 80 # Default port for image
This is how my Ingress looks like. Experimented with default-backend annotation as well as various placement of the default backend, nothing worked. When I try to curl https://xxx.amazonaws.com/users/jozef, I keep getting 301 message but the location is unchanged. The final output looks like this
HTTP/1.1 301 Moved Permanently
Server: openresty/1.15.8.2
Date: Wed, 13 Nov 2019 15:52:14 GMT
Content-Length: 0
Connection: keep-alive
Location: https://xxx.amazonaws.com/users/jozef
* Connection #0 to host xxx.amazonaws.com left intact
* Maximum (50) redirects followed
curl: (47) Maximum (50) redirects followed
Does someone have an idea what am I doing wrong? This is my Ingress. Also, if it helps, we use Kubernetes version 1.14.6. Thanks a million
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-nginx
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "false"
nginx.ingress.kubernetes.io/force-ssl-redirect: "false"
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- http:
paths:
- path: /fibonacci/(.*)
backend:
serviceName: fibonacci-k8s-service
servicePort: 80
- path: /(.*)
backend:
serviceName: api-gateway-redirect-service
servicePort: 80
The resolution to the problem was the addition of the 'Host: hostname' header in the curl command.
The service that was handling the request needed Host: hostname header to properly reply to this request. After the hostname header was provided the respond was correct.
Links:
Curl docs
Ingress docs
So I ve kept reading about this subject and it turns out that ingress controllers generally don't go through services but connect to pods directly (it looks up pods selected by the service and configures them into nginx), wich makes the use case here (connecting to the serice that isn't backed up by anypod) destined to fail.
HOWEVER, it looks like that in recent version this has been supported by nginx ingress controller with nginx+ ONLY so far.
references:
Support for Type ExternalName Services
Ingress uses Endpoints to configure PODs Ips in nginx config to load balance

Is it possible to rewrite HOST header in k8s Ingress Controller?

Due to some legacy application that relies on Host header to function correctly, I need to have an Ingress (proxy, etc) that capable of rewrite Host header and pass that to downstream (backend). Is there any Ingress Controller that supports this functionality?
Example:
End user access our website through foo.com/a for backend a and foo.com/b for backend b. But since a and b are legacy app, it only accept:
a accepts connection when Host: a.foo.com
b accepts connection when Host: b.foo.com
This can be done using this annotation: nginx.ingress.kubernetes.io/upstream-vhost: host.example.com
I'm not sure whether you can find appropriate annotation within NGINX Ingress Controller for Host header modification to match your requirement as well. However, you can consider using nginx.ingress.kubernetes.io/configuration-snippet annotation in order to append configuration snippet to the location block inside nginx.conf of the particular Nginx controller pod:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header Host www.example-host.com;
name: my-app
spec:
rules:
- host: my-app.example.com
http:
paths:
- backend:
path: /app
serviceName: my-app
servicePort: http
We set here Host header www.example-host.com for target URL my-app.example.com.
I want to add my finding to this question of mine.
Although my solution is not using k8s Ingress Controller, our cluster is using Istio and Istio's VirtualService supports rewrite the uri and authority (Host header) as documented in this link: https://istio.io/docs/reference/config/istio.networking.v1alpha3/#HTTPRewrite
To know how I implement that in my case, you can take a look at this link: https://github.com/istio/istio/issues/11668
you can use ingress nginx controller on Kubernetes and set head and also transfer to backend and manage services connection from ingress objects.
here sharing link for rewrite target from header: https://kubernetes.github.io/ingress-nginx/examples/rewrite/
ingress nginx will be also good with SSL cert manager you can add it.
manage other thing using annotations of ingress.
check this out for ingress SSL setup you can modify it and per your need: https://www.digitalocean.com/community/tutorials/how-to-set-up-an-nginx-ingress-with-cert-manager-on-digitalocean-kubernetes
ingress will be like at last
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
tls:
- hosts:
- myapp.abc.com
secretName: ingress-tls
rules:
- host: myapp.abc.com
http:
paths:
- path: /my-service
backend:
serviceName: my-backend
servicePort: 80

Resources