2

I'm trying to set up the following architecture but I'm struggling:

  • Keycloak container with this image jboss/keycloak:7.0.0

  • Apache with mod_auth_openidc

  • The apache has a protected directory

  • Apache does an SSL client Authent

I want to configure the following scenario:

  • A user visits mywebsite/demo

  • Apache prompt him to authenticate with his certificate

  • Apache forward the info to keycloak

  • Keycloak uses X509/Validate Username to validate the certificate (CN)

  • Return the resource to the user once authenticated

I have the following config for Apache vhost :

Listen 8081 https
<VirtualHost *:8081>

        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/html/

        SSLEngine on
        SSLCipherSuite HIGH
        SSLProtocol all -SSLv3 -TLSv1.3


        SSLCertificateFile /etc/apache2/ssl/serv.crt
        SSLCertificateKeyFile /etc/apache2/ssl/serv.key
        SSLCACertificateFile /etc/apache2/ssl/ca.crt

        <Location /pdf >
                ProxyPass http://mywebsite:5001/pdf
                ProxyPassReverse http://mywebsite:5001/pdf
        </Location>
        #RequestHeader set CERT_CHAIN ""
        RequestHeader set  SSL_CLIENT_CERT ""


        OIDCCryptoPassphrase passphrase
        OIDCProviderMetadataURL https://mywebsite:9004/auth/realms/demorealm/.well-known/openid-configuration
        OIDCClientID demo2
        OIDCClientSecret e6dc781f-49c0-4cfa-9cde-411f9d8bc2cb
        OIDCSSLValidateServer Off
        OIDCRedirectURI https://mywebsite:9998/demo2/redirect
        OIDCRemoteUserClaim preferred_username
        OIDCInfoHook access_token id_token userinfo session


        <Location /demo2 >

                SSLVerifyClient require
                SSLVerifyDepth 2
                #RequestHeader set SSL_CLIENT_CERT_CHAIN_0 "%{{CERT_CHAIN}}s"
                RequestHeader set SSL_CLIENT_CERT "%{SSL_CLIENT_CERT}s"
                #Require ssl


                AuthType openid-connect
                Require valid-user
                Loglevel debug
        </Location>

</VirtualHost>

For the keycloak container, I'm not sure if the container consider my standalone.xml if I mount it instead of the default so I have executed the following jboss commands:

   /subsystem=keycloak-server/spi=x509cert-lookup:write-attribute(name=default-provider, value="apache")
   /subsystem=keycloak-server/spi=x509cert-lookup/provider=apache:write-attribute(name=properties.sslClientCert,value="SSL_CLIENT_CERT")
   /subsystem=keycloak-server/spi=x509cert-lookup/provider=apache:write-attribute(name=properties.sslCertChainPrefix,value="CERT_CHAIN")
   /subsystem=keycloak-server/spi=x509cert-lookup/provider=apache:write-attribute(name=properties.certificateChainLength,value="10")
   :reload

My keycloak is configured as follow : Client redirections :

client redirs

And the Authentication flow :

Execution

Config execution authenticator

But when I visit the website I get this error as a user "Team XYZ" with certificate CN "Team XYZ" : {"error_description":"X509 client certificate is missing.","error":"invalid_request"}

Keycloak Logs :

21:10:24,178 WARN  [org.keycloak.services.x509.AbstractClientCertificateFromHttpHeadersLookup] (default task-49) HTTP header "SSL_CLIENT_CERT" is empty

20:09:48,062 WARN  [org.keycloak.events] (default task-9) type=LOGIN_ERROR, realmId=5c005f6f-a912-4788-bf53-345551eb0e01, clientId=demo2, userId=null, ipAddress=Dummy, error=user_not_found, auth_method=openid-connect, auth_type=code, response_type=code, redirect_uri=https://mywebsite:9998/demo2/redirect, code_id=d2b3aecf-0a53-4d3a-85fd-3433aee61d61, response_mode=query, authSessionParentId=d2b3aecf-0a53-4d3a-85fd-3433aee61d61, authSessionTabId=FqOsf6BrEBk

Can someone please help me, I've been stuck with this for days now.

No name
  • 21
  • 1
  • 5
  • Hi, I've got the same error, except that I don't have apache or nginx in front of my keycloak as a reverse proxy. Have you solved in some way? – Gianluca Feb 24 '20 at 08:33
  • You need to set the SSL_CLIENT_CERT header. I’ve solved my issue by putting an RP ahead of keycloak, apparently we can’t modify mod_auth_openidc redirection headers. – No name Feb 25 '20 at 13:54
  • Ok, so you are saying that is mandatory to have a reverse proxy in front of keycloak? At the moment my keycloak is exposed directly and I'm calling it on port 8443, I don't have nginx or apache in front of it. Is there a way to set SSL_CLIENT_CERT, or it is a parameter related just to nginx or apache? – Gianluca Feb 25 '20 at 18:09
  • No it's not mandatory to have an RP. You can set it up as follow : 1- Expose Jboss(Wildfly) directly and configure Mutual HTTPS on it (https://www.keycloak.org/docs/latest/server_admin/#enable-x-509-client-certificate-user-authentication). 2- Behind an RP (apache, nginx ...) where you need to forward the SSL_CLIENT_CERT to Wildfly(keycloak) by setting it in the HTTP Headers. – No name Feb 26 '20 at 19:18
  • I've tried both solution in these days, exposing it directly or putting it behind nginx and setting the SSL_CLIENT_CERT forwarding in nginx config. I don't know what I'm missing, but with both I still receive the error "X509 client certificate is missing.". If I've understood well I get this error when Keycloak doesn't receive the client certificate, right? – Gianluca Feb 27 '20 at 10:28
  • Yes, you are right. You need to give more infos. did you try to remove certificate lookup (for nginx) and configure wildfly with mutual SSL ? – No name Feb 27 '20 at 10:47

1 Answers1

0

In a kubernetes environnement the following solution is working

      nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
      nginx.ingress.kubernetes.io/proxy-ssl-secret: "mynamespace/backend-x509-secret"
      nginx.ingress.kubernetes.io/proxy-ssl-verify: "on"
      nginx.ingress.kubernetes.io/proxy-ssl-verify-depth: "2"

      nginx.ingress.kubernetes.io/auth-tls-secret: "mynamespace/backend-x509-secret"
      nginx.ingress.kubernetes.io/auth-tls-verify-client: "optional"
      nginx.ingress.kubernetes.io/auth-tls-verify-depth: "2"
      nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream: "true"

where mynamespace/backend-x509-secret is generated from a kustomization.yaml

secretGenerator:
- name: backend-x509-secret
  files:
  - tls.crt
  - tls.key
  - ca.crt

where tls.crt,tls.key,ca.crt are my owns self signed and CA certificates use for keycloak X509 authorization, whereas my nginx is using a let's encrypt certificate.
Then keycloak config file standalone.xml or standalone-ha.xml is updated with the following cli file at startup

/subsystem=keycloak-server/spi=x509cert-lookup:write-attribute(name=default-provider, value="nginx")            
/subsystem=keycloak-server/spi=x509cert-lookup/provider=default:remove
/subsystem=keycloak-server/spi=x509cert-lookup/provider=nginx:add(enabled=true,properties={sslClientCert => "ssl-client-cert", sslCertChainPrefix => "USELESS",     certificateChainLength => "2"})            

you can also dynamically change your keycloak config using

$JBOSS_HOME/bin/jboss-cli.sh --connect --command='/subsystem=keycloak-server/spi=x509cert-lookup:write-attribute(name=default-provider, value="nginx")'            
$JBOSS_HOME/bin/jboss-cli.sh --connect --command='/subsystem=keycloak-server/spi=x509cert-lookup/provider=default:remove'
$JBOSS_HOME/bin/jboss-cli.sh --connect --command='/subsystem=keycloak-server/spi=x509cert-lookup/provider=nginx:add(enabled=true,properties={ sslClientCert => "ssl-client-cert", sslCertChainPrefix => "USELESS", certificateChainLength => "2"})'           
$JBOSS_HOME/bin/jboss-cli.sh --connect --command=':reload'