<p>I have obtained a cert from name.com.</p>
<pre class="lang-sh prettyprint-override"><code>➜ tree .     
.
├── ca.crt
├── vpk.crt
├── vpk.csr
└── vpk.key
</code></pre>
<p><strong>How I created the secrets</strong></p>
<p>I added ca.crt content at the end of vpk.crt file.</p>
<pre class="lang-sh prettyprint-override"><code>(⎈ | vpk-dev-eks:argocd)
➜ k create secret tls tls-secret --cert=vpk.crt --key=vpk.key --dry-run -o yaml | kubectl apply -f -

(⎈ | vpk-dev-eks:argocd)
➜ kubectl create secret generic ca-secret --from-file=ca.crt=ca.crt --dry-run -o yaml | kubectl apply -f -
</code></pre>
<p><strong>This is my ingress:</strong></p>
<pre class="lang-yaml prettyprint-override"><code>apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: websockets-ingress
  namespace: development
  annotations:
    kubernetes.io/ingress.class: &quot;nginx&quot;
    nginx.ingress.kubernetes.io/proxy-send-timeout: &quot;3600&quot;
    nginx.ingress.kubernetes.io/proxy-read-timeout: &quot;3600&quot;
    # Enable client certificate authentication
    nginx.ingress.kubernetes.io/auth-tls-verify-client: &quot;optional_no_ca&quot;
    # Create the secret containing the trusted ca certificates
    nginx.ingress.kubernetes.io/auth-tls-secret: &quot;development/ca-secret&quot;
    # Specify the verification depth in the client certificates chain
    nginx.ingress.kubernetes.io/auth-tls-verify-depth: &quot;1&quot;
    # Specify if certificates are passed to upstream server
    nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream: &quot;true&quot;
    argocd.argoproj.io/sync-wave: &quot;10&quot;
spec:
  tls:
    - hosts:
      - backend-dev.project.com
      secretName: tls-secret
  
  rules:
  - host: backend-dev.project.com
    http:
      paths:
      - path: /ws/
        backend:
          serviceName: websockets-service
          servicePort: 443
</code></pre>
<p>The cert is properly validated, I can connect via various CLI WebSocket clients and <a href="https://www.ssllabs.com/ssltest" rel="nofollow noreferrer">https://www.ssllabs.com/ssltest</a> gives me &quot;A+&quot;</p>
<p>However if I set</p>
<p><code>nginx.ingress.kubernetes.io/auth-tls-verify-client: &quot;on&quot;</code></p>
<p>then everything stops working and I get 400 error on the nginx ingress controller side (POD logs).</p>
<p><strong>I am confused from the official docs:</strong></p>
<p>The optional_no_ca parameter (1.3.8, 1.2.5) requests the client certificate but does not require it to be signed by a trusted CA certificate. This is intended for the use in cases when a service that is external to nginx performs the actual certificate verification. The contents of the certificate is accessible through the $ssl_client_cert variable.</p>
<h3>So what exactly &quot;optional_no_ca&quot; is doing and why &quot;on&quot; fails the requests?</h3>

<p><strong>Optional_no_ca</strong> does the optional client certificate validation and it does not fail the request when the client certificate is not signed by the CAs from <strong>auth-tls-secret</strong>. Even after specifying the optional_no_ca parameter, it is necessary to provide the client certificate. As mentioned in the document <a href="http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_trusted_certificate" rel="nofollow noreferrer">1</a>, the actual certificate verification is done when the service is external to Nginx.</p>
<p>When you set <strong>nginx.ingress.kubernetes.io/auth-tls-verify-client:on</strong>,
it requests a client certificate that must be signed by a certificate that is included in the secret key <strong>ca.crt</strong> of the secret specified by <strong>nginx.ingress.kubernetes.io/auth-tls-secret: secretName</strong>.</p>
<p>If not so, then certificate verification will fail and result in a status code 400 (Bad Request). Check <a href="https://github.com/kubernetes/ingress-nginx/blob/master/docs/user-guide/nginx-configuration/annotations.md#client-certificate-authentication" rel="nofollow noreferrer">this</a> for further information.</p>
