NGINX Integration

NGINX is an HTTP and reverse proxy server which became famous as one of the fastest web servers out there, heimdall can be integrated with by making use of the ngx_http_auth_request_module. In such setup, NGINX delegates authentication and authorization to heimdall. If heimdall answers with a 2XX code, NGINX grants access and forwards the original request to the upstream service. If heimdall returns 401 or 403, the access is denied with the corresponding error code. Any other response code returned by heimdall is considered an error.

If there is no matching rule on heimdall side, heimdall responds with 404 Not Found, which, as said above will be treated by NGINX as error. To avoid such situations, you can define a default rule, which is anyway recommended to have secure defaults, which, depending on the configuration, would then respond either with 401 or 403, or still 405 if you do not allow a specific HTTP method.

Since NGINX is highly configurable and heimdall supports different integration options, you can use any of the configuration examples given below. All of these enable heimdall to build the URL of the protected backend server for rule matching purposes.

In most cases you must configure heimdall to trust your NGINX instances by setting trusted_proxies for the Decision, respectively Proxy service. Exceptions are described in the sections below.

Forward only the host information in the header

With this method you set the X-Forwarded-Host to let heimdall know the host, respectively dome the request was sent to. All other URL parts (schema, path and query parameter) as well as the HTTP method are then inferred from the URL and the request heimdall receives.

Instead of using X-Forwarded-Host you could also make use of the Host header. In that case, there is no need to configure the trusted_proxies.

Example 1. Possible Configuration
# nginx.conf
...

location / {
  auth_request            /_auth;  (1)
  auth_request_set        $auth_cookie $upstream_http_set_cookie;  (2)
  add_header              Set-Cookie $auth_cookie;
  auth_request_set        $authHeader0 $upstream_http_authorization;  (3)
  proxy_set_header        'Authorization' $authHeader0;
  # mitigate HTTPoxy Vulnerability
  # https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/
  proxy_set_header Proxy  "";
  ...
}

location = /_auth {  (4)
  internal;
  proxy_pass               http://heimdall:4456$request_uri; (5)
  proxy_pass_request_body  off;  (6)
  proxy_set_header         Content-Length   "";
  proxy_set_header         X-Forwarded-Host $http_host;  (7)
  proxy_set_header         X-Forwarded-For  $remote_addr;  (8)
}
1Configures NGINX to forward every request to the internal /_auth endpoint (this is where the actual heimdall integration happens - see below).
2When the response from heimdall returns, this and the next line set the Cookies set by heimdall in the response (whether you need this depends on your Contextualizers and Unifiers configuration)
3When the response from heimdall returns, this and the next line set the Authorization header set by heimdall in the response (which header to set depends again on your Contextualizers and Unifiers configuration)
4This is where the "magic" happens
5Configures NGINX to pass the request to heimdall and sets the request path and queries from the original request
6Disables sending of the request body. If your heimdall rules make use of the body, you should set this to on and remove the next line.
7This is where you forward the host information to heimdall
8Not really required, but makes the remote address available to heimdall and thus to the mechanisms used in by the rules. Requires trusted_proxies to be configured.

Forward all information in X-Forwarded-* headers

With this method you set the X-Forwarded-Method, X-Forwarded-Proto, X-Forwarded-Host and X-Forwarded-Path to let heimdall know the host, respectively domain url and the used HTTP method.

Compared to the previous integration option, the configuration only differs in the definition of the internal /_auth endpoint. So, the example configuration is limited to that part only.

Example 2. Possible Configuration
# nginx.conf
...

location = /_auth {
  internal;
  proxy_pass               http://heimdall:4456;  (1)
  proxy_pass_request_body  off;
  proxy_set_header         Content-Length         "";
  proxy_set_header         X-Forwarded-Method     $request_method;  (2)
  proxy_set_header         X-Forwarded-Proto      $scheme;  (3)
  proxy_set_header         X-Forwarded-Host       $http_host;  (4)
  proxy_set_header         X-Forwarded-Path       $request_uri;  (5)
  proxy_set_header         X-Forwarded-For        $remote_addr;
}
1Configures NGINX to pass the request to heimdall.
2Let NGINX forward the used HTTP method to heimdall.
3Let NGINX forward the used HTTP schema to heimdall.
4Let NGINX forward the used host to heimdall.
5Let NGINX forward the used path and query parameter to heimdall.

Forward all information in X-Forwarded-Uri and X-Forwarded-Method headers

This method is a simplified alternative to the previous one in which heimdall receives everything required to know the host url and the HTTP method in HTTP headers.

The difference is again in the definition of the internal /_auth endpoint. So, the example configuration is limited to that part.

Example 3. Possible Configuration
# nginx.conf
...

location = /_auth {
  internal;
  proxy_pass               http://heimdall:4456;  (1)
  proxy_pass_request_body  off;
  proxy_set_header         Content-Length         "";
  proxy_set_header         X-Forwarded-Method     $request_method;  (2)
  proxy_set_header         X-Forwarded-Uri        $scheme://$http_host$request_uri;  (3)
  proxy_set_header         X-Forwarded-For        $remote_addr;
}
1Configures NGINX to pass the request to heimdall.
2Let NGINX forward the used HTTP method to heimdall.
3Let NGINX forward the entire used HTTP URL to heimdall.

Integration with NGINX Ingress Controller.

The integration option, described in the Forward all information in X-Forwarded-* headers section corresponds more or less to the way how the ngnix.conf file is generated by the default nginx-ingress template used by the NGINX Ingress Controller. The only missing parts are the request path and the query parameter. So you can easily integrate heimdall by adding the following annotations to your ingress configuration.

Example 4. Possible Configuration
nginx.ingress.kubernetes.io/auth-url: "http://<heimdall service name>.<namespace>.svc.cluster.local:<decision port>/$request_uri" (1)
nginx.ingress.kubernetes.io/auth-response-headers: Authorization (2)
    # other annotations required
1Configures the controller to pass the request path and query parameters to heimdall’s decision service endpoint with <heimdall service name>, <namespace> and <decision port> depending on your configuration.
2Let NGINX forward the Authorization header set by heimdall to the upstream service. This configuration depends on your Contextualizers and Unifiers configuration

Last updated on Dec 19, 2022