SSL termination Nginx ingress controller

6/6/2018

I am unable to get the TLS termination at nginx ingress controller working on my kubernetes cluster.

my ingress rule looks as the following :

Christophers-MacBook-Pro-2:acme-microservice cjaime$ kubectl describe ing myapp-ingress-1
Name:             myapp-ingress-1
Namespace:        default
Address:          
Default backend:  default-http-backend:80 (<none>)
TLS:
 acme-io terminates myapp-default.acme.io
Rules:
 Host                            Path  Backends
 ----                            ----  --------
 myapp-default.acme.io  
                                 /   myapp:80 (<none>)
Annotations:
 ingress.kubernetes.io/ssl-redirect:  true
 kubernetes.io/ingress.class:         nginx
Events:
 Type    Reason  Age               From                      Message
 ----    ------  ----              ----                      -------
 Normal  UPDATE  53m (x2 over 1h)  nginx-ingress-controller  Ingress default/myapp-ingress-1
 Normal  UPDATE  53m (x2 over 1h)  nginx-ingress-controller  Ingress default/myapp-ingress-1
 Normal  UPDATE  53m (x2 over 1h)  nginx-ingress-controller  Ingress default/myapp-ingress-1
 Normal  UPDATE  53m (x2 over 1h)  nginx-ingress-controller  Ingress default/myapp-ingress-1

Whenever I try to access this from the browser I get the back the following server certificate

Server certificate
subject=/O=Acme Co/CN=Kubernetes Ingress Controller Fake Certificate
issuer=/O=Acme Co/CN=Kubernetes Ingress Controller Fake Certificate

This is preventing me from creating a valid SSL connection. I know my secret is correct because when using openssl I get a valid connection as follows

openssl s_client -servername myapp-default.acme.io -connect us1a-k8s-4.acme.io:31443 -showcerts
CONNECTED(00000003)

<content omitted>

   Start Time: 1528241749
   Timeout   : 300 (sec)
   Verify return code: 0 (ok)
---

However If I run the same command with the servername omitted I get the same fake certificate and a connection error

openssl s_client  -connect us1a-k8s-4.acme.io:31443 -showcerts
CONNECTED(00000003)
depth=0 O = Acme Co, CN = Kubernetes Ingress Controller Fake Certificate
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 O = Acme Co, CN = Kubernetes Ingress Controller Fake Certificate
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
0 s:/O=Acme Co/CN=Kubernetes Ingress Controller Fake Certificate
  i:/O=Acme Co/CN=Kubernetes Ingress Controller Fake Certificate

<content omitted>

   Start Time: 1528241957
   Timeout   : 300 (sec)
   Verify return code: 21 (unable to verify the first certificate)
-- hackmabrain
kubernetes
kubernetes-ingress
nginx
ssl

2 Answers

6/6/2018

It works as below now :

Prior to termination of SSL at the ingress controller, the successful http request from browser was to the ingress controller with a host header set :

Chrome Browser

http://us1a-k8s-4.acme.io:31443/index.html
Host : myapp-default.acme.io

*us1a-k8s-4.acme.io is the node where nginx ingress controller 
lives.*

After updating the ingress definition to use a cert, we got this to work

curl --resolve myapp-default.acme.io:31443:172.31.0.18 https://myapp- 
default.acme.io:31443/index.html

*where 172.31.0.18 would be the IP for us1a-k8s-4.acme.io*  

but from browser, using a host header the way we were using it before for the http request didn't work.

however when we made an entry as below to /etc/hosts file

172.31.0.18     myapp-default.acme.io

and hit the below url via browser :

http://myapp-default.acme.io:31443/index.html

IT WORKED!

Seems like the host header is not known to nginx, and it uses the URL to look up the correct certificate.

Check this https://www.claudiokuenzler.com/blog/693/curious-case-of-curl-ssl-tls-sni-http-host-header

-- hackmabrain
Source: StackOverflow

6/6/2018

Your tests with openssl are executed correctly and they show that nginx does offer the valid certificate for myapp-default.acme.io when that hostname is provided in the request via SNI. This is in harmony with what you configured in the Ingress.

For other hostnames or requests without a hostname the default certificate is sent. That certificate is to be stored in a Secret and configured via a command line parameter to the ingress controller (--default-ssl-certificate=$(POD_NAMESPACE)/tls-ingress).

Your browser warning was either because of a mismatch in the hostname or a cached fake certificate in your browser. I suggest you look up how flush the certificate cache in your b browser and/or redo the test with curl:

curl -v https://myapp-default.acme.io

If it still does not work correctly, you may be affected by #1954 - update nginx-ingress-controller.

-- Janos Lenart
Source: StackOverflow