Skip to content

How can I configure ingress for server-proto h1 and h2 depending to Content-Type header #747

@GuillaumeSmaha

Description

@GuillaumeSmaha

Hi,

I have one backend able to handle http and gRPC . I have only one URL to access this backend and depending of the header "Content-type", it is able to process http or gRPC requests.

I tried to configure one or 2 Kubernetes ingresses by defining server-proto: h1 and server-proto: h2 but I was not able to make it work because they have the same URL for 2 ingresses.

I am wondering if is there a way to implement it that I am not aware ?

Without finding a solution based on the current annotation, I made a workaround change on the ingress code to duplicate the entries: one for h1 and one for h2 when the annotation server-proto is equal to h1,h2

You can see the implementation details here:
GuillaumeSmaha@309a365

It is more a workaround/PoC, so I didn't made a PR for it.

With the following Kubernetes ingress (based on the latest version v3.1.14):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    haproxy.org/check: "true"
    haproxy.org/check-http: /health/live
    haproxy.org/check-interval: 1m
    haproxy.org/forwarded-for: "true"
    haproxy.org/ingress.class: haproxy
    haproxy.org/load-balance: roundrobin
    haproxy.org/ssl-passthrough: "false"
    haproxy.org/ssl-redirect-port: "443"
    haproxy.org/standalone-backend: "true"
    haproxy.org/server-proto: "h1,h2"
  name: myapp
  namespace: default
spec:
  rules:
  - host: myapp.com
    http:
      paths:
      - backend:
          service:
            name: myapp
            port:
              number: 80
        path: /
        pathType: ImplementationSpecific
  - host: '*.myapp.com'
    http:
      paths:
      - backend:
          service:
            name: myapp
            port:
              number: 80
        path: /
        pathType: ImplementationSpecific
  tls:
  - hosts:
    - myapp.com
    - '*.myapp.com'
    secretName: tls-myapp

It is generating the following configuration:
generated-haproxy.cfg.txt

$ cat /etc/haproxy/haproxy.cfg


frontend http
  mode http
  bind 0.0.0.0:8080 name v4
  bind [::]:8080 name v6
  http-request set-var(txn.base) base
  http-request set-var(txn.path) path
  http-request set-var(txn.host) req.hdr(Host),field(1,:),lower
  http-request set-var(txn.host_match) var(txn.host),map(/etc/haproxy/maps/host.map)
  http-request set-var(txn.host_match) var(txn.host),regsub(^[^.]*,,),map(/etc/haproxy/maps/host.map,'') if !{ var(txn.host_match) -m found }
  http-request set-var(txn.is_h2c) str(true) if { req.hdr(Content-Type) -m sub application/grpc }
  http-request set-var(txn.path_match) var(txn.host_match),concat(,txn.path,),map(/etc/haproxy/maps/path-exact.map)
  http-request set-var(txn.path_match) var(txn.host_match),concat(,txn.path,),map(/etc/haproxy/maps/path-prefix-exact-h2.map) if { var(txn.is_h2c) -m str true } !{ var(txn.path_match) -m found }
  http-request set-var(txn.path_match) var(txn.host_match),concat(,txn.path,),map_beg(/etc/haproxy/maps/path-prefix-h2.map) if { var(txn.is_h2c) -m str true } !{ var(txn.path_match) -m found }
  http-request set-var(txn.path_match) var(txn.host_match),concat(,txn.path,),map(/etc/haproxy/maps/path-prefix-exact.map) if !{ var(txn.path_match) -m found }
  http-request set-var(txn.path_match) var(txn.host_match),concat(,txn.path,),map_beg(/etc/haproxy/maps/path-prefix.map) if !{ var(txn.path_match) -m found }
  http-request redirect location https://%[hdr(host),field(1,:)]:443%[capture.req.uri] code 302 if { var(txn.path_match) -m dom dbe4b28f9c4404fc36a7ae76ead9a37d }
  http-request redirect location https://%[hdr(host),field(1,:)]:8443%[capture.req.uri] code 302 if { var(txn.path_match) -m dom 92afcf7456e1a884dd198b1f8bfb6f63 }
  use_backend %[var(txn.path_match),field(1,.)]
  default_backend default_svc_default-local-service_http

frontend https
  mode http
  bind 0.0.0.0:8443 name v4 crt /etc/haproxy/certs/frontend ssl alpn h2,http/1.1
  bind [::]:8443 name v6 crt /etc/haproxy/certs/frontend ssl alpn h2,http/1.1
  bind [email protected]:8443 name quicv4 crt /etc/haproxy/certs/frontend ssl alpn h3
  bind quic6@[::]:8443 name quicv6 crt /etc/haproxy/certs/frontend ssl alpn h3
  http-request set-var(txn.base) base
  http-request set-var(txn.path) path
  http-request set-var(txn.host) req.hdr(Host),field(1,:),lower
  http-request set-var(txn.host_match) var(txn.host),map(/etc/haproxy/maps/host.map)
  http-request set-var(txn.host_match) var(txn.host),regsub(^[^.]*,,),map(/etc/haproxy/maps/host.map,'') if !{ var(txn.host_match) -m found }
  http-request set-var(txn.is_h2c) str(true) if { req.hdr(Content-Type) -m sub application/grpc }
  http-request set-var(txn.path_match) var(txn.host_match),concat(,txn.path,),map(/etc/haproxy/maps/path-exact.map)
  http-request set-var(txn.path_match) var(txn.host_match),concat(,txn.path,),map(/etc/haproxy/maps/path-prefix-exact-h2.map) if { var(txn.is_h2c) -m str true } !{ var(txn.path_match) -m found }
  http-request set-var(txn.path_match) var(txn.host_match),concat(,txn.path,),map_beg(/etc/haproxy/maps/path-prefix-h2.map) if { var(txn.is_h2c) -m str true } !{ var(txn.path_match) -m found }
  http-request set-var(txn.path_match) var(txn.host_match),concat(,txn.path,),map(/etc/haproxy/maps/path-prefix-exact.map) if !{ var(txn.path_match) -m found }
  http-request set-var(txn.path_match) var(txn.host_match),concat(,txn.path,),map_beg(/etc/haproxy/maps/path-prefix.map) if !{ var(txn.path_match) -m found }
  http-request redirect scheme https unless { ssl_fc }
  http-request set-header X-Forwarded-Proto https
  use_backend %[var(txn.path_match),field(1,.)]
  default_backend default_svc_default-local-service_http
  http-response set-header alt-svc "h3=\":443\";ma=60;"

frontend stats
  mode http
  bind :::1024 name v6
  bind *:1024 name stats
  stats enable
  stats uri /
  stats refresh 10s
  stats show-legends
  http-request set-var(txn.base) base
  http-request use-service prometheus-exporter if { path /metrics }

backend default_myapp_h2_svc_myapp_http
  mode http
  balance roundrobin
  option forwardfor
  no option abortonclose
  option httpchk /health/live
  default-server check inter 60000 proto h2
  server SRV_1 10.210.4.172:8080 enabled
  server SRV_2 127.0.0.1:1 disabled

backend default_myapp_svc_myapp_http
  mode http
  balance roundrobin
  option forwardfor
  no option abortonclose
  option httpchk /health/live
  default-server check inter 60000
  server SRV_1 10.210.4.172:8080 enabled
  server SRV_2 127.0.0.1:1 disabled

And path files:

/ $ cat /etc/haproxy/maps/path-exact.map
/ $ cat /etc/haproxy/maps/path-prefix-exact-h2.map
/ $ cat /etc/haproxy/maps/path-prefix-h2.map
.myapp.com/			eai-toolkit_eaid_h2_svc_eaid_http.dbe4b28f9c4404fc36a7ae76ead9a37d
myapp.com/			eai-toolkit_eaid_h2_svc_eaid_http.dbe4b28f9c4404fc36a7ae76ead9a37d
/ $ cat /etc/haproxy/maps/path-prefix-exact.map
/ $ cat /etc/haproxy/maps/path-prefix.map
.myapp.com/			eai-toolkit_eaid_svc_eaid_http.dbe4b28f9c4404fc36a7ae76ead9a37d
myapp.com/			eai-toolkit_eaid_svc_eaid_http.dbe4b28f9c4404fc36a7ae76ead9a37d

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions