PKI sign-on to CloudForms using RH SSO 7.2 – Part 1 of 2

(Part 2 is available here!)

With the advent of Public Key Infrastructure across organisations, it became possible to authenticate a user based on the certificate they provide. Red Hat Single Sign On 7.2 is able to authenticate users based on a provided certificate, matching some value from the certificate (e.g. CN, email) against RH SSO’s internal database of users.

When combined with the Security Assertion Markup Language (SAML) authentication out-of-the-box in CloudForms, we can achieve passwordless, certificate-based sign on to CloudForms.

There are three main areas to this configuration::

  1. Configuring RH SSO 7.2 for mutual TLS, requesting a client certificate.
  2. Configuring CloudForms for SAML against RH SSO 7.2.
  3. Enable the X.509 browser authentication flow in RH SSO 7.2.

Step 1 is the focus of this blog post. Steps 2 and 3 will follow in the next post.

RH SSO 7.2 and X509 Authentication

Firstly, there’s already existing documentation for this. Take a look at the following URL:

X.509 Client Certificate User Authentication

You need to perform a few primary steps:

  1. If you don’t already have one, generate or acquire a certificate for RH SSO to present to the user and save this in a key store.
  2. Generate a trust store that SSO will use to validate the presented client certificate.
  3. Enable mutual TLS on SSO 7.2. With mutual TLS configured you are requesting the user provides a certificate when negotiating the TLS connection with SSO.
  4. Configure a X.509 Browser Flow to allow the user to be authenticated with the presented certificate. This we’ll do in the next post.

Step 1: generate a certificate for SSO from IPA

Skip this step if you already have a certificate and private key generated.

Assuming your system configured for SSO is registered to IPA, you can run the below command to generate a certificate that SSO will present to a connecting user:

ipa-getcert request -f /etc/pki/tls/certs/sso.crt -k /etc/pki/tls/private/sso.key -r -I sso

This requests a new certificate from the IPA server you are registered to, stores the public and private keys at /etc/pki/tls/certs/sso.crt and /etc/pki/tls/private/sso.key respectively, and uses the nickname “sso” to track the certificate.

Issue an ipa-getcert list to check the results:

[root@sso log]# ipa-getcert list
Number of certificates and requests being tracked: 1.
Request ID 'sso':
        status: MONITORING
        stuck: no
        key pair storage: type=FILE,location='/etc/pki/tls/private/sso.key'
        certificate: type=FILE,location='/etc/pki/tls/certs/sso.crt'
        CA: IPA
        issuer: CN=Certificate Authority,O=HOME.AJG.ID.AU
        subject: CN=sso.home.ajg.id.au,O=HOME.AJG.ID.AU
        expires: 2020-07-05 10:42:41 UTC
        dns: sso.home.ajg.id.au
        principal name: host/sso.home.ajg.id.au@HOME.AJG.ID.AU
        key usage: digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment
        eku: id-kp-serverAuth,id-kp-clientAuth
        pre-save command: 
        post-save command: 
        track: yes
        auto-renew: yes

Note: if you see an error relating to NEED_KEY_GEN_PERMS, ensure you have the appropriate filesystem permissions and – crucially – the right SELinux context. certmonger has access to directories with the cert_t type (which is everything under /etc/pki).

Generate a PKCS12 key store for your SSO certificate

This is a piece of cake using the openssl command:

openssl pkcs12 -export -in /etc/pki/tls/certs/sso.crt -inkey /etc/pki/tls/private/sso.key -out sso.p12

This uses the openssl PKCS12 module:

  • -export: exports a new PKCS12 key store
  • -in: the full path to the certificate file
  • -inkey: the private key that corresponds to the certificate
  • -out: the filename to write to.

Enter a password to protect the keystore. Note it down – you’ll need it later.

Step 2: Generate a trust store

The trust store is the list of certificate authorities that RH SSO will trust. By default it will use whatever is in the Java trust store, but if you have a custom CA you’ll need this.

If the user presents a certificate signed by one of these CAs in the trust store, the certificate is considered valid (subject to revocation checks).

I use the certificate for my IPA CA, since that’s what my user certificate and SSO certificate is signed with, so I generate a trust store like so:

openssl pkcs12 -export -nokeys -in /etc/ipa/ca.crt -out truststore.p12
  • -nokeys: we’re not exporting private keys to this truststore.

Set a password – SSO configuration will expect one.

Step 3: Enable the HTTPS endpoint and mutual TLS

Configuring SSL for SSO is straightforward. My configuration below assumes a standalone configuration. Place this as appropriate within the configuration file appropriate to your deployment (e.g. domain.xml or standalone-ha.xml).

You could also make these modifications through the JBoss CLI if you prefer, although I leave that an exercise for the reader 🙂

You need to add a new security realm with the server-identities and authentication stanzas for your key store and trust store. Make sure your keystore and trust-store files are located in the configuration directory (e.g. standalone/configuration, domain/configuration, etc):

<management>
    ...
    <security-realms>
        ...

        <security-realm name="ssl-realm">
            <server-identities>
                <ssl>
                    <keystore path="sso.p12"
                                relative-to="jboss.server.config.dir"
                                keystore-password="<YOURPASSWORD>" />
                </ssl>
            </server-identities>
            <authentication>
                <truststore path="truststore.pfx" relative-to="jboss.server.config.dir" keystore-password="<YOURPASSWORD>" />
            </authentication>
        </security-realm>

        ...
    </security-realms>
    ....
</management>

Add a HTTPS listener, and ensure the security-realm is set to the name of your SSL realm. Also, notice how the “verify-client” attribute is set to “REQUESTED”. A user is requested to provide a certificate, but they aren’t knocked back if they don’t. Alternatively, set this to “REQUIRED” if you do not want any SSO connections without a valid client certificate.

<subsystem xmlns="urn:jboss:domain:undertow:4.0">
    <buffer-cache name="default"/>
    <server name="default-server">
        <http-listener name="default" socket-binding="http" redirect-socket="https" enable-http2="true"/>
        <https-listener name="https" socket-binding="https" security-realm="ssl-realm" enable-http2="true" verify-client="REQUESTED"/>
        <host name="default-host" alias="localhost">
            <location name="/" handler="welcome-content"/>
            <http-invoker security-realm="ApplicationRealm"/>
        </host>
    </server>
    ....
</subsystem>

The https socket binding defines which port Undertow will listen for SSL connections on:

<socket-binding name="https" port="${jboss.https.port:8443}"/>

Restart your SSO server, and you’re ready to go. Assuming you have a certificate installed in your browser, you should see the following when visiting the login page:

As long as your certificate was signed by a CA in the trust store, you should be able to connect. If you didn’t require a client certificate, only request one, you should be able to press ‘cancel’ and still reach a login prompt.

Even if you present a certificate you’ll still be asked to enter a username and password; that’s because we don’t have the certificate-based browser authentication flow enabled yet. We’ll do that after we have the SAML integration completed.


The next post will discuss the SAML integration – this is another step that’s covered pretty well in the documentation, but here’s a few gotchas that could pop up.

More in the next post!

 

Leave a Reply

Your email address will not be published. Required fields are marked *