ingress-nginx: from-to-www-redirect is applied after SSL instead of before, causing security warning in browser

Is this a request for help?: No, bug

What keywords did you search in NGINX Ingress controller issues before filing this one?: force-www, ssl, https, kubernetes ingress controller fake certificate


Is this a BUG REPORT or FEATURE REQUEST?: bug

NGINX Ingress controller version: 0.9.1

Kubernetes version: 1.8.5

Environment: GKE

  • Cloud provider or hardware configuration: Google Cloud
  • OS (e.g. from /etc/os-release): Container OS
  • Kernel (e.g. uname -a):
  • Install tools: Helm
  • Others: n/a

What happened: I have an app I would like to host on www.foo.com. My nginx ingress has the from-to-www-redirect flag enabled to redirect requests from the base domain url, and has a TLS secret to provide for secure connections. This combination of redirect and SSL works for most url inputs, but not one in particular - https://foo.com. In this case, browsers present a security warning like this:

Attackers might be trying to steal your information from foo.com (for example, passwords, messages, or credit cards). Learn more
NET::ERR_CERT_AUTHORITY_INVALID
Subject: Kubernetes Ingress Controller Fake Certificate
Issuer: Kubernetes Ingress Controller Fake Certificate
Expires on: Feb 1, 2019
Current date: Feb 7, 2018
PEM encoded chain:
...

Forcing the browser to proceed to the “unsafe” site redirects to the correct destination of https://www.foo.com and enables SSL like nothing ever happened. For reference, the following urls all redirect to https://www.foo.com with no warnings:

foo.com http://foo.com www.foo.com http://www.foo.com

What you expected to happen: I expect https://foo.com to redirect to https://www.foo.com without browsers displaying a false alarm.

How to reproduce it (as minimally and precisely as possible):

  1. Set up an application on GKE
  2. Place it behind an nginx ingress configured to enable from-to-www-redirect and SSL via a certificate, with a subdomain host like www.foo.com pointing to the application service
  3. Attempt to reach the application with https://<base-domain>.

Anything else we need to know:

Here’s my nginx ingress config file:

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

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 6
  • Comments: 33 (3 by maintainers)

Most upvoted comments

For those interested in a short term work around, I add the following annotation to get it to work as I need for now:

nginx.ingress.kubernetes.io/configuration-snippet: |
  if ($host = 'foo.com' ) {
    rewrite ^ https://www.foo.com$request_uri permanent;
  }

Then I add the root foo.com to the rules:

---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: group-1
  annotations:
    kubernetes.io/ingress.class: "group1-ingress"
    kubernetes.io/tls-acme: "true"
    [ cert-manager annotations ]
    nginx.ingress.kubernetes.io/configuration-snippet: |
      if ($host = 'foo.com' ) {
        rewrite ^ https://www.foo.com$request_uri permanent;
      }
    nginx.ingress.kubernetes.io/ssl-redirect: "True"
    nginx.ingress.kubernetes.io/from-to-www-redirect: "True"
spec:
  tls:
  - hosts:
    - www.foo.com
    - foo.com
    secretName: prd-live-group-1
  rules:
  - host: www.foo.com
    http:
      paths:
      - backend:
          serviceName: foo-service
          servicePort: 80
  - host: foo.com
    http:
      paths:
      - backend:
          serviceName: foo-service
          servicePort: 80

I have same issue, my certificate is valid for both www.foo.com and foo.com but when using from-to-www-redirect and

  tls:
  - hosts:
    - www.foo.com
    - foo.com
    secretName: foo-com-ssl

ssl_certificate and ssl_certificate_key directives don’t get generated for foo.com server block. I’ve checked this with nginx template and these directives don’t exists in them either https://github.com/kubernetes/ingress-nginx/blob/36cce00fdd570b5b03ef1b19672f9641dfcfedd5/rootfs/etc/nginx/template/nginx.tmpl#L377-L405

@thomascooper’s solution also works for redirecting www to non-www. Something like:

nginx.ingress.kubernetes.io/configuration-snippet: |
      if ($host = 'www.foo.com' ) {
        rewrite ^ https://foo.com$request_uri permanent;
      }

I could not get this to work without using this snippet. I’m sure the developers on this project have their hands full, but the current behavior outlined in this thread seems unexpected and the issue warrants staying open.

I can confirm that issue exists in 0.14.0, generic block with no ssl included is generated for this specific scenario:

	server {

		listen 80;
		listen 443 ssl;

		listen [::]:80;
		listen [::]:443;

		server_name www.foo.com;

		return 308 $scheme://foo.com$request_uri;

	}

Is this supposed to work now? Just want to know if there is something wrong on my side of if the problem still exist.

I am having the same issue using nginx-ingress-controller:0.14.0. If I visit the root domain i receive a cert error (its serving the Kubernetes Ingress Controller Fake Certificate).

I use https://github.com/jetstack/cert-manager (very similar and based on kube-lego, same as the commenter above).

Here is my ingress config:

---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: group-1
  annotations:
    kubernetes.io/ingress.class: "group1-ingress"
    kubernetes.io/tls-acme: "true"
    [ cert-manager annotations ]
    nginx.ingress.kubernetes.io/ssl-redirect: "True"
    nginx.ingress.kubernetes.io/from-to-www-redirect: "True"
spec:
  tls:
  - hosts:
    - www.foo.com
    - foo.com
    secretName: prd-live-group-1
  rules:
  - host: www.foo.com
    http:
      paths:
      - backend:
          serviceName: foo-service
          servicePort: 80

Still seems like a problem for https://foo.com when you want to use from-to-www-redirect. Similar to above, this seems to work for us, in the www.foo.com ingress:

    nginx.ingress.kubernetes.io/configuration-snippet: |
      if ($host = 'foo.com' ) {
        rewrite ^ https://www.foo.com$request_uri permanent;
      }
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    nginx.ingress.kubernetes.io/server-alias: foo.com

We’re using a wildcard cert for *.foo.com

Experiencing this as well, with certs generated by cert-manager (ex kube-lego)

Pretty serious issue IMHO, this makes from-to-www-redirect unusable with TLS.

The spec.tls.hosts entry in my ingress has both www.foo.com, foo.com, and a 3rd domain, and the resulting cert does have all 3 domains.

So, the problem definitely seems to be in the generated nginx config.

thanks @thomascooper !

This worked for me:

nginx.ingress.kubernetes.io/configuration-snippet: |
      if ($host = 'foo.com' ) {
        rewrite ^ https://www.foo.com$request_uri permanent;
      }

@corpulent Your problem is that there is no ingress rule for www.demo.foo.com. Whenever a request come from this domain, k8s does not know that you want to execute this ingress since it is not written there.

Update your rules as follow:

  rules:
    - host: "demo.foo.com"
      http:
        paths:
          - path: /
            backend:
              serviceName: demo-service
              servicePort: 5678
    - host: "www.demo.foo.com"
      http:
        paths:
          - path: /
            backend:
              serviceName: demo-service
              servicePort: 5678
  tls:
    - hosts:
      - "demo.foo.com"
      - "www.demo.foo.com"
      secretName: wildcard-foo-com

Watching this!

Closing. This works as expected. As @JordanP said, if you have an SSL certificate, you need one that contains all the hosts you need (CN in the certificate). This is a restriction in NGINX that we cannot change.

Same here, have to use the configuration-snippet annotation to configure the redirect in nginx, as well as listing all domains in the rules section.

If you have additional hosts in the tls section (for example www or non www version of your domain), you still have to list them in the rules section and map them to some service because it seems like the generated nginx config only reads the listed hosts in the rules section.

any status update on this? I’m experiencing the same issue… if nothing else my comment will hopefully keep this issue open

yeah, I have this in 0.20.0. The issue as I see it is the following taken from one of my ingress pods nginx.conf. This is the code I assume nginx.ingress.kubernetes.io/from-to-www-redirect triggers.

	server {

		listen 80 proxy_protocol;
		listen 443 proxy_protocol ssl;

		listen [::]:80 proxy_protocol;
		listen [::]:443 proxy_protocol;

		server_name example.com.au;

		return 308 $scheme://www.example.com.au$request_uri;

	}

this does not have a valid ssl cert to serve.

@artemzakharov NGINX, not the controller.