Traefik & Keycloak: error SSL_ERROR_RX_RECORD_TOO_LONG - kubernetes

I use an HAProxy to redirect all requests from 80 port to a 443 and using a NodePort to enter on a traefik-ingress-controller (v1.6.6, inside a Kubernetes cluster).
Here the HAProxy.conf:
frontend http-frontend
bind *:80
reqadd X-Forwarded-Proto:\ http
default_backend http_app
frontend https-frontend
bind *:443 ssl crt /etc/ssl/certs/my-cert.pem
reqadd X-Forwarded-Proto:\ https
default_backend traefik_app
backend http_app
redirect scheme https if !{ ssl_fc }
backend traefik_app
server traefik localhost:30010 check
Every application running on my Kubernetes cluster has an Ingress.
Among them I have a Keycloak pod (v4.1.0, for the authentication) with this ingress:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: keycloak
annotations:
kubernetes.io/ingress.class: traefik
spec:
rules:
- host: login.myapp.it
http:
paths:
- backend:
serviceName: keycloak
servicePort: 8080
Here a picture:
When I connect to https://login.myapp.it/auth/admin/ I get redirected to
https://login.myapp.it:80/auth/admin/master/console/ (note the port 80) and I received an SSL_ERROR_RX_RECORD_TOO_LONG error.
Someone has some hints for this redirect issue with keycloak behind proxy?
Thank you in advance.

Sounds like you are missing your TLS certs on your ingress:
$ kubectl -n kube-system create secret tls your-k8s-tls-secret --key=tls.key --cert=tls.crt
Then:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: keycloak
annotations:
kubernetes.io/ingress.class: traefik
spec:
tls:
- secretName: your-k8s-tls-secret
rules:
- host: login.myapp.it
http:
paths:
- backend:
serviceName: keycloak
servicePort: 8080
Hope it helps!

I solved my issue using the following traefik annotation:
traefik.frontend.passHostHeader: "true"
that forwards client Host header to the backend.
Here a complete ingress example:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: keycloak
annotations:
kubernetes.io/ingress.class: traefik
traefik.frontend.passHostHeader: "true"
spec:
rules:
- host: login.myapp.it
http:
paths:
- backend:
serviceName: keycloak
servicePort: 8080
In alternative I may have added to haproxy.cfg the following:
reqadd X-Forwarded-Port:\ 443

Related

K8S traffic to one service via two separate ingress (http + https)

So I have a bunch of services running in a cluster, all exposed via HTTP only ingress object, example:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
name: some-ingress
spec:
ingressClassName: nginx
rules:
- http:
paths:
- backend:
service:
name: some-svc
port:
number: 80
path: /some-svc(/|$)(.*)
pathType: Prefix
They are accessed by http://<CLUSTER_EXTERNAL_IP>/some-svc, and it works ofc.
Now I want to create an additional ingress object for every service which will force SSL connections and allow the use of a domain instead of an IP address.
The problem is that the newer SSL ingresses always return 404 while testing the connection.
The manifests are as follows:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: "some-ingress-ssl"
annotations:
ingress.kubernetes.io/ssl-redirect: "true"
ingress.kubernetes.io/app-root: "/some-svc"
spec:
tls:
- hosts:
- foobar.com
secretName: foobar-tls
rules:
- host: foobar.com
http:
paths:
- path: /some-svc(/|$)(.*)
pathType: Prefix
backend:
service:
name: some-svc
port:
number: 80
tests (foobar.com point to CLUSTER_EXTERNAL_IP):
> curl -I http://<CLUSTER_EXTERNAL_IP>/some-svc
HTTP/1.1 200 OK
> curl -I https://foobar.com/some-svc
HTTP/2 404
Is it possible to have both ingresses simultaneously? (one enforcing SSL, the other not)
If so what am I doing wrong here?
Figured out I was missing this annotation:
nginx.ingress.kubernetes.io/rewrite-target: /$2
in SSL ingress...
works like a charm now, maybe someone will find this usefull

Ingress resource hostname

I have kube cluster & its control plane endpoint is haproxy. I want to use hostname of system where haproxy lies and use it as hostname in the ingress resource. Is it possible to achieve this. The request ha proxy backend config is below:
frontend k8s_frontend
bind *:6443
mode tcp
default_backend k8s_backend
backend k8s_backend
mode tcp
balance roundrobin
server master1 10.50.8.117:6443
server master2 10.50.8.118:6443
server master3 10.50.8.119:6443
frontend http_frontend
bind :80
bind :443 ssl crt /com.pem
default_backend servers
backend servers
balance roundrobin
server worker1 10.50.8.120:443 ssl verify none
server worker2 10.50.8.121:443 ssl verify none
Below is my ingress resource:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: dashboard-ingress
namespace: kubernetes-dashboard
annotations:
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
spec:
rules:
- host: "HAPROXY_HOSTNAME"
http:
paths:
- pathType: Prefix
path: "/k8s"
backend:
service:
name: kubernetes-dashboard
port:
number: 443
Yes, you can mention the hostname of HAProxy in the ingress source. The ingress controller node can be resolved as hostname along with deploying and exposing the echo server service as shown below. Kindly refer to this document.
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: haproxy
name: echoserver
spec:
rules:
host: $HOST
http:
paths:
backend:
serviceName: echoserver
servicePort: 8080
path: /
EOF
More details on HAProxy Ingress Controller can be found here.

Minikube | Ingress Service - Bad Request

I'm working on a single-node cluster which works fine with docker-compose but the reconfiguration of the same setup using Minikube Ingress Controller gives me a Bad Request response.
Bad Request
Your browser sent a request that this server could not understand.
Reason: You're speaking plain HTTP to an SSL-enabled server port.
Instead use the HTTPS scheme to access this URL, please.
My Ingress looks like this:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress-service
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
rules:
- http:
paths:
- path: /?(.*)
pathType: Prefix
backend:
service:
name: emr-cluster-ip-service
port:
number: 443
- path: /?(.*)
pathType: Prefix
backend:
service:
name: erp-cluster-ip-service
port:
number: 8069
How to fix this?
You are exposing HTTPS service on HTTP ingress, which is not the right thing to do. You might want to do one of the following:
Configure TLS-enabled ingress.
Configure TLS passthough on ingress object.
In both cases you also need to set nginx.ingress.kubernetes.io/ssl-redirect: "true"

Problem with SSL passthrough in Nginx Controller

I'm forced to use Nginx Ingress, but it's complicated and doesn't fulfill our requirements.
I tried to route traffic from Nginx ingress to Traefik, but it seems that redirection from HTTP to HTTPS doesn't work.
Here is how my Ingress looks like:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
name: some-ingress
spec:
tls:
- hosts:
- "example.com"
secretName: some-secret
rules:
- host: "example.com"
http:
paths:
- backend:
serviceName: traefik
servicePort: 443
I don't know how to fix that. I tried different ways. Maybe there is another way to route HTTP traffic on port 80 to traefik service on port 80 and 443 to traefik service on port 443 (?)
Unfortunately, I'm not able to use any external load balancer because it's not provided. I'm aware that there is something called MetalLB, but I'm not able to fulfill all requirements.
Thank you in advance!
Did you try to add the backend-protocol annotation?
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"

Access service via custom HTTPS port using nginx-ingress

When using nginx-ingress in Kubernetes, how can I define a custom port which should be used for HTTPS, instead of 443? My configuration looks as follows:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/tls-acme: "true"
creationTimestamp: "2019-04-17T14:15:25Z"
generation: 3
name: foo
namespace: foo
resourceVersion: "1535141"
selfLink: /apis/extensions/v1beta1/namespaces/foo/ingresses/foo
uid: f1b4dae9-6072-1239-a12a-fa161aff25ae
spec:
rules:
- host: example.com
http:
paths:
- backend:
serviceName: foo
servicePort: 80
path: /
tls:
- hosts:
- example.com
secretName: foo-ingress-tls
status:
loadBalancer:
ingress:
- {}
Preferably, I would like to be able to access the service via HTTPS on both the default 443 port and an additional custom port.
Unfortunately in ingress-nginx it is impossible to listen to more than one HTTPS port. You can change HTTPS port number using --https-port command line argument, but there can only be one HTTPS port.