jcmoraisjr / haproxy-ingress

HAProxy Ingress
https://haproxy-ingress.github.io
Apache License 2.0
1.04k stars 270 forks source link

ssl-passthrough ingress breaks others #598

Open tumbl3w33d opened 4 years ago

tumbl3w33d commented 4 years ago

Might be related to #492 but in this case it's not a missing feature but it actually breaks my setup when I add the ssl-passthrough ingress to other ones which "merge" properly.

My ingresses

---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: myproject-haproxy-soap-http
  namespace: myproject
  annotations:
    ingress.kubernetes.io/ssl-redirect: "false"
    ingress.kubernetes.io/hsts: "false"
spec:
  rules:
    - host: example.com
      http:
        paths:
          - path: /
            backend:
              serviceName: myproject-service
              servicePort: 80
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: myproject-haproxy-management
  namespace: myproject
  annotations:
    ingress.kubernetes.io/ssl-redirect: "false"
    ingress.kubernetes.io/hsts: "false"
    ingress.kubernetes.io/backend-protocol: "h1-ssl"
spec:
  rules:
    - host: example.com
      http:
        paths:
          - path: /management
            backend:
              serviceName: myproject-service
              servicePort: 8500

---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: myproject-haproxy-soap-tls
  namespace: myproject
  annotations:
    ingress.kubernetes.io/ssl-passthrough: "true"
spec:
  tls:
    - hosts:
      - example.com
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              serviceName: myproject-service
              servicePort: 443

Service

apiVersion: v1
kind: Service
metadata:
  name: myproject-service
  namespace: myproject
  annotations:
    haproxy.org/check: "disabled"
    haproxy.org/forwarded-for: "disabled"
spec:
  selector:
    customer: myproject
  ports:
    - name: soap-https
      protocol: TCP
      port: 443
      targetPort: 8443
    - name: soap-http
      protocol: TCP
      port: 80
      targetPort: 8081
    - name: management-http
      protocol: TCP
      port: 8500
      targetPort: 8500

Explanation:

With the first 2 ingresses the /etc/haproxy/maps/_front001_host.map looks like this

example.com/management myproject1_myproject-service_8500
example.com/ myproject1_myproject-service_8081

When the third ingress comes in, such file doesn't exist anymore. Instead, the port 80 frontend loads /etc/haproxy/maps/_global_http_front.map which is empty. So the effect is, that the formerly working http frontends are gone.

jcmoraisjr commented 4 years ago

Hi, ssl-passthrough was designed in such a way that, if configured, everything else is ignored due to the fact that a path cannot be extracted from the encrypted data. But http/:80 doesn't have this issue and could be configured if ssl-redirect is false. I'll have a look on this and perhaps merge to at least v0.10 depending on the amount of changes. Thanks for reporting.

tumbl3w33d commented 4 years ago

Edit: ignore this comment. Explanation in the next. ;)

Hi @jcmoraisjr , thank you for your quick response. I understand that the current ssl-passthrough approach comes with these limitations, but reading the explanation I'd like to extend the example to make sure we're on the same page about what HAProxy can achieve and it would be great if the ingress controller would strive for the same.

For the sake of completeness I'll post all 3 ingresses again with a modified version of the second

---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: myproject-haproxy-soap-http
  namespace: myproject
  annotations:
    ingress.kubernetes.io/ssl-redirect: "false"
    ingress.kubernetes.io/hsts: "false"
spec:
  rules:
    - host: example.com
      http:
        paths:
          - path: /
            backend:
              serviceName: myproject-service
              servicePort: 80
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: myproject-haproxy-management
  namespace: myproject
  annotations:
    ingress.kubernetes.io/ssl-redirect: "false"
    ingress.kubernetes.io/hsts: "false"
    ingress.kubernetes.io/backend-protocol: "h1-ssl"
spec:
  tls:
    - hosts:
        - example.com
      secretName: example-cert
  rules:
    - host: example.com
      http:
        paths:
          - path: /management
            backend:
              serviceName: myproject-service
              servicePort: 8500

---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: myproject-haproxy-soap-tls
  namespace: myproject
  annotations:
    ingress.kubernetes.io/ssl-passthrough: "true"
spec:
  tls:
    - hosts:
      - example.com
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              serviceName: myproject-service
              servicePort: 443

In this scenario there are pure http hosts (1st ingress), ssl hosts terminated by HAProxy (ingress 2) and ssl hosts passed through (ingress 3). And the currently generated configuration is not even far from delivering that.

Again, like in the first scenario, the setup works as expected as long as the third ingress with ssl-passthrough doesn't come in.

Since I'm new to k8s and the haproxy ingress controller - there's no way of working around this until it's handled properly, is there?

tumbl3w33d commented 4 years ago

I just realized that it cannot work to distinguish on the same port with the same hostname depending on the path because that information isn't part of the SNI header. My bad. In the setup from which I'm porting this I used a different port for that reason.