Exclude specific hosts from ssl redirect in Kubernetes Nginx Ingress

1/24/2019

I have an Nginx ingress controller set up on my kubernetes cluster, which by default does an https redirect for any requests that it receives, so http://example.com is automatically forwarded on to https://example.com.

I now have a host that I need to serve over http and not https, essentially excluding it from the ssl redirect. What I have found is that I can disable the ssl redirect across the whole ingress, but not for a specific host.

My Ingress yaml:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
   name: ingress
annotations:
    kubernetes.io/ingress.class: nginx
spec:
  tls:
  - hosts:
    - mysslsite.co.uk
secretName: tls-secret

rules:
 - host: my-ssl-site.co.uk
   http:
    paths:
    - path: /
      backend:
        serviceName: my-service
        servicePort: 80
 - host: my-non-ssl-site.co.uk
   http:
      paths:
      - path: /
        backend:
          serviceName: my-other-service
          servicePort: 80

My Config Map:

apiVersion: v1
kind: ConfigMap
metadata:
  labels:
    app: nginx-ingress
    chart: nginx-ingress-0.28.3
    component: controller
    heritage: Tiller
    release: nginx-ingress
  name: undercooked-moth-nginx-ingress-controller
  namespace: default
data:
  proxy-buffer-size: "512k"
  client-header-buffer-size: "512k"
  proxy-body-size: "100m"
  large-client-header-buffers: "4 512k"
  http2-max-field-size: "512k"
  http2-max-header-size: "512k"
  fastcgi_buffers: "16 16k" 
  fastcgi_buffer_size: "32k"

What I have tried:

  1. Attempt to turn off ssl redirect across the board and set a rule to redirect to the site requiring ssl to https by setting the annotation nginx.ingress.kubernetes.io/ssl-redirect: "false" and adding the following config snippet:

    nginx.ingress.kubernetes.io/configuration-snippet: |
          if ($host = 'my-ssl-site.co.uk' ) {
            rewrite ^ https://my-ssl-site.co.uk$request_uri permanent;
          }
    

    This does remove the https redirect but results in a too many redirects error for the site requiring ssl.

  2. Attempted to add rules in the ConfigMap as per this answer to turn off ssl redirect and handle the conditional redirect in a server config snippet but this still resulted in an ssl redirect.

  3. Tried to add a second ingress controller so that one could have ssl redirect enabled and the other one could have it turned off. I created the controller but I think I also need to create a second nginx ingress and configure and label the apps that will be returned to each? This seems like overkill when all I want to do is exclude one service on the cluster from the ssl redirect.

Is there anything obvious I am missing? It feels as though it shouldn't be this hard to add a simple rule to exclude one host from the ssl-redirect.

-- Declan McNulty
https
kubernetes
kubernetes-ingress
nginx
ssl

1 Answer

1/25/2019

You can create two Ingress objects, one for each site in the same namespace.

Use annotation nginx.ingress.kubernetes.io/ssl-redirect: "true" for SSL site

Use annotation nginx.ingress.kubernetes.io/ssl-redirect: "false" for Non-SSL site

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
   name: cmac-ingress
   namespace: ns1
   annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  tls:
  - hosts:
    - my-ssl-site.co.uk
    secretName: testsecret-tls
  rules:
  - host: my-ssl-site.co.uk
    http:
      paths:
      - path: /
        backend: 
          serviceName: my-service
          servicePort: 80
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
   name: cmac-ingress1
   namespace: ns1
   annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
  tls:
  - hosts:
    - my-site.co.uk
    secretName: testsecret-tls
  rules:
  - host: my-site.co.uk
    http:
      paths:
      - path: /
        backend: 
          serviceName: my-service
          servicePort: 80

Here is the result from ingress-controller nginx.conf file:

    ## start server my-site.co.uk
    server {
            server_name my-site.co.uk ;

            listen 80;

            set $proxy_upstream_name "-";

            listen 443  ssl http2;

            # PEM sha: ffa288482443e529d72a0984724f79d5267a2a22
            ssl_certificate                         /etc/ingress-controller/ssl/default-fake-certificate.pem;
            ssl_certificate_key                     /etc/ingress-controller/ssl/default-fake-certificate.pem;

            location / {

                    <some lines skipped>

                    if ($scheme = https) {
                            more_set_headers                        "Strict-Transport-Security: max-age=15724800; includeSubDomains";
                    }

                    <some lines skipped>

            }

    }       
    ## end server my-site.co.uk

    ## start server my-ssl-site.co.uk
    server {
            server_name my-ssl-site.co.uk ;

            listen 80;

            set $proxy_upstream_name "-";

            listen 443  ssl http2;

            # PEM sha: ffa288482443e529d72a0984724f79d5267a2a22
            ssl_certificate                         /etc/ingress-controller/ssl/default-fake-certificate.pem;
            ssl_certificate_key                     /etc/ingress-controller/ssl/default-fake-certificate.pem;

            location / {


                    <some lines skipped>

                    if ($scheme = https) {
                            more_set_headers                        "Strict-Transport-Security: max-age=15724800; includeSubDomains";
                    }

                    # enforce ssl on server side
                    if ($redirect_to_https) {

                            return 308 https://$best_http_host$request_uri;

                    }

                    <some lines skipped>

            }

    }    
    ## end server my-ssl-site.co.uk

You can find additional redirection section in the SSL-enforced site definition:

# enforce ssl on server side
if ($redirect_to_https) {

        return 308 https://$best_http_host$request_uri;

}
-- VAS
Source: StackOverflow