Skip to content

Commit

Permalink
Add rustls example; Incorporate rustls into github action workflows
Browse files Browse the repository at this point in the history
  • Loading branch information
nemosupremo committed Jan 12, 2024
1 parent 8edd689 commit 15b3c80
Show file tree
Hide file tree
Showing 7 changed files with 212 additions and 31 deletions.
11 changes: 8 additions & 3 deletions .github/workflows/tls.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,13 @@ jobs:
working-directory: ./scylla
steps:
- uses: actions/checkout@v3
- name: Check
- name: Check OpenSSL
run: cargo check --verbose --features "ssl"
working-directory: ${{env.working-directory}}
- name: Run tls example
run: cargo run --example tls
- name: Check OpenSSL
run: cargo check --verbose --features "rustls"
working-directory: ${{env.working-directory}}
- name: Run OpenSSL example
run: cargo run --features "ssl" --example tls
- name: Run rustls example
run: cargo run --features "rustls" --example rustls
18 changes: 16 additions & 2 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,19 @@ name = "examples"
publish = false
version = "0.0.0"

[features]
rustls = ["scylla/rustls"]
cloud = ["scylla/cloud"]
ssl = ["scylla/ssl"]

[dev-dependencies]
anyhow = "1.0.33"
futures = "0.3.6"
openssl = "0.10.32"
rustyline = "9"
rustyline-derive = "0.6"
scylla = {path = "../scylla", features = ["ssl", "cloud", "chrono", "time"]}
tokio = {version = "1.1.0", features = ["full"]}
scylla = { path = "../scylla", features = ["chrono", "time"] }
tokio = { version = "1.1.0", features = ["full"] }
tracing = "0.1.25"
tracing-subscriber = { version = "0.3.14", features = ["env-filter"] }
chrono = { version = "0.4", default-features = false }
Expand All @@ -20,6 +25,8 @@ uuid = "1.0"
tower = "0.4"
stats_alloc = "0.1"
clap = { version = "3.2.4", features = ["derive"] }
tokio-rustls = "0.25"
rustls-pemfile = "2"

[[example]]
name = "auth"
Expand All @@ -36,6 +43,12 @@ path = "logging.rs"
[[example]]
name = "tls"
path = "tls.rs"
required-features = ["ssl"]

[[example]]
name = "rustls"
path = "rustls.rs"
required-features = ["rustls"]

[[example]]
name = "cqlsh-rs"
Expand Down Expand Up @@ -108,6 +121,7 @@ path = "query_history.rs"
[[example]]
name = "cloud"
path = "cloud.rs"
required-features = ["cloud"]


[[example]]
Expand Down
163 changes: 163 additions & 0 deletions examples/rustls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
use anyhow::Result;
use scylla::transport::session::{IntoTypedRows, Session};
use scylla::SessionBuilder;
use std::env;
use std::sync::Arc;

use tokio_rustls::rustls::{
self,
client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
pki_types::{CertificateDer, ServerName, UnixTime},
ClientConfig, DigitallySignedStruct, RootCertStore,
};

// How to run scylla instance with TLS:
//
// Edit your scylla.yaml file and add paths to certificates
// ex:
// client_encryption_options:
// enabled: true
// certificate: /etc/scylla/db.crt
// keyfile: /etc/scylla/db.key
//
// If using docker mount your scylla.yaml file and your cert files with option
// --volume $(pwd)/tls.yaml:/etc/scylla/scylla.yaml
//
// If python returns permission error 13 use "Z" flag
// --volume $(pwd)/tls.yaml:/etc/scylla/scylla.yaml:Z
//
// In your Rust program connect to port 9142 if it wasn't changed
// Create new a ClientConfig with your certificate added to it's
// root store.
//
// If your server is using a certifcate that does not have it's IP address
// as a Common Name or Subject Alternate Name you will need to skip
// name verification as part of rustls's configuration.
//
// Build it and add to scylla-rust-driver's SessionBuilder

#[tokio::main]
async fn main() -> Result<()> {
// Create connection
let uri = env::var("SCYLLA_URI").unwrap_or_else(|_| "127.0.0.1:9142".to_string());

println!("Connecting to {} ...", uri);
let mut root_cert_store = RootCertStore::empty();
let rustls_pemfile::Item::X509Certificate(cert) = rustls_pemfile::read_one_from_slice(
&tokio::fs::read("./test/tls/ca.crt")
.await
.expect("Failed to load cert"),
)
.expect("Failed to parse pem")
.expect("No certificates in file")
.0
else {
panic!("not a certificate")
};
root_cert_store
.add(cert)
.expect("Failed to add cert to root cert");

let mut config = ClientConfig::builder()
.with_root_certificates(root_cert_store)
.with_no_client_auth();

config
.dangerous()
.set_certificate_verifier(Arc::new(NoCertificateVerification::default()));

let session: Session = SessionBuilder::new()
.known_node(uri)
.rustls_config(Some(Arc::new(config)))
.build()
.await?;

session.query("CREATE KEYSPACE IF NOT EXISTS ks WITH REPLICATION = {'class' : 'NetworkTopologyStrategy', 'replication_factor' : 1}", &[]).await?;

session
.query(
"CREATE TABLE IF NOT EXISTS ks.t (a int, b int, c text, primary key (a, b))",
&[],
)
.await?;

session
.query("INSERT INTO ks.t (a, b, c) VALUES (?, ?, ?)", (3, 4, "def"))
.await?;

session
.query("INSERT INTO ks.t (a, b, c) VALUES (1, 2, 'abc')", &[])
.await?;

let prepared = session
.prepare("INSERT INTO ks.t (a, b, c) VALUES (?, 7, ?)")
.await?;
session
.execute(&prepared, (42_i32, "I'm prepared!"))
.await?;
session
.execute(&prepared, (43_i32, "I'm prepared 2!"))
.await?;
session
.execute(&prepared, (44_i32, "I'm prepared 3!"))
.await?;

// Rows can be parsed as tuples
if let Some(rows) = session.query("SELECT a, b, c FROM ks.t", &[]).await?.rows {
for row in rows.into_typed::<(i32, i32, String)>() {
let (a, b, c) = row?;
println!("a, b, c: {}, {}, {}", a, b, c);
}
}
println!("Ok.");

Ok(())
}

#[derive(Debug)]
struct NoCertificateVerification {
supported: rustls::crypto::WebPkiSupportedAlgorithms,
}

impl Default for NoCertificateVerification {
fn default() -> Self {
Self {
supported: rustls::crypto::ring::default_provider().signature_verification_algorithms,
}
}
}

impl ServerCertVerifier for NoCertificateVerification {
fn verify_server_cert(
&self,
_end_entity: &CertificateDer<'_>,
_intermediates: &[CertificateDer<'_>],
_server_name: &ServerName<'_>,
_ocsp_response: &[u8],
_now: UnixTime,
) -> Result<ServerCertVerified, rustls::Error> {
return Ok(ServerCertVerified::assertion());
}

fn verify_tls12_signature(
&self,
_message: &[u8],
_cert: &CertificateDer<'_>,
_dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, rustls::Error> {
return Ok(HandshakeSignatureValid::assertion());
}

fn verify_tls13_signature(
&self,
_message: &[u8],
_cert: &CertificateDer<'_>,
_dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, rustls::Error> {
return Ok(HandshakeSignatureValid::assertion());
}

fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
self.supported.supported_schemes()
}
}
4 changes: 2 additions & 2 deletions scylla/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[features]
default = ["rustls"]
default = []
ssl = ["dep:tokio-openssl", "dep:openssl"]
rustls = ["dep:tokio-rustls"]
cloud = ["scylla-cql/serde", "dep:serde_yaml", "dep:serde", "dep:url", "dep:base64"]
cloud = ["ssl", "scylla-cql/serde", "dep:serde_yaml", "dep:serde", "dep:url", "dep:base64"]
secret = ["scylla-cql/secret"]
chrono = ["scylla-cql/chrono"]
time = ["scylla-cql/time"]
Expand Down
3 changes: 0 additions & 3 deletions scylla/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,3 @@ pub use transport::metrics::Metrics;

#[cfg(all(feature = "ssl", feature = "rustls"))]
compile_error!("both rustls and ssl should not be enabled together.");

#[cfg(all(feature = "cloud", not(any(feature = "ssl", feature = "rustls"))))]
compile_error!("cloud feature requires either the rustls or ssl feature.");
1 change: 1 addition & 0 deletions scylla/src/transport/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ mod ssl_config {
sni: Option<ServerName<'static>>,
}

#[cfg(feature = "rustls")]
impl SslConfig {
// Used in case when the user provided their own ClientConfig to be used in all connections.
pub fn new_with_global_config(config: &Arc<ClientConfig>) -> Self {
Expand Down
43 changes: 22 additions & 21 deletions test/tls/ca.crt
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
-----BEGIN CERTIFICATE-----
MIID5TCCAs2gAwIBAgIUIz5sdjquoebzlA6s3gQNRsYV5jUwDQYJKoZIhvcNAQEL
BQAwgYExCzAJBgNVBAYTAlBMMQowCAYDVQQIDAFNMQ8wDQYDVQQHDAZXYXJzYXcx
DzANBgNVBAoMBlNjeWxsYTEVMBMGA1UECwwMdGVzdGluZ19yb290MRUwEwYDVQQD
DAx0ZXN0aW5nX3Jvb3QxFjAUBgkqhkiG9w0BCQEWB2Zvb0BiYXIwHhcNMjEwMzMw
MTI1ODUwWhcNNDEwMzI1MTI1ODUwWjCBgTELMAkGA1UEBhMCUEwxCjAIBgNVBAgM
AU0xDzANBgNVBAcMBldhcnNhdzEPMA0GA1UECgwGU2N5bGxhMRUwEwYDVQQLDAx0
ZXN0aW5nX3Jvb3QxFTATBgNVBAMMDHRlc3Rpbmdfcm9vdDEWMBQGCSqGSIb3DQEJ
ARYHZm9vQGJhcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANlzsXih
nryaSUSf/sXD6oDeU2m0/Fn/HvKL97BwdDKBz3kbs7fyztDCJyvRa24f679cQ1Av
5RqmemTU7m0KaTmJy9cXewjD7P1gDF8K4GumiekBgIsPNyBwVk5TQJBkvPPwjreP
JSj2wlXA7FXc9uUuNVx1ku6ElpK0pWt18uU8+nVRAeZTVZ7ppgmh/aRmMOFNPs6z
Lb9liNJAKPCR7iIALLnpiQOXHMnj+6+o8wMOMD4ehFY8XHYd0TYj5w+OD4tNOjfb
6m21gBaqoMjVVvBq+pmuHDT+oiLyBXpIQ9LNFBXnd/LyqTFiFjoT4yEPgWtpgScQ
CVqi+EJBryRXmUMCAwEAAaNTMFEwHQYDVR0OBBYEFL5PBn2IWZvz5Ce259Z7vym1
tNKDMB8GA1UdIwQYMBaAFL5PBn2IWZvz5Ce259Z7vym1tNKDMA8GA1UdEwEB/wQF
MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAAojwm/3pqAYSBKdq2dqRYvMrVF2a1yE
d5R8AnR/r0vfJEvw9pa+Y8kC/XRezODSiA2HSTTRDI3HxEyixMwLewyS+VcDHYvp
pLZQuCD5zzuq6hWj22o0XklX441TZbkfimzAVhCxlSoufj0l9AG8Ae/xHrOy/Dcd
uzPmnrw9XDb9PkoJHjji3Apb2HjSjO3b17+Pb9TA1YZNiil+jOjwJ8L5UdLw/dYQ
gu5MSxQOerq3wMTY8CUIDMrJMdKenQSGoCEcgLpF27utuUbZGJhFnRe9j1H4der1
RSFMXoVZLI/69iQHmNC3+3keHK1W+CgMliWQ5cF2cly2otAxATriOxM=
MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl
MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp
U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw
NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE
ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp
ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3
DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf
8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN
+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0
X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa
K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA
1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G
A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR
zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0
YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD
bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w
DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3
L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D
eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp
VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY
WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=
-----END CERTIFICATE-----

0 comments on commit 15b3c80

Please sign in to comment.