diff --git a/shotover-proxy/example-configs/cassandra-cluster-tls/docker-compose.yml b/shotover-proxy/example-configs/cassandra-cluster-tls/docker-compose.yml new file mode 100644 index 000000000..4f8050f3e --- /dev/null +++ b/shotover-proxy/example-configs/cassandra-cluster-tls/docker-compose.yml @@ -0,0 +1,61 @@ +version: "3.3" +networks: + cluster_subnet: + name: cluster_subnet + driver: bridge + ipam: + driver: default + config: + - subnet: 172.16.1.0/24 + gateway: 172.16.1.1 + +services: + cassandra-one: + image: bitnami/cassandra:3.11 + networks: + cluster_subnet: + ipv4_address: 172.16.1.2 + healthcheck: + &healthcheck + test: [ "CMD", "cqlsh", "-e", "describe keyspaces" ] + interval: 5s + timeout: 5s + retries: 60 + environment: + &environment + CASSANDRA_SEEDS: "cassandra-one,cassandra-two" + CASSANDRA_CLUSTER_NAME: TestCluster + CASSANDRA_DC: dc1 + CASSANDRA_RACK: rack1 + CASSANDRA_ENDPOINT_SNITCH: GossipingPropertyFileSnitch + CASSANDRA_NUM_TOKENS: 128 + MAX_HEAP_SIZE: "400M" + MIN_HEAP_SIZE: "400M" + HEAP_NEWSIZE: "48M" + CASSANDRA_ENABLE_SCRIPTED_USER_DEFINED_FUNCTIONS: "true" + CASSANDRA_ENABLE_USER_DEFINED_FUNCTIONS: "true" + CASSANDRA_KEYSTORE_PASSWORD: "password" + CASSANDRA_TRUSTSTORE_PASSWORD: "password" + CASSANDRA_CLIENT_ENCRYPTION: "true" + volumes: + &volumes + - ../cassandra-tls/certs/keystore.p12:/bitnami/cassandra/secrets/keystore + - ../cassandra-tls/certs/truststore.p12:/bitnami/cassandra/secrets/truststore + + cassandra-two: + image: bitnami/cassandra:3.11 + networks: + cluster_subnet: + ipv4_address: 172.16.1.3 + healthcheck: *healthcheck + environment: *environment + volumes: *volumes + + cassandra-three: + image: bitnami/cassandra:3.11 + networks: + cluster_subnet: + ipv4_address: 172.16.1.4 + healthcheck: *healthcheck + environment: *environment + volumes: *volumes diff --git a/shotover-proxy/example-configs/cassandra-cluster-tls/topology.yaml b/shotover-proxy/example-configs/cassandra-cluster-tls/topology.yaml new file mode 100644 index 000000000..99b81e82f --- /dev/null +++ b/shotover-proxy/example-configs/cassandra-cluster-tls/topology.yaml @@ -0,0 +1,20 @@ +--- +sources: + cassandra_prod: + Cassandra: + listen_addr: "127.0.0.1:9042" + tls: + certificate_authority_path: "example-configs/cassandra-tls/certs/localhost_CA.crt" + certificate_path: "example-configs/cassandra-tls/certs/localhost.crt" + private_key_path: "example-configs/cassandra-tls/certs/localhost.key" +chain_config: + main_chain: + - CassandraSinkCluster: + first_contact_points: ["172.16.1.2:9042", "172.16.1.3:9042"] + data_center: "dc1" + tls: + certificate_authority_path: "example-configs/cassandra-tls/certs/localhost_CA.crt" + certificate_path: "example-configs/cassandra-tls/certs/localhost.crt" + private_key_path: "example-configs/cassandra-tls/certs/localhost.key" +source_to_chain_mapping: + cassandra_prod: main_chain diff --git a/shotover-proxy/tests/cassandra_int_tests/mod.rs b/shotover-proxy/tests/cassandra_int_tests/mod.rs index 894a7b464..e330f5643 100644 --- a/shotover-proxy/tests/cassandra_int_tests/mod.rs +++ b/shotover-proxy/tests/cassandra_int_tests/mod.rs @@ -47,6 +47,40 @@ fn test_passthrough() { batch_statements::test(&connection); } +#[test] +#[serial] +fn test_source_tls_and_single_tls() { + test_helpers::cert::generate_cassandra_test_certs(); + let _compose = DockerCompose::new("example-configs/cassandra-tls/docker-compose.yml"); + + let shotover_manager = + ShotoverManager::from_topology_file("example-configs/cassandra-tls/topology.yaml"); + + let ca_cert = "example-configs/cassandra-tls/certs/localhost_CA.crt"; + + { + // Run a quick test straight to Cassandra to check our assumptions that Shotover and Cassandra TLS are behaving exactly the same + let direct_connection = + shotover_manager.cassandra_connection_tls("127.0.0.1", 9042, ca_cert); + assert_query_result( + &direct_connection, + "SELECT bootstrapped FROM system.local", + &[&[ResultValue::Varchar("COMPLETED".into())]], + ); + } + + let connection = shotover_manager.cassandra_connection_tls("127.0.0.1", 9043, ca_cert); + + keyspace::test(&connection); + table::test(&connection); + udt::test(&connection); + native_types::test(&connection); + collections::test(&connection); + functions::test(&connection); + prepared_statements::test(&connection); + batch_statements::test(&connection); +} + #[test] #[serial] #[cfg(feature = "alpha-transforms")] @@ -70,19 +104,20 @@ fn test_cluster() { #[test] #[serial] -fn test_source_tls_and_single_tls() { +#[cfg(feature = "alpha-transforms")] +fn test_source_tls_and_cluster_tls() { test_helpers::cert::generate_cassandra_test_certs(); - let _compose = DockerCompose::new("example-configs/cassandra-tls/docker-compose.yml"); + let _compose = DockerCompose::new("example-configs/cassandra-cluster-tls/docker-compose.yml"); let shotover_manager = - ShotoverManager::from_topology_file("example-configs/cassandra-tls/topology.yaml"); + ShotoverManager::from_topology_file("example-configs/cassandra-cluster-tls/topology.yaml"); let ca_cert = "example-configs/cassandra-tls/certs/localhost_CA.crt"; { // Run a quick test straight to Cassandra to check our assumptions that Shotover and Cassandra TLS are behaving exactly the same let direct_connection = - shotover_manager.cassandra_connection_tls("127.0.0.1", 9042, ca_cert); + shotover_manager.cassandra_connection_tls("172.16.1.2", 9042, ca_cert); assert_query_result( &direct_connection, "SELECT bootstrapped FROM system.local", @@ -90,7 +125,7 @@ fn test_source_tls_and_single_tls() { ); } - let connection = shotover_manager.cassandra_connection_tls("127.0.0.1", 9043, ca_cert); + let connection = shotover_manager.cassandra_connection_tls("127.0.0.1", 9042, ca_cert); keyspace::test(&connection); table::test(&connection); diff --git a/test-helpers/src/docker_compose.rs b/test-helpers/src/docker_compose.rs index aa1f5355b..3c0fa7299 100644 --- a/test-helpers/src/docker_compose.rs +++ b/test-helpers/src/docker_compose.rs @@ -125,7 +125,8 @@ impl DockerCompose { self.wait_for_log("Startup complete", 2, 110) } "example-configs-docker/cassandra-peers-rewrite/docker-compose.yml" - | "example-configs/cassandra-cluster/docker-compose.yml" => { + | "example-configs/cassandra-cluster/docker-compose.yml" + | "example-configs/cassandra-cluster-tls/docker-compose.yml" => { self.wait_for_log("Startup complete", 3, 180) } path => unimplemented!(