Configuring SSL/TLS communications
From JPPF 3.3 Documentation
|
Main Page > Configuration guide > Configuring SSL/TLS |
A JPPF grid has the ability to use secure connections between its components. This is done by using the SSL/TLS protocols over network connections, and provides security services such as peer authentication, data encryption and data integrity. This documentation aims at describing how to configure secure connections between JPPF servers, nodes and clients. If you wish to learn details of the SSL/TLS protocols in Java, our recommendation is to read about this in the Java Secure Socket Extension (JSSE) Reference Guide.
Additionally, all downloadable JPPF components now come with a predefined set of SSL configuration files, which can be used as-is for testing purposes. These files notably include a truststore and a keystore containing self-signed certificates and private keys. For real-world secure connectivity in JPPF, you will have to provide your own key- and trust- stores, with the proper certificate chains, validated by trusted certificate authorities.
1 Enabling secure connectivity
1.1 In the nodes and clients
Nodes and clients use either secure connections, or non-secure connections, but not both at the same time. Thus, this is determined from a single configuration property in their respective configuration file:
# Enable SSL. Default value is false (disabled)
# If enabled, only SSL/TLS connections are established
jppf.ssl.enabled = true
For a node, this also means that its embedded JMX server will only accept secure connections. Apart from the SSL configuration itself, no other properties are required to enable secure connections: the hosts and ports defined in the configuration or via server discovery will be assumed to be secure. If they are not, no connection will be possible.
1.2 In the servers
A JPPF server has the ability to accept both secure and non-secure connections, i.e. this is not a single on/off switch as for nodes and clients. Additionally, there are 3 areas of a JPPF server that can be configured separately: “standard” connections from nodes and clients (grid jobs handling and distributed class loader), connections to other servers and embedded JMX server. These are configured via the following properties in the server's configuration file:
# Port number to which the server listens for secure connections, defaults to 11443 # A negative value indicates that no secure connection is accepted jppf.ssl.server.port = 11443 # toggle to enable secure connections to remote peer servers, defaults to false jppf.peer.ssl.enabled = true # Enabling JMX features via secure connections, defaults to false jppf.management.ssl.enabled = true
Please note that jppf.ssl.server.port (secure port) comes in addition to jppf.server.port (non secure) and that both can be used together. For instance, if you wish to only accept secure connections, you will have to disable the non-secure connections by specifying a negative port number:
As for the non-secure port, assigning a value of 0 will cause JPPF to dynamically allocate a valid port number.
# disable non-secure connections jppf.server.port = -1 # enable secure connections jppf.ssl.server.port = 11443
In a similar way you can use either JMX secure or non-secure connections, or both:
# disable JMX via non-secure connections jppf.management.enabled = false # enable JMX via secure connections jppf.management.ssl.enabled = true # secure JMX server port jppf.management.ssl.port = 11193
2 Locating the SSL configuration
The SSL configuration is loaded separately from the JPPF configuration itself. The effect of this is that it is harder to find for a remote application, and it will not appear in the JPPF monitoring tools and APIs, the goal being to avoid providing information about how JPPF is secured, which would defeat the purpose of securing it in the first place.
2.1 Configuration as a file or classpath resource
To specify the location of the SSL configuration as a file, you can use the jppf.ssl.configuration.file property in the JPPF configuration file of the driver, node or client:
# location of the SSL configuration in the file system or classpath
jppf.ssl.configuration.file = config/ssl/ssl.properties
The lookup for the specified file or resource is performed first in the file system, then in the classpath. This allows you for instance to embed a configuration file in a jar file, with the possibility to override it with another file.
Relative paths are relative to the current working directory as specified by System.getProperty("user.dir").
2.2 Configuration as an external source
JPPF provides a more sophisticated way to locate its SSL configuration, which requires the implementation of a specific plugin. This is useful in situations where a configuration file is not considered secure enough, or if you need to load the configuration from a centralized location, for instance if you run JPPF in a cloud environment and want to fetch the configuration via a cloud storage facility such as Amazon's S3.
This is done via the jppf.ssl.configuration.source property:
# SSL configuration as an arbitrary source. Value is the fully qualified name
# of an implementation of java.util.concurrent.Callable<InputStream> with optional
# space-separated arguments
jppf.ssl.configuration.source = implementation_of_Callable<InputStream> arg1 ... argN
where implementation_of_Callable<InputStream> is the fully qualified name of a class which implements the interface Callable<InputStream> and which must have either a noarg constructor, or a (String...args) vararg constructor.
For example, the predefined JPPF plugin FileStoreSource is implemented as follows:
package org.jppf.ssl; import java.io.InputStream; import java.util.concurrent.Callable; import org.jppf.utils.FileUtils; // A secure store source that uses a file as source public class FileStoreSource implements Callable<InputStream> { // Optional arguments that may be specified in the configuration private final String[] args; public FileStoreSource(final String... args) throws Exception { this.args = args; if ((args == null) || (args.length == 0)) throw new SSLConfigurationException("missing parameter: file path"); } @Override public InputStream call() throws Exception { // lookup in the file system, then in the classpath InputStream is = FileUtils.getFileInputStream(args[0]); if (is == null) throw new SSLConfigurationException("could not find file " + args[0]); return is; } }
We can then use it in the configuration:
jppf.ssl.configuration.source = org.jppf.ssl.FileStoreSource config/ssl/ssl.properties
which is in fact equivalent to:
jppf.ssl.configuration.file = config/ssl/ssl.properties
3 SSL configuration properties
These properties are defined in the SSL configuration file and represent the information required to create and initialize SSLContext, SSLSocket and SSLEngine objects.
3.1 SSLContext protocol
This is the protocol name used in SSLContext.getInstance(String protocol). It is defined as:
# SSLContext protocol, defaults to SSL
jppf.ssl.context.protocol = SSL
A list of valid protocol names is available here.
3.2 Enabled protocol versions
This is the list of supported protocol versions, such as returned by SSLEngine.getEnabledProtocols(). It is defined as a list of space-separated names:
# list of space-separated enabled protocols
jppf.ssl.protocols = SSLv2Hello SSLv3
A list of valid protocol versions is available here.
3.3 Enabled cipher suites
This is the list of supported protocol versions, such as returned by SSLEngine.getEnabledCipherSuites(). It is defined as a list of space-separated names:
# enabled cipher suites as a list of space-separated values
jppf.ssl.cipher.suites = SSL_RSA_WITH_RC4_128_MD5 SSL_RSA_WITH_RC4_128_SHA
A list of supported cipher suites is available here.
3.4 Client authentication
The client authentication mode is determined by calling the methods SSLEngine.getWantClientAuth() and SSLEngine.getNeedClientAuth(). It is defined as:
# client authentication mode
# possible values: none | want | need
jppf.ssl.client.auth = none
3.5 Key store and associated password
As for the location of the SSL configuration, there are two ways to specify the location of a keystore:
# path to the key store on the file system jppf.ssl.keystore.file = config/ssl/keystore.ks # an implementation of Callable<InputStream> with optional space-separated arguments jppf.ssl.keystore.source = org.jppf.ssl.FileStoreSource config/ssl/keystore.ks
Note that, if both properties are defined, JPPF will first attempt to load the key store from the defined source, then from the specified file path.
In a similar fashion, there are two ways to specify the key store's password: either as a clear text password, or as a password source. This can be done as follows:
# keystore password in clear text jppf.ssl.keystore.password = password # keystore password from an arbitrary source # the source is an implementation of Callable<char[]> with optional parameters jppf.ssl.keystore.password.source = org.jppf.ssl.PlainTextPassword password
3.6 Trust store and associated password
The trust store and its password are defined in the same way as for the key store:
# path to the trust store on the file system jppf.ssl.truststore.file = config/ssl/truststore.ks # an implementation of Callable<InputStream> with optional space-separated arguments jppf.ssl.truststore.source = org.jppf.ssl.FileStoreSource config/ssl/truststore.ks # keystore password in clear text jppf.ssl.truststore.password = password # keystore password from an arbitrary source # the source is an implementation of Callable<char[]> with optional parameters jppf.ssl.truststore.password.source = org.jppf.ssl.PlainTextPassword password
3.7 Special case: distinct driver trust stores for nodes and clients
In the case when the JPPF driver has mutual authentication enabled (jppf.ssl.client.auth = need”), it might be desirable to use distinct trust stores for the certificates of the nodes and the clients that will connect to the driver. This can be done as follows:
# specify that a separate trust store must be used for client certificates jppf.ssl.client.distinct.truststore = true # path to the client trust store on the file system jppf.ssl.client.truststore.file = config/ssl/truststore_cli.ks # an implementation of Callable<InputStream> with optional space-separated arguments jppf.ssl.client.truststore.source = o.j.s.FileStoreSource config/ssl/truststore_cli.ks # keystore password in clear text jppf.ssl.client.truststore.password = password # keystore password from an arbitrary source # the source is an implementation of Callable<char[]> with opptional parameters jppf.ssl.client.truststore.password.source = org.jppf.ssl.PlainTextPassword password
In this configuration, a client will not be able to authenticate with the server, even if it uses the same keystore and password as the nodes.
4 Full SSL configuration example
# SSLContext protocol, defaults to SSL jppf.ssl.context.protocol = SSL # list of space-separated enabled protocols jppf.ssl.protocols = SSLv2Hello SSLv3 # enabled cipher suites as a list of space-separated values jppf.ssl.cipher.suites = SSL_RSA_WITH_RC4_128_MD5 SSL_RSA_WITH_RC4_128_SHA # client authentication mode; possible values: none | want | need jppf.ssl.client.auth = none # path to the key store on the file system. jppf.ssl.keystore.file = config/ssl/keystore.ks # keystore password in clear text jppf.ssl.keystore.password = password # the trust store location as an arbitrary source: # an implementation of Callable<InputStream> with optional space-separated arguments jppf.ssl.truststore.source = org.jppf.ssl.FileStoreSource config/ssl/truststore.ks # truststore password as an arbitrary source: # an implementation of Callable<char[]> with optional space-separated arguments jppf.ssl.truststore.password.source = org.jppf.ssl.PlainTextPassword password
Main Page > Configuration guide > Configuring SSL/TLS |