Nginx Ingress with Basic authentication breaks preflight requests

Viewed 1100

I'm trying to set up simple rule for my backend service secured by basic authentication. It works perfectly fine when I try to send request with curl or postman, the issue is when my frontend application tries to do the same. As I understand browsers sends preflight requests (OPTIONS method) which is used for CORS policy check. The issue is that Authorization header is not being added to this request which resolves with server responding 401. Is there a way to make Ingress omit authorization for specific methods?

Here is my Ingress (nginx) config:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: somesome-routing
  annotations:
    nginx.ingress.kubernetes.io/auth-type: basic
    nginx.ingress.kubernetes.io/auth-secret: basic-auth
    nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required'
spec:
  rules:
    - host: somesome.com
      http:
        paths:
          - path: /
            backend:
              serviceName: backend-service
              servicePort: 80
2 Answers

I ended up with workaround including two ingresses - one secured which routes traffic to frontend application and second one insecure which routes to my own nginx based api gateway which itself defines authentication rules:

#secure-ingress.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: secure-routing
  annotations:
    kubernetes.io/ingress.class: "nginx"
    cert-manager.io/cluster-issuer: "letsencrypt-staging"
    nginx.ingress.kubernetes.io/use-regex: "true"
    nginx.ingress.kubernetes.io/auth-type: basic
    nginx.ingress.kubernetes.io/auth-secret: basic-auth
    nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required'
spec:
  rules:
    - host: somesome.com
      http:
        paths:
          - path: /
            backend:
              serviceName: frontend-service
              servicePort: 80

#ingress.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: routing
  annotations:
    kubernetes.io/ingress.class: "nginx"
    cert-manager.io/cluster-issuer: "letsencrypt-staging"
spec:
  rules:
    - host: api.somesome.com
      http:
        paths:
          - path: /
            backend:
              serviceName: api-gateway-service
              servicePort: 80
# api-gateway/nginx.conf
worker_processes      1;

events {
    worker_connections  1024;
}

http {
    log_format timed_combined '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_time';
    access_log           /var/log/nginx/access.log timed_combined;
    client_max_body_size 20M;
    default_type         application/octet-stream;
    include              mime.types;
    keepalive_timeout    65;
    resolver             ${RESOLVER} ipv6=off;
    sendfile             on;

    server {
        listen          80;
        server_name     localhost;
        gzip            on;
        gzip_comp_level 6;
        gzip_min_length 1000;
        gzip_types      text/plain application/json application/xml;

        location ~* ^/backend_path {
            add_header 'Access-Control-Allow-Headers' 'authorization,content-type,iplanetdirectorypro';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, OPTIONS, DELETE';

            proxy_set_header X-Forwarded-Host $host;
            proxy_set_header X-Forwarded-Server $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_send_timeout 6000;
            proxy_read_timeout 6000;

            proxy_pass http://${BACKEND}$request_uri;
        }
    }
}

Auth or external auth breaks preflight / CORS because the default template does not handle OPTIONS requests the correct way. In fact, the auth handling is the same for all HTTP methods.

So the question to answer is "How can I handle OPTIONS requests differently?" or "How can I apply the auth only to specific methods". You can achieve this via configuration snippets. (Look here: nginx-ingress docs)

You can find a similar question here: How can I put basic auth on specific HTTP methods in ngnix ingress?

Related