How to configure SSL/HTTPS on WildFly

This is a complete tutorial to show how to configure SSL/HTTPS support for exchanging keys, encrypting data, and authenticating message integrity on WildFly application server.

Generally speaking, to configure SSL/HTTPS you can either use the pure JSSE implementation (and the keytool utility) or a native implementation based on OpenSSL. We will cover at first the JSSE implementation with keytool. Later we will show how to enable OpenSSL on WildFly 11 or newer.

Create server and client certificates

The keytool utility stores the keys and certificates in a file termed as keystore, a repository of certificates used for identifying a client or a server. Typically, a keystore contains one client or one server’s identity, which are protected by using a password.

You can create a certificate for your server using the following command:

$  keytool -genkeypair -alias localhost -keyalg RSA -keysize 2048 -validity 365 -keystore server.keystore -dname "cn=Server Administrator,o=Acme,c=GB" -keypass secret -storepass secret

This command created the keystore named server.keystore in the working directory, with the password “secret” . It generates a public/private key pair for the entity whose “distinguished name” has a common name of Server Administrator , organization of Acme and two-letter country code of GB.

TIP: The message “The JKS keystore uses a proprietary format” simply reminds you that JKS is a format specific to Java, while PKCS12 is a standardized and language-neutral way of storing encrypted private keys and certificates. You can generate a PKCS12 format using the option -storetype PKCS12 or importing the JKS file into a PKCS12 one with the command keytool -importkeystore -srckeystore server.keystore -destkeystore server.keystore -deststoretype pkcs12

Now let’s store the server keystore into the configuration folder of the application server:

$ cp server.keystore $JBOSS_HOME/standalone/configuration

If you only need a one-way authentication (Server–>Client) then you are done.

Otherwise, if you need a two-way authentication (Server<–>Client) then we need to create as well the client certificates and export them to create a truststore.

The following command, will create the client certificate, which is used to authenticate against the server when accessing a resource through SSL:

$ keytool -genkeypair -alias client -keyalg RSA -keysize 2048 -validity 365 -keystore client.keystore -dname "CN=client" -keypass secret -storepass secret

Now export both the client and the server keystores in a certificate file:

$ keytool -exportcert  -keystore server.keystore -alias localhost -keypass secret -storepass secret -file server.crt
 
$ keytool -exportcert  -keystore client.keystore -alias client -keypass secret -storepass secret -file client.crt

Finally, import the certificates into the server’s and client’s truststores:

$ keytool -importcert -keystore server.truststore -storepass secret -alias client -trustcacerts -file client.crt -noprompt
 
$ keytool -importcert -keystore client.truststore -storepass secret -alias localhost -trustcacerts -file server.crt -noprompt

The above commands are contained in a shell script which is available at: http://bit.ly/2GB4PKV

Done with certificates, we will be storing as well the the client.truststore into the configuration folder of the application server:

$ cp client.truststore $JBOSS_HOME/standalone/configuration

Configuring One-Way SSL / HTTPS for WildFly applications

When using WildFly 11 or newer you can either use Elytron or the Legacy SSL configuration.

To verify which one is the default one check and see if the https-listener is configured to use a legacy security realm for its SSL configuration:

/subsystem=undertow/server=default-server/https-listener=https:read-attribute(name=security-realm)
{
    "outcome" => "success",
    "result" => "ApplicationRealm"
}

The above command shows that the https-listener is configured to use the legacy ApplicationRealm for its SSL configuration. Therefore we will undefine the security-realm attribute in the https-listener as Undertow cannot reference both a legacy security realm and an ssl-context in Elytron.

The following CLI batch script will add the keystores the key manager and the ssl context configuration in the elytron subsystem, removing the reference to the Undertow’s https-listener.

batch
# Configure Server Keystore 
/subsystem=elytron/key-store=demoKeyStore:add(path=server.keystore,relative-to=jboss.server.config.dir, credential-reference={clear-text=secret},type=JKS)
# Server Keystore credentials   
/subsystem=elytron/key-manager=demoKeyManager:add(key-store=demoKeyStore,credential-reference={clear-text=secret})
# Server keystore Protocols   
/subsystem=elytron/server-ssl-context=demoSSLContext:add(key-manager=demoKeyManager,protocols=["TLSv1.2"])  
# This is only needed if WildFly uses by default the Legacy security realm
/subsystem=undertow/server=default-server/https-listener=https:undefine-attribute(name=security-realm)
# Store SSL Context information in undertow 
/subsystem=undertow/server=default-server/https-listener=https:write-attribute(name=ssl-context,value=demoSSLContext)

run-batch 

reload

TIP: You can also define a default SSL Context to be used by the Elytron subsystem, by setting the property default-ssl-context that will reference to the SSLContext which should be globally registered as the default.

You can find the above CLI script at: http://bit.ly/2FGCMNg

That’s all. Now if you try to access a Web application through the https://localhost:8443 address, you will be informed that you are using a self-signed certificate. If you add an exception to the browser you will be running through the SSL channel, with your certificate. You can also dump your SSL session from the command line using openssl tool as follows:

$ openssl s_client -showcerts -connect localhost:8443

CONNECTED(00000003)
Can't use SSL_get_servername
depth=0 C = GB, O = Acme, CN = Server Administrator
verify error:num=18:self signed certificate
verify return:1
depth=0 C = GB, O = Acme, CN = Server Administrator
verify return:1
---
Certificate chain
 0 s:C = GB, O = Acme, CN = Server Administrator
   i:C = GB, O = Acme, CN = Server Administrator
-----BEGIN CERTIFICATE-----
MIIDFTCCAf2gAwIBAgIEYWcexzANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJH
QjENMAsGA1UEChMEQWNtZTEdMBsGA1UEAxMUU2VydmVyIEFkbWluaXN0cmF0b3Iw
HhcNMjEwMjI3MTEzNzQ3WhcNMjIwMjI3MTEzNzQ3WjA7MQswCQYDVQQGEwJHQjEN
MAsGA1UEChMEQWNtZTEdMBsGA1UEAxMUU2VydmVyIEFkbWluaXN0cmF0b3IwggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtBmaeo7l2/CaW+FPY5UZOnlOY
Pg4xQtr5SHIR7mF3Q5+jfxi4trGWia0yRd6ae0pBF3tyVQAf/C7gZDPRczxnshoc
TQD/7vtEJcUJ5N7k+DXqoFtn7vkXyFpvilSVT1PCnlkuAXD9jZnDhRl8xfs16pVQ
Sm+NxOGFLlsLr5iJWsGHSLmRqTrGPcY1aPbXAahGLtqE/rPwVGt4nXhbKV9s3tsD
LDQHOfsbbm8qbxmR47IdMR5XNx8vhJt+fhB/ZVgoFUw+CVMmEa8PfNxWY/fDFiPU
ePv3/ZRzagLfnlpN+vVZTaZsJUHysumfEhlpRjiqPWLXlk3SVfIboL6nrPfBAgMB
AAGjITAfMB0GA1UdDgQWBBRy5STkvTGZuddpCBPR+CcBXHzVXzANBgkqhkiG9w0B
AQsFAAOCAQEAc0NYtsjBBueHjc6hgeMZmBqq7agZ7IkRSNrHQTUtznYAD/K3aZU9
G4NbxZ+weHpsaJc9qg0zmdDjLgSmYOAR87OU0OAAXf47h2ZUMQIpdmJMf/swBXsH
/QmWS6CBmaGGm6ND29mNyzdRDwYbeG45j2DYZI9a1TK2x3WLS0H5on4qRcqUWElW
iItwR22QlKrWdiBcl0jSxxJNPdFU0DSCGNwJqByYalS6Z0d+AQG6y7BMIsdyLi06
zNP+8auhvex5LmUx8tEWO4pxhLe+G4iVm6XXVUkgw+6tBwDLzpaL+eL/EQZZWLbP
WrrpXVlYc/kuxq4iJtTFWEMCZEnzWblyYA==
-----END CERTIFICATE-----
---
Server certificate
subject=C = GB, O = Acme, CN = Server Administrator
issuer=C = GB, O = Acme, CN = Server Administrator

---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: ECDH, P-256, 256 bits
---
SSL handshake has read 1281 bytes and written 429 bytes
Verification error: self signed certificate
---
New, TLSv1.2, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES256-GCM-SHA384
    Session-ID: DFB40F6008C4BF507807DFBBDFD3E937195595E191221631EF20F18296C6F845
    Session-ID-ctx: 
    Master-Key: 87A7C384BE6F232D63903BC18CD385A6F29216CA1D0F281E9976785D89C990BE92E5B0F4C20618619B416407F6D24055
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1614426182
    Timeout   : 7200 (sec)
    Verify return code: 18 (self signed certificate)
    Extended master secret: yes
---

In terms of configuration, here is the tls section which has been added to WildFly:

<tls>
    <key-stores>
        <key-store name="demoKeyStore">
        <credential-reference clear-text="secret"/>
        <implementation type="JKS"/>
        <file path="server.keystore" relative-to="jboss.server.config.dir"/>
        </key-store>
    </key-stores>
    <key-managers>
        <key-manager name="demoKeyManager" key-store="demoKeyStore">
        <credential-reference clear-text="secret"/>
        </key-manager>
    </key-managers>
    <server-ssl-contexts>
        <server-ssl-context name="demoSSLContext" protocols="TLSv1.2" key-manager="demoKeyManager"/>
    </server-ssl-contexts>
</tls>

And here is the corresponding undertow section:

 <subsystem xmlns="urn:jboss:domain:undertow:10.0" default-server="default-server" default-virtual-host="default-host" default-servlet-container="default" default-security-domain="other" statistics-enabled="${wildfly.undertow.statistics-enabled:${wildfly.statistics-enabled:false}}">
          <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" ssl-context="demoSSLContext" enable-http2="true"/>
              <host name="default-host" alias="localhost">
                  <location name="/" handler="welcome-content"/>
                  <filter-ref name="server-header"/>
                  <filter-ref name="x-powered-by-header"/>
                  <http-invoker security-realm="ApplicationRealm"/>
              </host>
          </server>

Configuring Mutual SSL Authentication for WildFly applications

Mutual SSL provides the same security as SSL, with the addition of authentication and non-repudiation of the client authentication, using digital signatures. When mutual authentication is used, the server would request the client to provide a certificate in addition to the server certificate issued to the client. Mutual authentication requires an extra round trip time for client certificate exchange. In addition, the client must buy and maintain a digital certificate. We can secure our war application deployed over WildFly with mutual(two-way) client certificate authentication and provide access permissions or privileges to legitimate users.

IMPORTANT: It is assumed that you have already completed the One-Way SSL configuration for the server as discussed earlier in this tutorial!

In order to update your One-Way configuration to use Mutual SSL configuration, we need a SSL Context which includes also the Client Truststore and TrustManager in its configuration:

batch
 
# Add the Truststore, TrustManager to a SSL Context configuration
/subsystem=elytron/key-store=demoTrustStore:add(path=client.truststore,relative-to=jboss.server.config.dir,type=JKS,credential-reference={clear-text=secret})

/subsystem=elytron/trust-manager=demoTrustManager:add(key-store=demoTrustStore)

/subsystem=elytron/server-ssl-context=twoWaySSL:add(key-manager=demoKeyManager,trust-manager=demoTrustManager,protocols=[TLSv1.2],need-client-auth=true)

# This is only needed if WildFly uses by default the Legacy security realm 
/subsystem=undertow/server=default-server/https-listener=https:undefine-attribute(name=security-realm)

# Store SSL Context information in undertow 
/subsystem=undertow/server=default-server/https-listener=https:write-attribute(name=ssl-context,value=twoWaySSL)
 
run-batch

reload

Using the CLI security command to configure One-Way HTTPS

If you prefer, a simpler way to enable SSL for the HTTP server is by means of the **security enable-ssl-http-server** CLI command. This command has the advantage of combining the definition of the key-store, key-manager and ssl-context in just one command. So, assumed that the file server.keystore is in the same folder as the jboss-cli, you can enable SSL for the HTTP server with just this command:

[standalone@localhost:9990 /] security enable-ssl-http-server --key-store-path=server.keystore --key-store-password=secret 

Server reloaded. SSL enabled for default-server ssl-context is ssl-context-server.keystore key-manager is key-manager-server.keystore key-store is server.keystore

Your One-Way SSL configuration is ready and the server has been reloaded for you to reflect the changes. You can also use the **–interactive** option which will let you create also the keystore. Here is a transcript of a sample ssl configuration for the HTTP server which will eventually create the file wildfly.keystore, the certificate file wildfly.pem and wildfly.csr file in server configuration directory:

[standalone@localhost:9990 /] security enable-ssl-http-server --interactive
Please provide required pieces of information to enable SSL:

Certificate info:
Key-store file name (default default-server.keystore): wildfly.keystore
Password (blank generated): password
What is your first and last name? [Unknown]: John Smith
What is the name of your organizational unit? [Unknown]: QA
What is the name of your organization? [Unknown]: Acme
What is the name of your City or Locality? [Unknown]: London
What is the name of your State or Province? [Unknown]: 
What is the two-letter country code for this unit? [Unknown]: UK
Is CN=John Smith, OU=QA, O=Acme, L=London, ST=Unknown, C=UK correct y/n [y]?y
Validity (in days, blank default): 
Alias (blank generated): jsmith
Enable SSL Mutual Authentication y/n (blank n):n

SSL options:
key store file: wildfly.keystore
distinguished name: CN=John Smith, OU=QA, O=Acme, L=London, ST=Unknown, C=UK
password: password
validity: default
alias: jsmith
Server keystore file wildfly.keystore, certificate file wildfly.pem and wildfly.csr file will be generated in server configuration directory.

Do you confirm y/n :y
Server reloaded.
SSL enabled for default-server
ssl-context is ssl-context-24f3d44b-a511-4b54-9610-ac414a8b6143
key-manager is key-manager-24f3d44b-a511-4b54-9610-ac414a8b6143
key-store   is key-store-24f3d44b-a511-4b54-9610-ac414a8b6143

Configuring OpenSSL as provider

When using Elytron for SSL/HTTPS you can opt for two different providers:

<providers>
        <aggregate-providers name="combined-providers">
            <providers name="openssl"/>
            <providers name="elytron"/>
        </aggregate-providers>
        <provider-loader name="elytron" module="org.wildfly.security.elytron"/>
        <provider-loader name="openssl" module="org.wildfly.openssl"/>
</providers> 

In order to switch to OpenSSL, at first set your security Realm to use OpenSSL TSL as protocol:

/core-service=management/security-realm=ApplicationRealm/server-identity=ssl:write-attribute(name=protocol, value=openssl.TLS)

This will show in your console that the OpenSSL protocol has been loaded:

12:08:00,027 INFO  [org.wildfly.openssl.SSL] (MSC service thread 1-7) WFOPENSSL0002 OpenSSL Version OpenSSL 1.0.2j-fips  26 Sep 2016

Next, we need to change the ordering of the providers in the elytron combined-providers, which means that OpenSSL will now take precedence:

/subsystem=elytron/aggregate-providers=combined-providers:list-add(index=0, name=providers, value=openssl)
/subsystem=elytron/aggregate-providers=combined-providers:list-remove(index=2, name=providers)

Configuring SSL using Legacy mode

If you are using an earlier version of WildFly (8/9/10) or you simply don’t want to use Elytron as security mechanism, you can still use the Legacy security for securing your HTTP communication.

Start by creating a Security Realm which will contain the keystore and trustore references

/core-service=management/security-realm=SSLRealm:add

Next, for one-way SSL, set the path to the keystore, along with the keystore path and password:

/core-service=management/security-realm=SSLRealm/server-identity=ssl:add(keystore-path="server.keystore", keystore-relative-to="jboss.server.config.dir", keystore-password="secret")

If you are using mutual authentication, you will need to set the path to the truststore, along with the its path and password:

/core-service=management/security-realm=SSLRealm/authentication=truststore:add(keystore-password="secret",keystore-path="server.truststore",keystore-relative-to="jboss.server.config.dir")

Finally, set the value of Undertow’s https listener to your Security Realm:

/subsystem=undertow/server=default-server/https-listener=default-https:write-attribute(name=security-realm,value=SSLRealm)

This tutorial has covered how to configure TLS/SSL on WldFly application server. If you want to use the latest version of TLS (1.3), you can continue reading here: Configuring TLS 1.3 on WildFly application Server