Skip to content

Commit fbf364b

Browse files
olim7tAlexandre Dutra
authored andcommitted
JAVA-917: Document SSL configuration.
1 parent 946e7c7 commit fbf364b

2 files changed

Lines changed: 66 additions & 63 deletions

File tree

changelog/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
- [bug] JAVA-986: Update documentation links to reference 3.0.
1313
- [improvement] JAVA-841: Refactor SSLOptions API.
1414
- [improvement] JAVA-948: Don't limit cipher suites by default.
15+
- [improvement] JAVA-917: Document SSL configuration.
1516

1617
Merged from 2.1 branch:
1718

features/ssl/README.md

Lines changed: 65 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,11 @@ if you've followed the steps for inter-node encryption).
7171

7272
### Driver configuration
7373

74-
#### Property-based
74+
The base class to configure SSL is [SSLOptions]. It's very generic, but
75+
you don't necessarily need to deal with it directly: the default
76+
instance, or the provided subclasses, might be enough for your needs.
77+
78+
#### JSSE, Property-based
7579

7680
`withSSL()` gives you a basic JSSE configuration:
7781

@@ -94,87 +98,85 @@ for specific details, like keystore locations and passwords:
9498
-Djavax.net.ssl.keyStorePassword=password123
9599
```
96100

97-
#### Programmatic
101+
#### JSSE, programmatic
98102

99103
If you need more control than what system properties allow, you can
100-
configure SSL programmatically by creating an [SSLOptions] instance:
104+
configure SSL programmatically with [JdkSSLOptions]:
101105

102106
```java
103107
SSLContext sslContext = ... // create and configure SSL context
104-
String[] cipherSuites = ...
105108

106-
SSLOptions sslOptions = new SSLOptions(sslContext, cipherSuites);
109+
JdkSSLOptions sslOptions = JdkSSLOptions.builder()
110+
.withSSLContext(context)
111+
.build();
107112

108113
Cluster cluster = Cluster.builder()
109114
.addContactPoint("127.0.0.1")
110115
.withSSL(sslOptions)
111116
.build();
112117
```
113118

114-
A known limitation of the current API is that you can't customize the
115-
`SSLEngine`, which prevents advanced features like hostname
116-
verification. This will be fixed in 3.0 (see
117-
[JAVA-841](https://datastax-oss.atlassian.net/browse/JAVA-841)), in the
118-
meantime see below for a workaround.
119+
Note that you can also extend the class and override
120+
[newSSLEngine(SocketChannel)][newSSLEngine] if you need specific
121+
configuration on the `SSLEngine` (for example hostname verification).
122+
123+
[newSSLEngine]: http://docs.datastax.com/en/drivers/java/3.0/com/datastax/driver/core/JdkSSLOptions.html#newSSLEngine(io.netty.channel.socket.SocketChannel)
124+
125+
#### Netty
126+
127+
[NettySSLOptions] allows you to use Netty's `SslContext` instead of
128+
the JDK directly. The advantage is that Netty can use OpenSSL if
129+
available, which provides better performance.
130+
131+
##### Converting your client certificates for OpenSSL
132+
133+
OpenSSL doesn't use keystores, so if you use client authentication and
134+
generated your certificates with keytool, you need to convert them.
135+
136+
* use this command to extract the public certificate chain:
119137

138+
```
139+
keytool -export -keystore client.keystore -alias client -rfc -file client.crt
140+
```
141+
* follow
142+
[this tutorial](http://www.herongyang.com/crypto/Migrating_Keys_keytool_to_OpenSSL_3.html)
143+
to extract your client's private key from `client.keystore` to a text
144+
file `client.key` in PEM format.
120145
121-
### Bypassing `SSLOptions`
146+
##### Updating your dependencies
122147
123-
For advanced use cases, it's possible to bypass `SSLOptions` entirely:
124-
since the driver provides a hook into the Netty pipeline (by way of
125-
[NettyOptions]), you can add the SSL handler yourself:
148+
Netty-tcnative provides the native integration with OpenSSL. Follow
149+
[these instructions](http://netty.io/wiki/forked-tomcat-native.html) to
150+
add it to your dependencies.
151+
152+
##### Configuring the context
153+
154+
Use the following Java code to configure OpenSSL with your certificates:
126155
127156
```java
128-
import io.netty.handler.ssl.SslHandler;
129-
import javax.net.ssl.SSLContext;
130-
import javax.net.ssl.SSLEngine;
131-
132-
// Base implementation: each time a connection is established, create an SSL handler
133-
// and add it to the pipeline:
134-
public abstract class SslNettyOptions extends NettyOptions {
135-
@Override
136-
public void afterChannelInitialized(SocketChannel channel) throws Exception {
137-
channel.pipeline().addFirst("ssl", createSslHandler(channel));
138-
}
139-
140-
protected abstract SslHandler createSslHandler(SocketChannel channel);
141-
}
142-
143-
// Concrete implementation based on JSSE
144-
public class MyNettyOptions extends SslNettyOptions {
145-
146-
private final SSLContext sslContext = createContext();
147-
148-
protected SslHandler createSslHandler(SocketChannel channel) {
149-
return new SslHandler(createEngine(sslContext, channel));
150-
}
151-
152-
private static SSLContext createContext() {
153-
... // create and configure context
154-
}
155-
156-
private static SSLEngine createEngine(SSLContext sslContext, SocketChannel channel) {
157-
SSLEngine engine = sslContext.createSSLEngine();
158-
engine.setUseClientMode(true);
159-
... // any extra configuration
160-
return engine;
161-
}
162-
}
163-
164-
cluster = Cluster.builder()
157+
KeyStore ks = KeyStore.getInstance("JKS");
158+
// make sure you close this stream properly (not shown here for brevity)
159+
InputStream trustStore = new FileInputStream("client.truststore");
160+
ks.load(trustStore, "password123".toCharArray());
161+
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
162+
tmf.init(ks);
163+
164+
SslContextBuilder builder = SslContextBuilder
165+
.forClient()
166+
.sslProvider(SslProvider.OPENSSL)
167+
.trustManager(tmf);
168+
// only if you use client authentication
169+
.keyManager(new File("client.crt"), new File("client.key"));
170+
171+
SSLOptions sslOptions = new NettySSLOptions(builder.build());
172+
173+
Cluster cluster = Cluster.builder()
165174
.addContactPoint("127.0.0.1")
166-
.withNettyOptions(new MyNettyOptions())
175+
.withSSL(sslOptions)
167176
.build();
168177
```
169178

170-
This could be used for the following use cases:
171-
172-
* fine control over JSSE configuration, for example tuning the SSL
173-
engine for hostname verification;
174-
* bypassing JSSE altogether in favor of another SSL implementation:
175-
recent Netty versions support
176-
[OpenSSL](http://netty.io/wiki/forked-tomcat-native.html)
177-
for improved performance.
178-
179-
[SSLOptions]: http://docs.datastax.com/en/drivers/java/2.1/com/datastax/driver/core/SSLOptions.html
180-
[NettyOptions]: http://docs.datastax.com/en/drivers/java/2.1/com/datastax/driver/core/NettyOptions.html
179+
[SSLOptions]: http://docs.datastax.com/en/drivers/java/3.0/com/datastax/driver/core/SSLOptions.html
180+
[JdkSSLOptions]: http://docs.datastax.com/en/drivers/java/3.0/com/datastax/driver/core/JdkSSLOptions.html
181+
[NettySSLOptions]: http://docs.datastax.com/en/drivers/java/3.0/com/datastax/driver/core/NettySSLOptions.html
182+
[NettyOptions]: http://docs.datastax.com/en/drivers/java/3.0/com/datastax/driver/core/NettyOptions.html

0 commit comments

Comments
 (0)