4

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
  • 3,194
  • 6
  • 35
  • 54

1 Answers1

7

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
  • 8,538
  • 1
  • 28
  • 39
  • Thanks for that, do I need to create a separate ingress controller for the second ingress? If so, how do I configure it to point at the new ingress? I created the existing ingress controller using the nginx-ingress helm chart which doesn't seem to have a parameter that you can pass in to specify an exsiting ingress resource to use – Declan McNulty Jan 28 '19 at 09:16
  • You don't need additional ingress controller for that. One is enough. It reads all ingress objects in all namespaces from the cluster and add configuration sections to it's nginx.conf file. You can install additional ingress controller of different class if you want, for example nginx and traefik or haproxy. Each of them grabs only ingress objects of specific class: (kubernetes.io/ingress.class: nginx) If you install additional controller of the same class, it reads the same ingress objects from the cluster, so I guess both of them would have the same config. – VAS Jan 28 '19 at 09:32
  • Brilliant, everything now working thanks for your help – Declan McNulty Jan 28 '19 at 11:03