Skip to content

Decision API support for the nginx-ingress annotation nginx.ingress.kubernetes.io/auth-url  #521

@AlbinoDrought

Description

@AlbinoDrought

Is your feature request related to a problem? Please describe.

We are using nginx-ingress with the nginx.ingress.kubernetes.io/auth-url annotation.

We want to apply an access rule to this URL: https://admin.site.example/dashboard

We have an ingress config that looks like this:

ingress:
  enabled: true
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/auth-url: "http://oathkeeper.site.example/decisions$request_uri"
    nginx.ingress.kubernetes.io/auth-response-headers: Authorization

Oathkeeper expects (correct me if I'm wrong) a request that looks like this:

GET /decisions/dashboard HTTP/2
Host: admin.site.example

Oathkeeper will actually receive:

GET /decisions/dashboard HTTP/2
Host: oathkeeper.site.example

The default nginx-ingress template generates an NGINX config where the Host header sent to Oathkeeper is the auth_request host oathkeeper.site.example instead of our target host admin.site.example:

Generated nginx-ingress config
	## start server admin.site.example
	server {
		server_name admin.site.example ;		
		listen 80 proxy_protocol ;
		listen 443 proxy_protocol proxy_protocol ssl http2 ;		
		set $proxy_upstream_name "-";		

		ssl_certificate_by_lua_block {
			certificate.call()
		}		

		location = /_external-auth-Lw {
			internal;			# ngx_auth_request module overrides variables in the parent request,
			# therefore we have to explicitly set this variable again so that when the parent request
			# resumes it has the correct value set for this variable so that Lua can pick backend correctly
			set $proxy_upstream_name "example-site-admin-web-80";			
			proxy_pass_request_body     off;
			proxy_set_header            Content-Length          "";
			proxy_set_header            X-Forwarded-Proto       "";
			proxy_set_header            X-Request-ID            $req_id;			
			proxy_set_header            Host                    oathkeeper.site.example;
			proxy_set_header            X-Original-URL          $scheme://$http_host$request_uri;
			proxy_set_header            X-Original-Method       $request_method;
			proxy_set_header            X-Sent-From             "nginx-ingress-controller";
			proxy_set_header            X-Real-IP               $remote_addr;			
			proxy_set_header            X-Forwarded-For        $remote_addr;			
			proxy_set_header            X-Auth-Request-Redirect $request_uri;			
			proxy_buffering                         off;			
			proxy_buffer_size                       4k;
			proxy_buffers                           4 4k;
			proxy_request_buffering                 on;
			proxy_http_version                      1.1;			
			proxy_ssl_server_name       on;
			proxy_pass_request_headers  on;			
			# Pass the extracted client certificate to the auth provider			
			proxy_set_header Host "admin.site.example";			
			set $target http://oathkeeper.site.example/decisions$request_uri;
			proxy_pass $target;
		}		
		
		location / {			
			set $namespace      "example-site-admin";
			set $ingress_name   "example-site-admin-web";
			set $service_name   "example-site-admin-web";
			set $service_port   "80";
			set $location_path  "/";			rewrite_by_lua_block {
				lua_ingress.rewrite({
					force_ssl_redirect = false,
					ssl_redirect = true,
					force_no_ssl_redirect = false,
					use_port_in_redirects = false,
				})
				balancer.rewrite()
				plugins.run()
			}			
			# be careful with `access_by_lua_block` and `satisfy any` directives as satisfy any
			# will always succeed when there's `access_by_lua_block` that does not have any lua code doing `ngx.exit(ngx.DECLINED)`
			# other authentication method such as basic auth or external auth useless - all requests will be allowed.
			#access_by_lua_block {
			#}			
			header_filter_by_lua_block {
				lua_ingress.header()
				plugins.run()
			}			
			body_filter_by_lua_block {
			}			
			log_by_lua_block {
				balancer.log()				
			  monitor.call()				
			  plugins.run()
			}			
			port_in_redirect off;			set $balancer_ewma_score -1;
			set $proxy_upstream_name "example-site-admin-web-80";
			set $proxy_host          $proxy_upstream_name;
			set $pass_access_scheme  $scheme;			
			set $pass_server_port    $proxy_protocol_server_port;			
			set $best_http_host      $http_host;
			set $pass_port           $pass_server_port;			
			set $proxy_alternative_upstream_name "";			
			# this location requires authentication
			auth_request        /_external-auth-Lw;
			auth_request_set    $auth_cookie $upstream_http_set_cookie;
			add_header          Set-Cookie $auth_cookie;
			auth_request_set $authHeader0 $upstream_http_authorization;
			proxy_set_header 'Authorization' $authHeader0;			
			proxy_set_header Host                   $best_http_host;				
			# Allow websocket connections
			proxy_set_header                        Upgrade           $http_upgrade;			
			proxy_set_header                        Connection        $connection_upgrade;			
			proxy_set_header X-Request-ID           $req_id;
			proxy_set_header X-Real-IP              $remote_addr;			
			proxy_set_header X-Forwarded-For        $remote_addr;			
			proxy_set_header X-Forwarded-Host       $best_http_host;
			proxy_set_header X-Forwarded-Port       $pass_port;
			proxy_set_header X-Forwarded-Proto      $pass_access_scheme;			
			proxy_set_header X-Scheme               $pass_access_scheme;			
			# Pass the original X-Forwarded-For
			proxy_set_header X-Original-Forwarded-For $http_x_forwarded_for;			
			# mitigate HTTPoxy Vulnerability
			# https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/
			proxy_set_header Proxy                  "";			
			# Custom headers to proxied server			
			proxy_connect_timeout                   5s;
			proxy_send_timeout                      60s;
			proxy_read_timeout                      60s;			
			proxy_buffering                         off;
			proxy_buffer_size                       4k;
			proxy_buffers                           4 4k;			
			proxy_max_temp_file_size                1024m;			
			proxy_request_buffering                 on;
			proxy_http_version                      1.1;			
			proxy_cookie_domain                     off;
			proxy_cookie_path                       off;			
			# In case of errors try the next upstream server before returning an error
			proxy_next_upstream                     error timeout;
			proxy_next_upstream_timeout             0;
			proxy_next_upstream_tries               3;			
			proxy_pass http://upstream_balancer;			
			proxy_redirect                          off;		
		}	
	}
	## end server admin.site.example

Describe the solution you'd like

I would like to be able to point the auth-url annotation at Oathkeeper and have everything work without changing any internal nginx-ingress config templates.

Describe alternatives you've considered

The default template includes all the normal X-Forwarded-* headers. It may work out-of-the-box with the /decisions/traefik endpoint added in #486 , but I'm not sure if this is released yet.

Additional context

oryd/oathkeeper:v0.38.3-beta.1

quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.32.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    staleFeedback from one or more authors is required to proceed.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions