kubernetes-ingress icon indicating copy to clipboard operation
kubernetes-ingress copied to clipboard

Feature Request: auth proxy support

Open mateuszdrab opened this issue 2 years ago • 11 comments

Hi

I've been using the HAproxy controller as the internet facing ingress controller in my setup; however, for purpose of oauth2 authentication, I've been 'daisy-chaining' an Nginx Ingress Controller which is configured with duplicate ingresses to allow oauth2 authentication via oauth2-proxy. This is achieved with the annotations:

    nginx.ingress.kubernetes.io/auth-url: "https://$host/oauth2/auth"
    nginx.ingress.kubernetes.io/auth-signin: "https://$host/oauth2/start?rd=$escaped_request_uri"

Unfortunately, it does not appear that this ingress controller supports it - but I'd like to do away with jumping between controllers. Is it feasible to implement support for this? It is supported by a similar project at https://github.com/jcmoraisjr/haproxy-ingress

Thanks

mateuszdrab avatar Mar 10 '23 20:03 mateuszdrab

Hi @mateuszdrab , we might consider that in the future. Your request has been labeled as enhancement.

ivanmatmati avatar Apr 27 '23 14:04 ivanmatmati

I managed to get it working. That's definitely a work-around; but here the receip: 1/ Assemble the lua code in a configmap, I use a makefile for that:

lua:
        kubectl create configmap haproxy-lua --dry-run=client -o yaml \
        --from-literal=http.lua="$$(curl https://raw.githubusercontent.com/haproxytech/haproxy-lua-http/master/http.lua)" \
        --from-literal=auth-request.lua="$$(curl https://raw.githubusercontent.com/TimWolla/haproxy-auth-request/main/auth-request.lua)" \
        --from-literal=json.lua="$$(curl https://raw.githubusercontent.com/rxi/json.lua/master/json.lua)" \
        > haproxy-lua.configmap.yaml
        #kubectl apply -f heproxy-lua.configmap.yaml

2/ Modify the deployment; (I used helm) here the added values:

controller:
    extraVolumes:
    - name: haproxy-lua
      configMap:
        name: haproxy-lua
        items:
        - key: json.lua
          path: json.lua
        - key: http.lua
          path: haproxy-lua-http/http.lua
        - key: auth-request.lua
          path: auth-request.lua
    extraVolumeMounts:
    - name: haproxy-lua
      mountPath: /usr/share/haproxy
    config:
      global-config-snippet: |
        lua-prepend-path /usr/share/haproxy/?/http.lua
        lua-prepend-path /usr/share/haproxy/?.lua
        lua-load /usr/share/haproxy/auth-request.lua

3/ Now you need to modify the ingresses you want to protect with this added annotation

haproxy.org/backend-config-snippet: |
            http-request lua.auth-intercept oauth2-proxy_oauth2-proxy_http  /oauth2/auth  HEAD    *        -        -
            http-request redirect code 302 location http://%[hdr(host)]/oauth2/start?rd=%[capture.req.uri] if ! { var(txn.auth_response_successful) -m bool }

Note that I (also) use oauth2-proxy, and expose it via an ingress, so I have a backend (oauth2-proxy_oauth2-proxy_http) already created, but I guess that a backend CRD (https://www.haproxy.com/documentation/kubernetes/latest/community/configuration-reference/custom-resources/backend/) should do the trick as well

Reference:

  • https://github.com/TimWolla/haproxy-auth-request

PS: I just read a know limitation of the script I used "The backend must not be using TLS."; seeing the annotation you used, this might be a problem

Zempashi avatar Aug 07 '23 07:08 Zempashi

I managed to get it working. That's definitely a work-around; but here the receip: 1/ Assemble the lua code in a configmap, I use a makefile for that:

lua:
        kubectl create configmap haproxy-lua --dry-run=client -o yaml \
        --from-literal=http.lua="$$(curl https://raw.githubusercontent.com/haproxytech/haproxy-lua-http/master/http.lua)" \
        --from-literal=auth-request.lua="$$(curl https://raw.githubusercontent.com/TimWolla/haproxy-auth-request/main/auth-request.lua)" \
        --from-literal=json.lua="$$(curl https://raw.githubusercontent.com/rxi/json.lua/master/json.lua)" \
        > haproxy-lua.configmap.yaml
        #kubectl apply -f heproxy-lua.configmap.yaml

2/ Modify the deployment; (I used helm) here the added values:

controller:
    extraVolumes:
    - name: haproxy-lua
      configMap:
        name: haproxy-lua
        items:
        - key: json.lua
          path: json.lua
        - key: http.lua
          path: haproxy-lua-http/http.lua
        - key: auth-request.lua
          path: auth-request.lua
    extraVolumeMounts:
    - name: haproxy-lua
      mountPath: /usr/share/haproxy
    config:
      global-config-snippet: |
        lua-prepend-path /usr/share/haproxy/?/http.lua
        lua-prepend-path /usr/share/haproxy/?.lua
        lua-load /usr/share/haproxy/auth-request.lua

3/ Now you need to modify the ingresses you want to protect with this added annotation

haproxy.org/backend-config-snippet: |
            http-request lua.auth-intercept oauth2-proxy_oauth2-proxy_http  /oauth2/auth  HEAD    *        -        -
            http-request redirect code 302 location http://%[hdr(host)]/oauth2/start?rd=%[capture.req.uri] if ! { var(txn.auth_response_successful) -m bool }

Note that I (also) use oauth2-proxy, and expose it via an ingress, so I have a backend (oauth2-proxy_oauth2-proxy_http) already created, but I guess that a backend CRD (https://www.haproxy.com/documentation/kubernetes/latest/community/configuration-reference/custom-resources/backend/) should do the trick as well

Reference:

  • https://github.com/TimWolla/haproxy-auth-request

PS: I just read a know limitation of the script I used "The backend must not be using TLS."; seeing the annotation you used, this might be a problem

Thanks for sharing your steps - I think I overlooked this and never got to investigate it.

The backend was indeed set to https; however, I can change that easily.

Does it work fine when backend is http and frontend is https with SSL termination enabled?

mateuszdrab avatar Apr 06 '24 10:04 mateuszdrab

@Zempashi @mateuszdrab I am trying to reproduce your configuration but the backend configuration is invalid, at least from the haproxy's perspective. It is not included in the/etc/haproxy/haproxy.cfg but i get a /etc/haproxy/failed/haproxy.cfg.96ad8aec-f482-4716-8053-d422ad54de39 instead. In the log I can see this:

msg="config parsing [/etc/haproxy/haproxy.cfg.2bddb069-c5a1-4e0b-a3e9-ccd8e78a2e28:396]: 'http-request' 
expects 'wait-for-handshake', 'set-log-level', 'set-nice', 'use-service', 'sc-add-gpc(*)', 'sc-inc-gpc(*)', 
'sc-inc-gpc0(*)',  'sc-inc-gpc1(*)', 'sc-set-gpt(*)', 'sc-set-gpt0(*)', 'send-spoe-group', 'do-resolve(*)', 
'cache-use', 'add-acl(*)', 'add-header', 'allow', 'auth', 'capture', 'del-acl(*)', 'del-header', 'del-map(*)', 
'deny', 'disable-l7-retry', 'early-hint', 'normalize-uri', 'redirect', 'reject', 'replace-header', 
'replace-path', 'replace-pathq', 'replace-uri', 'replace-value', 'return', 'set-header', 
'set-map(*)', 'set-method', 'set-path',  'set-pathq', 'set-query', 'set-uri', 'strict-mode', 
'tarpit',  'track-sc(*)', 'set-timeout', 'wait-for-body',  'set-var-fmt(*)', 'set-var(*)', 'unset-var(*)', 
'set-dst', 'set-dst-port',  'set-mark', 'set-src', 'set-src-port',  'set-tos', 'silent-drop', 
'set-priority-class', 'set-priority-offset',  'set-bandwidth-limit',  but got 'lua.auth-intercept'."

I checked the documentation here and here. In backednd you can only use lua service with use-service but auth-intercept is an action that can only be used in frontend. The problem with this is there is only one frontend that is globally used and can not configure from annotations. So it looks like this workaround dose not work anymore.

paldib avatar Apr 18 '24 08:04 paldib

I also found it needs to be included in the frontend section I use frontend-config-snippet which enables auth for all ingresses.

To maintain ingress without reverse proxy auth, you can make a separate ingress class or something like the public_hosts acl in my config.

vaskozl avatar May 26 '24 16:05 vaskozl