Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nginx controller Client Authentication optional_no_ca not working

We are using Kubernetes and we need to check the client cert. What we need is to configure the Nginx ingress controller in order to pass the client certificate (if present) to the back-end service. We successfully configured it in our test environment. Here we have the following version:

  • Container runtimedocker://19.3.8
  • Kubelet version v1.17.6
  • nging 1.17

We used this ingress configuration:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: login-cns-produzione-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/configuration-snippet: "proxy_set_header X-SSL-CERT $ssl_client_escaped_cert;"
    nginx.ingress.kubernetes.io/server-snippet: "ssl_verify_client optional_no_ca ;"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  tls:
    - hosts:
        - login-cns.it
  rules:
  - host: login-cns.it
    http:
      paths:
      - path: /
        backend:
          serviceName: login-cns-produzione-service
          servicePort: 443

In our production environment, something is newer than the test. These are the versions in production:

  • Container runtimedocker://19.3.15
  • Kubelet versionv1.18.15
  • nging 1.19

The issue in production is that although we specify the directive optional_no_ca the ingress controller asks for the client certificate and tries to validate it and it fails Do you have any idea about why this happens?

Thank you

Angelo

EDIT

By reading here it seems I should use these annotations. But by adding them, the client certificate is not asked by Nginx

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: login-cns-test-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
    # Enable client certificate authentication
    nginx.ingress.kubernetes.io/auth-tls-verify-client: "optional_no_ca"
    # Create the secret containing the trusted ca certificates
    nginx.ingress.kubernetes.io/auth-tls-secret: "wso2is-collaudo/iamcoll-it"
    # Specify the verification depth in the client certificates chain
    nginx.ingress.kubernetes.io/auth-tls-verify-depth: "1"
    # Specify if certificates are passed to upstream server
    nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream: "true"
    nginx.ingress.kubernetes.io/auth-tls-error-page: "/cns/saml/dettagli-utente"
spec:
  tls:
    - hosts:
        - login-cns-test.it
  rules:
  - host: login-cns-test.it
    http:
      paths:
      - path: /
        backend:
          serviceName: login-cns-test-service
          servicePort: 443

The very strange thing is that with the previous annotation, I have some X.509 authentications successful and others unsuccessful. I really can't explain the issue.

More info about the versions:

  • nginx ingress controller version: nginx-ingress-controller:nginx-0.35.0-rancher2
  • nginx version: 1.19.2
  • openss version: OpenSSL 1.1.1g 21 Apr 2020

Any tips would be very appreciated... I'm fighting on this issue for several days

EDIT 2

If I use this configuration:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: login-cns-test-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/configuration-snippet: |
                        proxy_set_header X-SSL-CERT $ssl_client_escaped_cert;
                        error_page 495 496 497 ​/cns/saml/dettagli-utente;
    nginx.ingress.kubernetes.io/server-snippet: |
                         ssl_verify_client optional_no_ca;
                         if ($ssl_client_verify != SUCCESS) {
                              return 495;
                          }
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  tls:
    - hosts:
        - login-cns-test.it
  rules:
  - host: login-cns-test.it
    http:
      paths:
      - path: /
        backend:
          serviceName: login-cns-test-service
          servicePort: 443

The client certificate is asked but, then, Nginx fails on certificate verification and it stops... It doesn't allow the request to be routed to the default backend where I have all the business logic to check and verify the certificate

EDIT 3

In my nginx ingress controller logs I see:

2021/06/14 19:17:29 [crit] 9793#9793: *89059516 SSL_do_handshake() failed (SSL: error:0407E068:rsa routines:RSA_verify_PKCS1_PSS_mgf1:bad signature error:1417B07B:SSL routines:tls_process_cert_verify:bad signature) while SSL handshaking, client: XXX.YY.ZZ.WW, server: 0.0.0.0:443

So far, so good... I want that my Java application checks the certificate. But all the flow stops here. It seems I can't correctly configure the Nginx ingress controller error_page directive. Maybe should I configure the Nginx ingress controller ConfigMap (https://github.com/kubernetes/ingress-nginx/blob/master/docs/user-guide/nginx-configuration/configmap.md#custom-http-errors)?

like image 487
Angelo Immediata Avatar asked Jun 03 '21 17:06

Angelo Immediata


People also ask

Why should I use nginx instead of a server?

The first reason is simply because Nginx is battle tested and does the first level of screening. If for instance, the client fails to present a valid certificate, the request will not be forwarded to the appserver. Hence this is a nice safety net from possible bugs in the appserver code.

How do I add a certificate to my Nginx site?

Navigate to your nginx directory, and make a new directory for your site certificates (The ones you want to be publicly signed by a CA such as SSLTrust.AU)

How do I implement access control in Nginx?

Since Nginx will pass on various HTTP Headers to the appserver, we can use them to implement access control. When a request hits the appserver, it will check the HTTP header Ssl-Client-Verify is set to ‘SUCCESS’. If it isn’t, the request will be rejected with an error message.

How do I enable my site in Nginx?

Create a symlink to enable your site in nginx: Lastly, restart nginx: Double click the .PFX file, select “Current User”. If you set a passphrase on the PFX above, enter it here. Otherwise, leave blank and hit next.


Video Answer


1 Answers

Even after specifying the optional_no_ca parameter, it is necessary to provide the client certificate and because of using this parameter, it is not mandatory that the certificate is signed by the trusted CA 1 2.

like image 77
Anbu Thirugnana Sekar Avatar answered Nov 12 '22 05:11

Anbu Thirugnana Sekar