Add conditional request header in ingress controller according to incoming calls

3/16/2021

I am adding the external authentication using auth-url annotation. How to set conditional request headers for the auth-url api which depends on incoming calls? Can I set the request headers in nginx controller according to incoming calls?

Edited:

Hi, This is about adding a custom header(Id) which is expected into auth-url. I am setting the Id header which is required in authorize api of auth-url but not receiving in the api. Is this the right method to set? My next question is If it is set how can I set it conditionally depending on from which host server the request is coming through?

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: hello-kubernetes-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/auth-url:  http://ca6dd3adc439.ngrok.io/authorize
    nginx.ingress.kubernetes.io/auth-method: POST
    nginx.ingress.kubernetes.io/auth-snippet: |
      proxy_set_header Id "queryApps";
spec:
  rules:
  - host: "hw1.yourdomain"
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          serviceName:  hello-netcore-k8s
          servicePort: 80
  - host: "hw2.yourdomain"
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          serviceName: hello-kubernetes-second
          servicePort: 80


 
-- Divya Vyas
kubernetes
kubernetes-ingress
nginx
nginx-ingress

2 Answers

3/16/2021

Your question is not pretty clear so I assume that it was something related to authentication and header injection. For NGINX ingress, there are a couple ways for you to setup the authentication. The second ways in the following will talk about the header injection.

The first method will be the easiest one. You simply setup the secret and the annotation on the ingress.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: auth-ingress
  annotations:
    nginx.ingress.kubernetes.io/auth-secret: my-secret
    nginx.ingress.kubernetes.io/auth-type: basic
spec:
  rules:
  - http:
      paths:
      - path: /auth-url
        backend:
          service:
            name: test
            port:
              number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: normal-ingress
spec:
  rules:
  - http:
      paths:
      - path: /
        backend:
          service:
            name: test
            port:
              number: 80

The second one will be more complicated but it will be useful if you do your authentication with a particular header. You can inject the snippet of NGINX configuration to the ingress. Of course, if you want to do more manipulation like header adding, you can do it in this way as well.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: auth-ingress
  annotations:
    nginx.ingress.kubernetes.io/server-snippet: |
        if ( $some_condtion ) {
          return 403;
        }
spec:
  rules:
  - http:
      paths:
      - path: /auth-url
        backend:
          service:
            name: test
            port:80
-- Ryan Siu
Source: StackOverflow

3/16/2021

My next question is If it is set how can I set it conditionally depending on from which host server the request is coming through?

The best way would be to create two ingress objects with one where the external auth enabled for host hw1.yourdoman. For some reason while testing this the auth-snippet was not passing the header but with it works fine with configuration-snippet:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: hello-kubernetes-ingress-auth-on
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/auth-url:  http://ca6dd3adc439.ngrok.io/authorize
    nginx.ingress.kubernetes.io/auth-method: POST
    nginx.ingress.kubernetes.io/configuration-snippet:  |
       proxy_set_header Id  "queryApps";
spec:
  rules:
  - host: "hw1.yourdomain"
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          serviceName:  hello-netcore-k8s
          servicePort: 80

As you can see here it passes the desired header:

  "path": "/",
  "headers": {
    "host": "hw1.yourdomain",
    "x-request-id": "5e91333bed960802a67958d71e787b75",
    "x-real-ip": "192.168.49.1",
    "x-forwarded-for": "192.168.49.1",
    "x-forwarded-host": "hw1.yourdomain",
    "x-forwarded-port": "80",
    "x-forwarded-proto": "http",
    "x-scheme": "http",
    "id": "queryApps",
    "user-agent": "curl/7.52.1",
    "accept": "*/*"
  },
  "method": "GET",
  "body": "",
  "fresh": false,

Moving on, the second ingress object has to be configured the auth disabled for host hw2.yourdomain:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: hello-kubernetes-ingress-auth-off
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
  - host: "hw2.yourdomain"
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          serviceName: hello-kubernetes-second
          servicePort: 80

You can then have a look at the nginx.conf to check how the those two ingresss objects are configure at controller level. This is the first ingress:

       ## start server hw1.yourdomain
        server {
                server_name hw1.yourdomain ;

                listen 80  ;
                listen 443  ssl http2 ;

           set $proxy_upstream_name "-";
                
                location = /_external-auth-Lw {
                        internal;

          set $proxy_upstream_name "default-hello-netcore-k8s-80";

             hello-netcore-k8s.default.svc.cluster.local;
             proxy_set_header            X-Original-URL          $scheme://$http_host$request_uri;
--------
--------
                        # Pass the extracted client certificate to the auth provider

                        set $target http://hello-netcore-k8s.default.svc.cluster.local;
                        proxy_pass $target;
               location / {

                        set $namespace      "default";
                        set $ingress_name   "hello-kubernetes-ingress-auth-on";
                        set $service_name   "hello-netcore-k8s";
                        set $service_port   "80";
                        set $location_path  "/";


                        set $balancer_ewma_score -1;
                        set $proxy_upstream_name "default-hello-netcore-k8s-80";

                        # this location requires authentication
                        auth_request        /_external-auth-Lw;
                        auth_request_set    $auth_cookie $upstream_http_set_cookie;
                        add_header          Set-Cookie $auth_cookie;


                        # mitigate HTTPoxy Vulnerability
                        # https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/
                        proxy_set_header Proxy                  "";

                        # Custom headers to proxied server
--------
                        proxy_set_header Id "queryApps";
----

And this is the second one:

        ## start server hw2.yourdomain
        server {
                server_name hw2.yourdomain ;

                listen 80  ;
                listen 443  ssl http2 ;

                set $proxy_upstream_name "-";

                ssl_certificate_by_lua_block {
                        certificate.call()
                }

                location / {

                        set $namespace      "default";
                        set $ingress_name   "hello-kubernetes-ingress-auth-off";
                        set $service_name   "hello-kubernetes-second";
                        set $service_port   "80";
                        set $location_path  "/";
-- acid_fuji
Source: StackOverflow