Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

nginx k8s ingress - forcing www AND https?

I have a kubernetes setup that looks like this:

nginx ingress -> load balancer -> nginx app

after getting an SSL certificate for www.foo.com, I've installed it in my nginx ingress as a secret, and it works as expected - traffic to www.foo.com gets redirected to the https version instead, and browsers display a secure connection indicator. Great.

What hasn't been easy, however, is getting the ingress to redirect non-www traffic to the www version of the site. I've tried using kubernetes.io/from-to-www-redirect: "true", but it doesn't seem to do anything - navigating to foo.com doesn't redirect me to the www version of the url, but either takes me to an insecure version of my site, or navigates me to default backend - 404 depending on whether i include foo.com as a host with it's own path in my ingress.

I have been able to set up a patchy redirect by adding the following to my actual application's nginx config -

server {
  listen       80;
  server_name  foo.com;
  return       301 http://www.foo.com$request_uri;
}

UPDATE: from-to-www-redirect DOES work; you just have to reference it with nginx.ingress.kubernetes.io rather than kubernetes.io as I was. But, this only works for foo.com - typing in https://foo.com explicitly causes browsers to display a security warning and no redirect to the proper URL of https://www.foo.com occurs.

Here's my current config for the nginx ingress itself:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: foo-https-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
spec:
  rules:
    - host: www.foo.com
      http:
        paths:
          - backend:
              serviceName: foo-prod-front
              servicePort: 80
            path: /
  tls:
      - hosts:
          - www.foo.com
        secretName: tls-secret
like image 454
Artem Zakharov Avatar asked Feb 07 '18 03:02

Artem Zakharov


1 Answers

I had to solve an issue first:

The solution that worked for me is the one from @demisx but on my first try, the solution was not working for another reason. I had more than one ingress with reference to the "example.com" root host and as described on the documentation this was omitting my www redirect rule.

Documentation refers that "If at some point a new Ingress is created with a host equal to one of the options (like domain.com) the annotation will be omitted."

This is example is wrong:

Ingress 1 - to handle example.com

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: example-https-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
spec:
  rules:
    - host: www.example.com
      http:
        paths:
          - backend:
              serviceName: example-frontend
              servicePort: 80
            path: /
  tls:
      - hosts:
          - example.com
          - www.example.com
        secretName: tls-secret

Ingress 2 - to handle example.com/news

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: example-https-ingress-news
spec:
  rules:
    - host: example.com. # <--------- I HAD ANOTHER REFERENCE
      http:
        paths:
          - backend:
              serviceName: example-news
              servicePort: 80
            path: /news
     - host: www.example.com
       http:
         paths:
           - backend:
              serviceName: example-news
              servicePort: 80
            path: /news
  tls:
      - hosts:
          - example.com
          - www.example.com
        secretName: tls-secret

Solution - Correct Configuration

Make sure that you don't have any other ingress created with the root domain otherwise the redirect will not work as documentation refers. I removed the reference to example.com host on ingress 2 and then immediately started to work.

Ingress 1 - to handle example.com

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: example-https-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
spec:
  rules:
    - host: www.example.com
      http:
        paths:
          - backend:
              serviceName: example-frontend
              servicePort: 80
            path: /
  tls:
      - hosts:
          - example.com
          - www.example.com
        secretName: tls-secret

Ingress 2 - to handle example.com/news

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: example-https-ingress-news
spec:
  rules:
     # <--------- removed the other reference to the root host 
     - host: www.example.com
       http:
         paths:
           - backend:
              serviceName: example-news
              servicePort: 80
            path: /news
  tls:
      - hosts:
          - example.com
          - www.example.com
        secretName: tls-secret

Note: By the way, I didn't need to add the forward annotation to the 2nd ingress cause is already handled by the first ingress. I'm not sure though, if the order of deployment matters for nginx ingress controllers so take this as a note only and try to confirm yourself.

like image 116
while true Avatar answered Oct 18 '22 14:10

while true