Nginx's ssl_verify_client directive can be set to on, off, optional, or optional_no_ca. The last value is easy to misread. It requests a client certificate but does not verify the certificate chain against the configured trusted CA. Nginx describes it as intended for deployments where an external service performs the actual verification. If an application treats a presented certificate as proof of identity and Nginx is configured with optional_no_ca, the trust decision has moved somewhere that may not exist.

The certificate can still be useful as an input to another verification step. It should not be accepted merely because the TLS handshake completed. Nginx exposes the verification result through $ssl_client_verify. When Nginx is responsible for validation, an access rule should require the success state explicitly instead of testing only whether a certificate was supplied.

Make the verifier explicit

Choose one of two designs. In the first, Nginx verifies client certificates with a configured trust store and enforces the result before proxying the request. In the second, a trusted service receives the certificate and performs chain, hostname or identity checks that match the application's policy. The second design needs a protected handoff between Nginx and that service, with evidence that the verifier sees the exact certificate Nginx received.

Do not pass client-certificate fields in ordinary request headers without stripping client-supplied copies. Names such as X-Client-Verify, X-Client-Cert, and X-SSL-Client-S-DN are ordinary headers on the wire. A direct request to the application, or a proxy that forwards the incoming header unchanged, can make an unverified client look authenticated.

Bind the identity to the service

Certificate subject names are not automatically application usernames. The application should map the verified certificate to a service identity through a controlled registry, a SPIFFE or workload identity, or a certificate policy that defines the permitted subject names. Check revocation and certificate lifetime through the chosen trust path. Do not accept any certificate signed by a broad public CA as an internal workload identity unless the policy explicitly permits that population.

Separate client authentication from request authorization. A valid certificate may authenticate one workload, while the endpoint may require a different role or tenant. Apply those checks after the certificate identity is established and record both values in a structured authorization decision.

Test the failure cases

Use a staging endpoint and four clients:

  1. 1.

    No client certificate.

  2. 2.

    A certificate from an untrusted issuer.

  3. 3.

    An expired or revoked certificate.

  4. 4.

    A valid certificate with the wrong service subject or role.

For each case, inspect the Nginx variable, the upstream headers, the application log, and the final response. The expected result should be a denial at a named layer. A success caused by a missing certificate variable, a stale header, or a default-allow rule is a configuration defect.

Review the whole proxy chain

Document which component terminates TLS, which component verifies the client chain, and which component maps the certificate to an identity. Include any CDN, service mesh, ingress controller, or load balancer in that map. After a proxy or certificate change, rerun the cases and compare the results.

optional_no_ca has a legitimate use as a certificate-forwarding mode. It is unsafe as a stand-in for verification. The access policy must name the verifier and fail closed when verification cannot be completed.

References