Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 23 additions & 32 deletions docs/source/topics/security/tls.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,11 @@ Some notes on this guide:

### Generating the ScyllaDB/Cassandra Public and Private Keys

The most secure method of setting up TLS is to verify that DNS or IP address used to connect to the server matches identity information found in the TLS certificate. This helps to prevent man-in-the-middle attacks. ScyllaDB/Cassandra uses IP addresses internally so those can be used directly for verification or a domain name can be used via reverse DNS (PTR record). That means that the IP address or domain name of the ScyllaDB/Cassandra server where the certficate is installed needs to be present in either the certficate's common name (CN) or one of its subject alternative names (SANs). It's possible to create the certficate without either, but then it will not be possible to verify the server's identity. Although this is not as secure, it eases the deployment of TLS by allowing the same certficate to be deployed across the entire ScyllaDB/Cassandra cluster.
The most secure method of setting up TLS is to verify that DNS or IP address used to connect to the server matches identity information found in the TLS certificate. This helps to prevent man-in-the-middle attacks. ScyllaDB/Cassandra uses IP addresses internally so those can be used directly for verification (a domain name currently cannot be used via reverse DNS - PTR record). That means that the IP address of the ScyllaDB/Cassandra server where the certificate is installed needs to be present in one of the certificate's subject alternative names (SANs). It's possible to create the certificate without them, but then it will not be possible to verify the server's identity. Although this is not as secure, it eases the deployment of TLS by allowing the same certificate to be deployed across the entire ScyllaDB/Cassandra cluster.

To generate a public/private key pair with the IP address in the CN field use the following:
**NOTE:** this driver verifies the identity against subject alternative names of type `iPAddress` only; unlike the CPP driver, it does not fall back to the common name (CN). Prefer the SAN recipe below. A CN-only certificate can still be used, but only with identity verification relaxed to `CASS_SSL_VERIFY_PEER_CERT` or disabled with `CASS_SSL_VERIFY_NONE`.

```bash
keytool -genkeypair -noprompt -keyalg RSA -validity 36500 \
-alias node \
-keystore keystore.jks \
-storepass <keystore password> \
-keypass <key password> \
-dname "CN=<IP address or domain name goes here>, OU=Drivers and Tools, O=DataStax Inc., L=Santa Clara, ST=California, C=US"
```

If SAN is preferred use this command:
To generate a public/private key pair with the IP address in the SAN field use the following:

```bash
keytool -genkeypair -noprompt -keyalg RSA -validity 36500 \
Expand All @@ -37,8 +28,6 @@ keytool -genkeypair -noprompt -keyalg RSA -validity 36500 \
-dname "CN=node1.datastax.com, OU=Drivers and Tools, O=DataStax Inc., L=Santa Clara, ST=California, C=US"
```

**NOTE:** If an IP address SAN is present then it overrides checking the CN.

### Enabling `client-to-node` Encryption on ScyllaDB/Cassandra

The generated keystore from the previous step will need to be copied to all ScyllaDB/Cassandra node(s) and an update of the `cassandra.yaml` configuration file will need to be performed.
Expand Down Expand Up @@ -163,38 +152,40 @@ cass_ssl_set_verify_flags(ssl, CASS_SSL_VERIFY_NONE);
cass_ssl_free(ssl);
```

#### Enabling ScyllaDB/Cassandra identity verification
#### ScyllaDB/Cassandra identity verification

If a unique certificate has been generated for each ScyllaDB/Cassandra node with the IP address or domain name in the CN or SAN fields, you also need to enable identity verification.
If a unique certificate has been generated for each ScyllaDB/Cassandra node with
the IP address in the SAN field, the driver verifies that the node it connected
to is the one the certificate was issued for.

**NOTE:** This is disabled by default.
**NOTE:** This is disabled by default. This is part of `CASS_SSL_VERIFY_PEER_IDENTITY`.
The flags form a bitmask, so it can be requested explicitly on its own or combined with `CASS_SSL_VERIFY_PEER_CERT`:

```c
CassSsl* ssl = cass_ssl_new();

// Add identity verification flag: CASS_SSL_VERIFY_PEER_IDENTITY (IP address)
// Verify the certificate chain and the peer's identity (IP address).
cass_ssl_set_verify_flags(ssl, CASS_SSL_VERIFY_PEER_CERT | CASS_SSL_VERIFY_PEER_IDENTITY);

// Or use: CASS_SSL_VERIFY_PEER_IDENTITY_DNS (domain name)
cass_ssl_set_verify_flags(ssl, CASS_SSL_VERIFY_PEER_CERT | CASS_SSL_VERIFY_PEER_IDENTITY_DNS);
```

If using a domain name to verify the peer's identity then hostname resolution
(reverse DNS) needs to be enabled:
**NOTE:** the identity is matched against the certificate's subject alternative
names of type `iPAddress` only. Unlike the C/C++ driver, this driver does not
fall back to the subject common name (CN), so a certificate that identifies a
node only by CN is rejected.

**NOTE:** This is also disabled by default.
To validate the certificate chain without checking who the peer claims to be —
useful with a single certificate shared by all nodes — ask for
`CASS_SSL_VERIFY_PEER_CERT` alone:

```c
CassCluster* cluster = cass_cluster_new();

// Enable reverse DNS
cass_cluster_set_use_hostname_resolution(cluster, cass_true);

/* ... */

cass_cluster_free(cluster);
// Verify the certificate chain only; the peer's identity is not checked.
cass_ssl_set_verify_flags(ssl, CASS_SSL_VERIFY_PEER_CERT);
```

Verifying the identity against a domain name rather than an IP address
(`CASS_SSL_VERIFY_PEER_IDENTITY_DNS`) is **not supported**; it is accepted, but
treated as `CASS_SSL_VERIFY_PEER_IDENTITY`.

### Using ScyllaDB/Cassandra and the C/C++ driver with client-side certificates

Client-side certificates allow ScyllaDB/Cassandra to authenticate the client using public key cryptography and chains of trust. This is same process as above but in reverse. The client has a public and private key and the ScyllaDB/Cassandra node has a copy of the private key or the CA chain used to generate the pair.
Expand Down
15 changes: 11 additions & 4 deletions include/cassandra.h
Original file line number Diff line number Diff line change
Expand Up @@ -4302,14 +4302,21 @@ cass_ssl_add_trusted_cert_n(CassSsl* ssl,
*
* CASS_SSL_VERIFY_NONE - No verification is performed
* CASS_SSL_VERIFY_PEER_CERT - Certificate is present and valid
* CASS_SSL_VERIFY_PEER_IDENTITY - IP address matches the certificate's
* common name or one of its subject alternative names. This implies the
* certificate is also present.
* CASS_SSL_VERIFY_PEER_IDENTITY - IP address matches one of the certificate's
* subject alternative names of type iPAddress. This implies the certificate
* is also present.
* NOTE: unlike the C/C++ driver, the subject common name (CN) is NOT
* consulted. A certificate that identifies the node only by CN, with no
* iPAddress subject alternative name (SAN), is rejected. This follows from
* OpenSSL's X509_VERIFY_PARAM_set1_ip() (called by Rust Driver), which
* never falls back to the subject for IP address checks. Note that modern
* practices advocate for using SAN, and consider CN obsolete.
* CASS_SSL_VERIFY_PEER_IDENTITY_DNS - Hostname matches the certificate's
* common name or one of its subject alternative names. This implies the
* certificate is also present. Hostname resolution must also be enabled.
* NOTE: not supported; treated as CASS_SSL_VERIFY_PEER_IDENTITY.
*
* <b>Default:</b> CASS_SSL_VERIFY_NONE
* <b>Default:</b> CASS_SSL_VERIFY_PEER_CERT
*
* @public @memberof CassSsl
*
Expand Down
1 change: 1 addition & 0 deletions scylla-rust-wrapper/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ fn main() {
],
&out_path,
);
prepare_cppdriver_data("cppdriver_ssl_types.rs", &["CassSslVerifyFlags"], &out_path);
prepare_cppdriver_data(
"cppdriver_host_listener_types.rs",
&["CassHostListenerEvent", "CassHostListenerCallback"],
Expand Down
9 changes: 9 additions & 0 deletions scylla-rust-wrapper/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,15 @@ pub(crate) mod cass_authenticator_types {
include_bindgen_generated!("cppdriver_authenticator_types.rs");
}

/// CassSsl
pub(crate) mod cass_ssl_types {
#![allow(unused)]
#![allow(non_camel_case_types, non_snake_case)]
#![allow(unreachable_pub, unnameable_types)]

include_bindgen_generated!("cppdriver_ssl_types.rs");
}

/// CassHostListenerEvent, CassHostListenerCallback
pub(crate) mod cass_host_listener_types {
#![allow(unused)]
Expand Down
Loading
Loading