WildFly Elytron

Dynamic client SSL context that automatically delegates to different SSLContexts based on the host and port of the peer

WildFly 32 running at a community stability level or lower includes the ability to configure the dynamic SSL context. This dynamic SSL context delegates to other instances of SSL contexts that are selected based on the host and port of the peer.

Prerequisites

To follow along with this guide, you will need:

  • Roughly 15 minutes

  • WildFly 32 or newer

New dynamic-client-ssl-context resource

WildFly 32 has added a new dynamic-client-ssl-context resource to the elytron subsystem. This new resource has a single attribute authentication-context, which points to the configured authentication-context resource. It can have multiple ssl-contexts configured for different hosts and/or ports. The dynamic client SSL context dynamically delegates to the specific client SSL context that is configured for the host and/or port of the connection.

Example configuration on the server side

/subsystem=elytron/authentication-context=ac:add(match-rules=[{match-port=8443,ssl-context=client1-ssl-context},{match-host="www.example.org",ssl-context=client2-ssl-context}, {match-host="www.myhost.org", match-port=443, ssl-context=client3-ssl-context}])

/subsystem=elytron/dynamic-client-ssl-context=dynamicClientSSLContext:add(authentication-context=ac)

The dynamic client SSL context will dynamically switch between different configurations based on the host and port of the peer. In the above configuration, if the hostname of the peer connection is "www.example.org", then the client2-ssl-context will be used. If another request is made to port 8443, then client1-ssl-context will be used. Note that the first matching rule from the given authentication context is always preferred. If the destination does not match any of the rules, the configured default SSLContext will be used. If it is not configured, then SSLContext.getDefault() will be used.

It is also possible to configure this dynamic SSL context to be a default SSL context on the server:

/subsystem=elytron:write-attribute(name=default-ssl-context,value=dynamicClientSSLContext)
reload

If this is the case, standalone clients in a deployed applications that use the SSLContext.getDefault() will use this dynamic SSL context for their requests.

Example use on the client side

To use the dynamic client SSL context with the standalone clients, make sure you have the elytron module wildfly-elytron-dynamic-ssl on your classpath. You can then instantiate the org.wildfly.security.dynamic.ssl.DynamicSSLContext as shown below:

DynamicSSLContext dynamicSSLContext = new DynamicSSLContext();

The DynamicSSLContext instance loads the authentication context from the classpath as is described in the elytron client documentation.

You can also pass an existing AuthenticationContext instance to the org.wildfly.security.dynamic.ssl.DynamicSSLContextImpl class and use it directly with the DynamicSSLContext: new DynamicSSLContext(new DynamicSSLContextImpl(myAuthenticationContextInstance));

Same as on the server side, the client configuration can also specify different rules for different SSL contexts. These rules are used by the DynamicSSLContext to select an SSLContext to delegate to.

As always, you can use either the programmatic approach to provide the authentication context or the configuration file approach. Below is an example of SSL context rules in the configuration file:

<ssl-context-rules>
    <rule use-ssl-context="client-context1">
        <match-host name="www.example.org"/>
        <match-port number="443"/>
    </rule>
    <rule use-ssl-context="client-context2">
        <match-host name="localhost"/>
        <match-port number="8443"/>
    </rule>
    <rule use-ssl-context="client-context3">
        <match-port number="9443"/>
    </rule>
        <rule use-ssl-context="default-context">
    </rule>
</ssl-context-rules>

Note: Since the org.wildfly.security.dynamic.ssl.DynamicSSLContextSPI is an SPI, you can use your own implementation to provide SSL context selection instead of relying on the elytron client.

Example using reverse proxies

We will use a simple example consisting of a configure.cli file. This file configures 2 ports secured with TLS and 2 reverse proxies connecting to these ports.

To get the configure.cli file, clone the elytron-examples repository to your local machine:

git clone git@github.com:wildfly-security-incubator/elytron-examples.git

and navigate to the dynamic-ssl-reverse-proxies directory.

Since the community is the default stability, you can start the WildFly server with the following:

$WILDFLY_HOME/bin/standalone.sh

Examine the commands in the configure.cli file of the dynamic-ssl-reverse-proxies example. This file configures ports 9443 and 10443 to require a different certificate and truststore to connect. The URL http://localhost:8080/proxy has been configured as a reverse proxy, forwarding requests to port 9443, where there is a WildFly welcome page. Similarly, the URL http://localhost:8080/proxy2 forwards requests to port 10443. Finally, the authentication-context and dynamic-client-ssl-context have been configured to associate the ports with the appropriate client-ssl-context resource.

Run the configure.cli file to apply the changes to your running WildFly server:

$WILDFLY_HOME/bin/jboss-cli.sh --connect  --file=configure.cli

Testing the example

Try accessing the reverse proxy http://localhost:8080/proxy and the http://localhost:8080/proxy2 with your browser. Both of these URLs will successfully return the Welcome to WildFly page.

When you accessed the http://localhost:8080/proxy the reverse proxy forwarded your request to the https://localhost:9443/ URL. This URL requires you to provide a client certificate and to accept the server’s certificate. The request was successful because the dynamic client SSL context delegated to an appropriate client SSL context that has a requested certificate and truststore configured. If you tried to access the https://localhost:9443/ directly instead, the browser will require you to accept the server’s certificate and provide a client certificate.

Similarly, when you accessed the http://localhost:8080/proxy2, the reverse proxy redirected your request to https://localhost:10443/ and dynamic client SSL context delegated to a client SSL context that was configured specifically for the requested port.

Summary

This blog post explained why and how to configure the dynamic SSL context in both a standalone client and in a WildFly server. See the resources and WildFly documentation for more information.