Skip to main content

Overview

The ScyllaDB Rust Driver supports encrypted connections using TLS/SSL. This is essential for production environments where you need to protect data in transit. The driver supports two TLS implementations:
  • OpenSSL 0.10 (feature: openssl-010)
  • Rustls 0.23 (feature: rustls-023)
By default, TLS is disabled. To enable it, you must configure a TlsContext on the SessionBuilder.

TLS Context

The TlsContext enum abstracts over different TLS implementations:
#[non_exhaustive]
pub enum TlsContext {
    /// TLS context backed by OpenSSL 0.10.
    #[cfg(feature = "openssl-010")]
    OpenSsl010(openssl::ssl::SslContext),
    
    /// TLS context backed by Rustls 0.23.
    #[cfg(feature = "rustls-023")]
    Rustls023(Arc<rustls::ClientConfig>),
}
The TlsContext is cheaply clonable (reference-counted) and can be converted from either OpenSSL’s SslContext or Rustls’s ClientConfig.

OpenSSL Configuration

Prerequisites

Enable the openssl-010 feature in your Cargo.toml:
[dependencies]
scylla = { version = "*", features = ["openssl-010"] }
openssl = "0.10"

Basic OpenSSL Example

use scylla::client::session_builder::SessionBuilder;
use scylla::client::session::Session;
use openssl::ssl::{SslContextBuilder, SslMethod, SslVerifyMode};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut context_builder = SslContextBuilder::new(SslMethod::tls())?;
    context_builder.set_verify(SslVerifyMode::NONE);

    let session: Session = SessionBuilder::new()
        .known_node("127.0.0.1:9142")  // Note: TLS port is typically 9142
        .tls_context(Some(context_builder.build()))
        .build()
        .await?;

    Ok(())
}

OpenSSL with Certificate Verification

For production environments, you should verify the server certificate:
use std::fs;
use std::path::PathBuf;
use openssl::ssl::{SslContextBuilder, SslMethod, SslVerifyMode, SslFiletype};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut context_builder = SslContextBuilder::new(SslMethod::tls())?;
    
    // Load CA certificate
    let ca_dir = fs::canonicalize(PathBuf::from("./test/tls/ca.crt"))?;
    context_builder.set_ca_file(ca_dir.as_path())?;
    
    // Enable peer verification
    context_builder.set_verify(SslVerifyMode::PEER);

    let session: Session = SessionBuilder::new()
        .known_node("127.0.0.1:9142")
        .tls_context(Some(context_builder.build()))
        .build()
        .await?;

    Ok(())
}

Complete OpenSSL Example

Here’s a complete example based on the driver’s test suite:
use anyhow::Result;
use std::env;
use std::fs;
use std::path::PathBuf;
use openssl::ssl::{SslContextBuilder, SslMethod, SslVerifyMode};
use scylla::client::session::Session;
use scylla::client::session_builder::SessionBuilder;

#[tokio::main]
async fn main() -> Result<()> {
    // Get the URI (default to TLS port 9142)
    let uri = env::var("SCYLLA_URI")
        .unwrap_or_else(|_| "127.0.0.1:9142".to_string());

    println!("Connecting to {uri} with TLS...");

    // Create SSL context
    let mut context_builder = SslContextBuilder::new(SslMethod::tls())?;
    let ca_dir = fs::canonicalize(PathBuf::from("./test/tls/ca.crt"))?;
    context_builder.set_ca_file(ca_dir.as_path())?;
    context_builder.set_verify(SslVerifyMode::PEER);

    // Build session with TLS
    let session: Session = SessionBuilder::new()
        .known_node(uri)
        .tls_context(Some(context_builder.build()))
        .build()
        .await?;

    // Create keyspace and table
    session.query_unpaged(
        "CREATE KEYSPACE IF NOT EXISTS examples_ks \
         WITH REPLICATION = {'class': 'NetworkTopologyStrategy', 'replication_factor': 1}",
        &[],
    ).await?;

    session.query_unpaged(
        "CREATE TABLE IF NOT EXISTS examples_ks.tls \
         (a int, b int, c text, primary key (a, b))",
        &[],
    ).await?;

    // Insert data
    session.query_unpaged(
        "INSERT INTO examples_ks.tls (a, b, c) VALUES (?, ?, ?)",
        (1, 2, "abc"),
    ).await?;

    println!("Successfully connected and executed queries with TLS");

    Ok(())
}

Rustls Configuration

Prerequisites

Enable the rustls-023 feature in your Cargo.toml:
[dependencies]
scylla = { version = "*", features = ["rustls-023"] }
rustls = "0.23"
rustls-pki-types = "1"

Basic Rustls Example

use std::sync::Arc;
use scylla::client::session_builder::SessionBuilder;
use scylla::client::session::Session;
use rustls::RootCertStore;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let root_store = RootCertStore::empty();
    
    let config = Arc::new(
        rustls::ClientConfig::builder()
            .with_root_certificates(root_store)
            .with_no_client_auth(),
    );

    let session: Session = SessionBuilder::new()
        .known_node("127.0.0.1:9142")
        .tls_context(Some(config))
        .build()
        .await?;

    Ok(())
}

Rustls with Certificate Verification

use std::sync::Arc;
use rustls::pki_types::{CertificateDer, pem::PemObject};
use rustls::RootCertStore;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Load CA certificate from PEM file
    let rustls_ca = CertificateDer::from_pem_file("./test/tls/ca.crt")?;
    
    // Create root certificate store and add CA
    let mut root_store = RootCertStore::empty();
    root_store.add(rustls_ca)?;

    // Build client config with certificate verification
    let config = Arc::new(
        rustls::ClientConfig::builder()
            .with_root_certificates(root_store)
            .with_no_client_auth(),
    );

    let session: Session = SessionBuilder::new()
        .known_node("127.0.0.1:9142")
        .tls_context(Some(config))
        .build()
        .await?;

    Ok(())
}

Complete Rustls Example

Here’s a complete example based on the driver’s test suite:
use std::{env, sync::Arc};
use anyhow::Result;
use rustls::pki_types::{CertificateDer, pem::PemObject};
use scylla::client::{session::Session, session_builder::SessionBuilder};

#[tokio::main]
async fn main() -> Result<()> {
    // Get the URI (default to TLS port 9142)
    let uri = env::var("SCYLLA_URI")
        .unwrap_or_else(|_| "127.0.0.1:9142".to_string());

    println!("Connecting to {uri} with TLS (Rustls)...");

    // Load CA certificate
    let rustls_ca = CertificateDer::from_pem_file("./test/tls/ca.crt")?;
    let mut root_store = rustls::RootCertStore::empty();
    root_store.add(rustls_ca)?;

    // Build session with TLS
    let session: Session = SessionBuilder::new()
        .known_node(uri)
        .tls_context(Some(Arc::new(
            rustls::ClientConfig::builder()
                .with_root_certificates(root_store)
                .with_no_client_auth(),
        )))
        .build()
        .await?;

    // Create keyspace and table
    session.query_unpaged(
        "CREATE KEYSPACE IF NOT EXISTS examples_ks \
         WITH REPLICATION = {'class': 'NetworkTopologyStrategy', 'replication_factor': 1}",
        &[],
    ).await?;

    session.query_unpaged(
        "CREATE TABLE IF NOT EXISTS examples_ks.tls \
         (a int, b int, c text, primary key (a, b))",
        &[],
    ).await?;

    // Insert data
    session.query_unpaged(
        "INSERT INTO examples_ks.tls (a, b, c) VALUES (?, ?, ?)",
        (1, 2, "abc"),
    ).await?;

    println!("Successfully connected and executed queries with TLS");

    Ok(())
}

Setting Up ScyllaDB with TLS

To enable TLS on your ScyllaDB server, edit your scylla.yaml configuration file:
client_encryption_options:
    enabled: true
    certificate: /etc/scylla/db.crt
    keyfile: /etc/scylla/db.key

Using Docker

If running ScyllaDB in Docker, mount your configuration and certificates:
docker run -d \
  --volume $(pwd)/scylla.yaml:/etc/scylla/scylla.yaml:Z \
  --volume $(pwd)/certs:/etc/scylla/certs:Z \
  -p 9142:9142 \
  scylladb/scylla
The :Z flag is used on SELinux systems to properly set file permissions.

Port Configuration

  • Standard port: 9042 (non-TLS)
  • TLS port: 9142 (TLS-enabled)
  • Shard-aware port: 19042 (non-TLS)
  • Shard-aware TLS port: 19142 (TLS-enabled)
When connecting with TLS, make sure to use the appropriate port (typically 9142).

Combining TLS with Authentication

You can (and should) combine TLS with authentication for maximum security:
use openssl::ssl::{SslContextBuilder, SslMethod, SslVerifyMode};

let mut context_builder = SslContextBuilder::new(SslMethod::tls())?;
context_builder.set_verify(SslVerifyMode::PEER);
// ... configure certificates ...

let session: Session = SessionBuilder::new()
    .known_node("127.0.0.1:9142")
    .user("cassandra", "cassandra")
    .tls_context(Some(context_builder.build()))
    .build()
    .await?;

TLS Error Handling

TLS errors are wrapped in the TlsError enum:
#[non_exhaustive]
pub enum TlsError {
    #[cfg(feature = "openssl-010")]
    OpenSsl010(openssl::error::ErrorStack),
    
    #[cfg(feature = "rustls-023")]
    InvalidName(rustls::pki_types::InvalidDnsNameError),
    
    #[cfg(feature = "rustls-023")]
    PemParse(rustls::pki_types::pem::Error),
    
    #[cfg(feature = "rustls-023")]
    Rustls023(rustls::Error),
}
These errors automatically convert to std::io::Error for easier error handling.

Disabling TLS

To explicitly disable TLS (or revert after setting it):
let session: Session = SessionBuilder::new()
    .known_node("127.0.0.1:9042")
    .tls_context(None)
    .build()
    .await?;

Security Best Practices

Production Security Checklist:
  1. Always verify certificates - Use SslVerifyMode::PEER or configure proper root certificates
  2. Use strong TLS versions - Avoid TLS 1.0 and 1.1
  3. Protect private keys - Never commit private keys to source control
  4. Use proper CA certificates - Don’t use self-signed certificates in production
  5. Combine with authentication - TLS encrypts transport, but you still need authentication
  6. Rotate certificates - Implement a certificate rotation strategy

Choosing Between OpenSSL and Rustls

OpenSSL

Advantages:
  • Mature and widely tested
  • Extensive feature set
  • Common in many systems
Use when:
  • You need compatibility with existing OpenSSL infrastructure
  • Your system already has OpenSSL installed

Rustls

Advantages:
  • Pure Rust implementation
  • Memory safe
  • Modern TLS implementation
  • Smaller dependency footprint
Use when:
  • You prefer pure Rust dependencies
  • You want memory safety guarantees
  • You’re building a new system from scratch

See Also

Authentication

Configure username/password or custom authentication

Connection Overview

Learn about basic connection configuration

Build docs developers (and LLMs) love