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

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

Related

ingress nginx - proxy to external URL

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

GKE ingress pass cookie as header

I would like to use some kubernetes ingress (doesn't matter the ingress type) on google cloud GKE 1.19.7-gke.1302, and nginx ingress deployed by nginx-ingress-0.8.0 helm chart, and my need is to fetch a cookie and use it later to authenticate to our service. When I use nginx as deployment it works, but when I use nginx ingress it seems to ignore the annotation.
I tried using this configuration snippet for the nginx ingress, which works on the nginx deployment but not on the ingress:
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header "Authorization" "Basic $cookie_myToken";
And this is my entire ingress yaml:
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-nginx-ingress
namespace: default
annotations:
kubernetes.io/ingress.class: nginx
# enable backend redirections
kubernetes.io/tls-acme: "true"
# enable stickiness
nginx.ingress.kubernetes.io/affinity: "cookie"
nginx.ingress.kubernetes.io/session-cookie-name: "route"
nginx.ingress.kubernetes.io/session-cookie-expires: "172800"
nginx.ingress.kubernetes.io/session-cookie-max-age: "172800"
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header "Authorization" "Basic $cookie_myToken";
spec:
tls:
- secretName: my-tls
hosts:
- "test.com"
defaultBackend:
service:
name: my-nodeport
port:
number: 80
rules:
- host: "test.com"
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: my-nodeport
port:
number: 80
Any ideas?
Posting this answer to make it more visible as issue was identified and solved in comment section.
Root cause of this issue was Nginx Ingress Controller misconfiguration.
In the OP's setup Nginx Ingress Controller, v.0.8.0 was used. After redeploying Nginx Ingress to latest version (v0.44.0) from Nginx Ingress Documentation it started working properly.
Yes, reinstalling nginx ingress to the latest version with helm solved the problem.

Hostname (SNI) missing while using nginx ingress SSL Passtrough to underlying service

I'm trying to implement SSL Passtrough with nginx-ingress-controller. This is my Ingress Object:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/backend-protocol: HTTPS
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
labels:
my-label: example
name: example
namespace: example
spec:
rules:
- host: '*.example.com'
http:
paths:
- backend:
serviceName: example
servicePort: 8443
path: /
The --enable-ssl-passtrough flag is present in the controller args.
When request is coming trough ingress controller to my underlying service I'm trying to parse the SNI to find out what domain was used to find out the certificate I should present, but the service cannot find the SNI and returns this error:
{"level":"debug","ts":1592992137.1836417,"msg":"Error getting server name","error":"No hostname"}
Does nginx-ingress-controller remove the SNI when parsing? Or what may be the reason for such behavior?
Thanks in advance for help
I contacted nginx-ingress developers directly and I got information that the reason this is not working is the wildcard domain, which is not supported by nginx-ingress.
Everything else is configured correctly and when changing *.example.com into something specific (e.g. whatever.example.com) it works correctly.

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

Kubernetes ingress-nginx - How can I disable listening on https if no TLS configured?

I'm using kubernetes ingress-nginx and this is my Ingress spec. http://example.com works fine as expected. But when I go to https://example.com it still works, but pointing to default-backend with Fake Ingress Controller certificate. How can I disable this behaviour? I want to disable listening on https at all on this particular ingress, since there is no TLS configured.
kind: Ingress
apiVersion: extensions/v1beta1
metadata:
name: http-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: example.com
http:
paths:
- backend:
serviceName: my-deployment
servicePort: 80
I've tried this nginx.ingress.kubernetes.io/ssl-redirect: "false" annotation. However this has no effect.
I'm not aware of an ingress-nginx configmap value or ingress annotation to easily disable TLS.
You could remove port 443 from your ingress controllers service definition.
Remove the https entry from the spec.ports array
apiVersion: v1
kind: Service
metadata:
name: mingress-nginx-ingress-controller
spec:
ports:
- name: https
nodePort: NNNNN
port: 443
protocol: TCP
targetPort: https
nginx will still be listening on a TLS port, but no clients outside the cluster will be able to connect to it.
Redirection is not involved in your problem.
ingress-controller is listening on both port, 80 and 443. When you configure an ingress with only 80 port, if you reach the 443 port you are redirected to the default backend, which is expected behaviour.
A solution is to add an other nginx-controller, that will only listen on 80 port. And then you can configure your ingresses with kubernetes.io/ingress.class: myingress.
When creating the new nginx-controller, change the command --ingress-class=myingress of the daemonset. It will then handle only ingress annotated with this class.
If you use helm to deploy it, simply override the controller.ingressClass value.

Resources