Redirect Google Kubernetes Ingress to HTTPS

5/8/2019

I have an Angular App, running in a nginx docker container, that is running in Google Kubernetes and behind a Google Kubernetes Ingress with a Google Managed Certificate. I cannot seem to get the Ingress to automatically redirect to HTTPS if the request comes in on HTTP / port 80.

Apparently the Google Ingress "can't do it" so I've been trying to get the nginx instance to do it for me. But I think in that case I'd need actual certificate which I also can't figure out how to get out of Google.

But...there has to be a simple way to do this. HTTPS works fine on the site, I just can't get it to redirect away from HTTP to HTTPS...

This is my Ingress YAML:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ui-ingress
  annotations:
    kubernetes.io/ingress.global-static-ip-name: my-ip 
    networking.gke.io/managed-certificates: my-certificate
spec:
  rules:
  - host: example.com
    http:
      paths:
      - backend:
          serviceName: web-ui
          servicePort: 80

And my nginx.conf with a commented-out redirect that didn't work:

worker_processes  1;

events {
    worker_connections  1024;
}

http {

    server {
        listen 80 default_server;
        server_name example.com;

        root   /usr/share/nginx/html;
        index  index.html index.htm;
        include /etc/nginx/mime.types;

        gzip on;
        gzip_min_length 1000;
        gzip_proxied expired no-cache no-store private auth;
        gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;

        location / {
            try_files $uri $uri/ /index.html;
        }

        #if ($scheme = http) {
        #    return 301 https://$server_name$request_uri;
        #}
    }
}

I also tried this longer nginx.conf that resulted in a 502 error from Google / Ingress:

worker_processes  1;

events {
    worker_connections  1024;
}

http {

    server {
        listen 80;
        server_name example.com;

        return 301 https://example.com$request_uri;
    }

    server {
        listen 443 ssl http2;
        server_name example.com;

        return 301 $scheme://example.com$request_uri;
    }

    server {
        listen 443 ssl http2 default_server;
        listen [::]:443 ssl http2 default_server;
        server_name example.com;

        root   /usr/share/nginx/html;
        index  index.html index.htm;
        include /etc/nginx/mime.types;

        gzip on;
        gzip_min_length 1000;
        gzip_proxied expired no-cache no-store private auth;
        gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;

        location / {
            try_files $uri $uri/ /index.html;
        }


    }
}

The error from the pod is looking for the certificate to be installed but I don't know how to get the certificate out of Google Managed Certs to copy to the nginx image:

"textPayload": "2019/05/08 21:02:13 [emerg] 1#1: no \"ssl_certificate\" is defined for the \"listen ... ssl\" directive in /etc/nginx/nginx.conf:27\n"

-- FirstDivision
google-kubernetes-engine
kubernetes-ingress
nginx

2 Answers

5/9/2019

I was reading about setting up other load balancers and stumbled across the answer I was looking for. Instead of redirecting based on the $scheme in nginx you have to instead redirect on $http_x_forwarded_proto. This prevents the Google Health checks from failing because they do not pass the http_x_forwarded_proto header so it will never hit that redirect when it's a health check.

if ($http_x_forwarded_proto = "http") {
    return 301 https://$host$request_uri;
}
-- FirstDivision
Source: StackOverflow

5/9/2019

You’re right, for now, Google Cloud HTTPS Load Balancer doesn't allow http-->https redirects.

I don't know how to get the certificate out of Google Managed Certs to copy to the nginx image.

You can't. Google manages the certificates and renews them for you. Therefore you will not have access to your TLS key.

And since a Google Cloud HTTPS LB can listen on either HTTPS or HTTP, you can't redirect from HTTP to HTTPS.

My recommendation to get this done the quickest way would be:

  • Install nginx-ingress controller to your GKE cluster and just put the https redirect annotation it offers on your Ingress object.
  • This will create an L3 (TCP/IP) Load Balancer instead of HTTPS Load Balancer, so you can handle both HTTP and HTTPS traffic.
  • Install and use cert-manager controller to get certificates for your Ingress (not GKE ingress, Nginx ingress). This will provide the tls key + cert files for you as Secret (my gke-letsencrypt tutorial might help along the way).
  • You can then mount/use this Secret from your nginx Ingress ’s tls: field, which the nginx-ingress controller will configure on its nginx.conf.
-- AhmetB - Google
Source: StackOverflow