How to configure SSL/HTTPS on WildFly

This is a complete tutorial about configuring SSL/HTTPS support for JBoss EAP / 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 such as 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 keystore file, which is a repository of certificates used for identifying a client or a server. Typically, a keystore contains one client or one server’s identity, which can optionally include 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 creates the keystore 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. PKCS12, on the other hand, is the 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 following 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.

Configuring Two-way SSL

On the other hand, 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 you can use 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 available in this script at:

Finally, we will also store 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" => undefined
}

The above command shows that there is no legacy ApplicationRealm bound to the https-listener. You can jump to the batch script below.

On the other hand, if the https-listener uses the legacy ApplicationRealm for its SSL configuration you need to undefine it first:

/subsystem=undertow/server=default-server/https-listener=https:undefine-attribute(name=security-realm)

Next, run the following CLI batch script. The script will add the keystores the key manager and the ssl-context configuration in the elytron subsystem. Finally, it will store the SSL Context information in the 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"])  

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

run-batch 

reload

You can find the above CLI script at:

Finally, try to access a WildFly through the https://localhost:8443 address. You will get a warning as 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.

As you can see from the Browser Developer Console, the Connection uses a Secure Socket Layer with the data from our Certificate:

wildfly configure https ssl

Alternatively, you can use the curl command with the –verbose option (-v) to see details about the SSL Handshake:

curl -v https://localhost:8443

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.

How to view your certificate

You can 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
---

As an alternative, you can also dump the Certificate from the CLI by referencing its keystore:

/subsystem=elytron/key-store=demoKeyStore:read-alias(alias=localhost,verbose=false)

Changes in your configuration

If you have completed the above steps, the following tls section should be in your XML Configuration:

<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>

Finally, 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 in place, 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 as follows:

[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, run the following CLI script:

/subsystem=elytron:write-attribute(name=initial-providers, value=combined-providers)
/subsystem=elytron:undefine-attribute(name=final-providers)
reload

You will see the following log that confirms your OpenSSL version:

19:06:23,403 INFO  [org.wildfly.openssl.SSL] (MSC service thread 1-3) WFOPENSSL0002 OpenSSL Version OpenSSL 1.1.1q  FIPS 5 Jul 2022

On the other hand, you can also choose to configure SSL as provider for a single SSL Context. For example, let’s switch to OpenSSL for the sample demoSSLContext. You can add the providers additional parameter to it:

/subsystem=elytron/server-ssl-context=demoSSLContext:add(key-manager=demoKeyManager,protocols=["TLSv1.2"],providers=openssl)

Finally, it’s worth mentioning that you can specify a custom path for the for the OpenSSL library by setting the org.wildfly.openssl.path System Property at server startup.

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)

Conclusion

This tutorial has covered how to configure TLS/SSL on WildFly 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

On the other hand, if you want to configure TLS/SSL for WildFly Management interfaces, check out this tutorial: Securing JBoss / WildFly Management Interfaces: the easy way