apacheproxyclient-certificatesmod-securitymtls

mTLS with Apache proxy and many user certs?


I cannot get my Apache proxy server to send the certificate that the user chooses in the browser, to the downstream server.

The problem is SSLProxyMachineCertificateFile. If I set this variable, Apache ignores the cert I select in the browser and uses this one. If I don’t set it, I get error: AH02268: Proxy client certificate callback: downstream server wanted client certificate but none are configured

I want to set the CA for the client certificates in Apache, and any cert from that CA should be allowed and passed on to the downstream server.

Surely there is a way to do this?

VHost settings:

<VirtualHostInstance name='name' certfilename='example.com'>

SecRuleEngine Off

SSLCACertificateFile userCertChain.pem

SSLVerifyClient require
SSLVerifyDepth 10

SSLProxyEngine On
SSLProtocol all -TLSv1.3 -SSLv2 -SSLv3
SSLProxyProtocol all -TLSv1.3 -SSLv2 -SSLv3

#SSLProxyMachineCertificateFile userCertWithKey.pem

SSLProxyMachineCertificateChainFile userCertChain.pem

SSLProxyCACertificateFile downstreamServerFullchain.pem

SSLProxyVerify require
SSLProxyVerifyDepth 10

#SSLProxyCheckPeerName on
SSLProxyCheckPeerCN on

SSLHonorCipherOrder On

ServerName https://example.com:port
ServerAlias *.example.com

LogLevel debug

<Location />
    Require all granted
    ProxyPass https://example.com/
    ProxyPassReverse https://example.com/
</Location>
</VirtualHostInstance>

Solution

  • It's NOT possible, see: https://stackoverflow.com/a/20859810/5633214

    So after client auth to the proxy, I pulled out some details from the client cert and sent them to the backend server as request headers:

    SecRule SSL:SSL_CLIENT_S_DN_O ".*" \
           "phase:1,\
           id:'123456',\
           pass,\
           setenv:O=%{SSL.SSL_CLIENT_S_DN_O}"
    RequestHeader set Org %{O}e
    

    Make sure you REMOVE the header in your sec rules BEFORE sending something to the server (in case someone tries to add it to the request):

    SecRule &REQUEST_HEADERS:O "@eq 1" \
        "phase:1,\
        id:7890,\
        deny,\
        log,auditlog,\
        msg:'Organization present on request from client'"
    

    Everything together in correct order:

    SecRule &REQUEST_HEADERS:O "@eq 1" \
        "phase:1,\
        id:7890,\
        deny,\
        log,auditlog,\
        msg:'Organization present on request from client'"
    
    SecRule SSL:SSL_CLIENT_S_DN_O ".*" \
           "phase:1,\
           id:'123456',\
           pass,\
           setenv:O=%{SSL.SSL_CLIENT_S_DN_O}"
    
    RequestHeader set Org %{O}e
    

    See ModSecurity docs for how to set the header: https://github.com/owasp-modsecurity/ModSecurity/wiki/Reference-Manual-%28v3.x%29#user-content-setenv

    And Apache docs for what info you can get from the cert: https://httpd.apache.org/docs/current/mod/mod_ssl.html