From d9efb9a1c4714a345cbaa1101a99c726443dd969 Mon Sep 17 00:00:00 2001 From: Sviatoslav Boichuk Date: Tue, 6 Aug 2024 11:06:07 +0300 Subject: [PATCH 1/2] Make TLS connection to Redis/PSQL optional --- README.md | 10 +++- run_cgw.sh | 12 +++++ src/cgw_app_args.rs | 33 ++++++++++++- src/cgw_db_accessor.rs | 96 ++++++++++++++++++++++++------------- src/cgw_remote_discovery.rs | 40 +++++++++++----- 5 files changed, 143 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 4385417..7dd8b53 100644 --- a/README.md +++ b/README.md @@ -72,15 +72,20 @@ CGW_DB_HOST - IP or hostname of remote database server to connect to CGW_DB_PORT - PORT of remote database server to connect to CGW_DB_USER - PSQL DB username (credentials) to use upon connect to DB CGW_DB_PASS - PSQL DB password (credentials) to use upon connect to DB +CGW_DB_TLS - Utilize TLS connection with DB server CGW_REDIS_HOST - IP or hostname of remote redis-db server to connect to CGW_REDIS_PORT - PORT of remote redis-db server to connect to CGW_REDIS_USERNAME - REDIS username (credentials) to use upon connect to CGW_REDIS_PASSWORD - REDIS password (credentials) to use upon connect to +CGW_REDIS_TLS - Utilize TLS connection with REDIS server CGW_LOG_LEVEL - Log level to start CGW application with (debug, info) CGW_METRICS_PORT - PORT of metrics to connect to CGW_CERTS_PATH - Path to certificates located on host machine CGW_ALLOW_CERT_MISMATCH - Allow client certificate CN and device MAC address mismatch (used for OWLS) -CGW_NB_INFRA_CERTS_DIR - Path to NB infrastructure (Redis, PostgreSQL)certificates located on host machine +CGW_NB_INFRA_CERTS_DIR - Path to NB infrastructure (Redis, PostgreSQL) certificates located on host machine +CGW_NB_INFRA_TLS - Utilize TLS connection with NB infrastructure (Redis, PostgreSQL) + If set enabled - the CGW_DB_TLS and CGW_REDIS_TLS values will be ignored and + the TLS connection will be used for Redis and PostgreSQL connection ``` Example of properly configured list of env variables to start CGW: @@ -90,6 +95,7 @@ declare -x CGW_DB_HOST="localhost" # PSQL server is locate declare -x CGW_DB_PORT="5432" declare -x CGW_DB_USERNAME="cgw" # PSQL login credentials (username) default 'cgw' will be used declare -x CGW_DB_PASS="123" # PSQL login credentials (password) default '123' will be used +declare -x CGW_DB_TLS="no" declare -x CGW_GRPC_LISTENING_IP="127.0.0.1" # Local default subnet is 127.0.0.1/24 declare -x CGW_GRPC_LISTENING_PORT="50051" declare -x CGW_GRPC_PUBLIC_HOST="localhost" @@ -102,6 +108,7 @@ declare -x CGW_REDIS_HOST="localhost" # Redis server can be f declare -x CGW_REDIS_PORT="6379" declare -x CGW_REDIS_USERNAME="cgw" # REDIS login credentials (username) - optional declare -x CGW_REDIS_PASSWORD="123" # REDIS login credentials (password) - optional +declare -x CGW_REDIS_TLS="no" declare -x CGW_METRICS_PORT="8080" declare -x CGW_WSS_IP="0.0.0.0" # Accept WSS connections at all interfaces / subnets declare -x CGW_WSS_PORT="15002" @@ -111,6 +118,7 @@ declare -x CGW_WSS_KEY="key.pem" declare -x CGW_CERTS_PATH="/etc/ssl/certs" # Path to certificates located on host machine declare -x CGW_ALLOW_CERT_MISMATCH="no" # Allow client certificate CN and device MAC address mismatch declare -x CGW_NB_INFRA_CERTS_PATH="/etc/nb_infra_certs" +declare -x CGW_NB_INFRA_TLS="no" ``` # Certificates The CGW uses two different sets of certificate configuration: diff --git a/run_cgw.sh b/run_cgw.sh index 58adff8..c75aee3 100755 --- a/run_cgw.sh +++ b/run_cgw.sh @@ -29,14 +29,17 @@ DEFAULT_DB_PORT=5432 DEFAULT_DB_NAME="cgw" DEFAULT_DB_USER="cgw" DEFAULT_DB_PASW="123" +DEFAULT_DB_TLS="no" DEFAULT_REDIS_HOST="localhost" DEFAULT_REDIS_PORT=6379 +DEFAULT_REDIS_TLS="no" DEFAULT_METRICS_PORT=8080 CONTAINTER_CERTS_VOLUME="/etc/cgw/certs" CONTAINTER_NB_INFRA_CERTS_VOLUME="/etc/cgw/nb_infra/certs" +DEFAULT_NB_INFRA_TLS="no" DEFAULT_ALLOW_CERT_MISMATCH="no" @@ -61,12 +64,15 @@ export CGW_DB_PORT="${CGW_DB_PORT:-$DEFAULT_DB_PORT}" export CGW_DB_NAME="${CGW_DB_NAME:-$DEFAULT_DB_NAME}" export CGW_DB_USERNAME="${CGW_DB_USER:-$DEFAULT_DB_USER}" export CGW_DB_PASSWORD="${CGW_DB_PASS:-$DEFAULT_DB_PASW}" +export CGW_DB_TLS="${CGW_DB_TLS:-$DEFAULT_DB_TLS}" export CGW_REDIS_HOST="${CGW_REDIS_HOST:-$DEFAULT_REDIS_HOST}" export CGW_REDIS_PORT="${CGW_REDIS_PORT:-$DEFAULT_REDIS_PORT}" +export CGW_REDIS_TLS="${CGW_REDIS_TLS:-$DEFAULT_REDIS_TLS}" export CGW_METRICS_PORT="${CGW_METRICS_PORT:-$DEFAULT_METRICS_PORT}" export CGW_CERTS_PATH="${CGW_CERTS_PATH:-$DEFAULT_CERTS_PATH}" export CGW_ALLOW_CERT_MISMATCH="${CGW_ALLOW_CERT_MISMATCH:-$DEFAULT_ALLOW_CERT_MISMATCH}" export CGW_NB_INFRA_CERTS_PATH="${CGW_NB_INFRA_CERTS_PATH:-$DEFAULT_CERTS_PATH}" +export CGW_NB_INFRA_TLS="${CGW_NB_INFRA_TLS:-$DEFAULT_NB_INFRA_TLS}" if [ -z "${!CGW_REDIS_USERNAME}" ]; then export CGW_REDIS_USERNAME="${CGW_REDIS_USERNAME}" @@ -90,11 +96,14 @@ echo "CGW KAFKA HOST/PORT : $CGW_KAFKA_HOST:$CGW_KAFKA_PORT" echo "CGW KAFKA TOPIC : $CGW_KAFKA_CONSUME_TOPIC:$CGW_KAFKA_PRODUCE_TOPIC" echo "CGW DB NAME : $CGW_DB_NAME" echo "CGW DB HOST/PORT : $CGW_DB_HOST:$CGW_DB_PORT" +echo "CGW DB TLS : $CGW_DB_TLS" echo "CGW REDIS HOST/PORT : $CGW_REDIS_HOST:$CGW_REDIS_PORT" +echo "CGW REDIS TLS : $CGW_REDIS_TLS" echo "CGW METRICS PORT : $CGW_METRICS_PORT" echo "CGW CERTS PATH : $CGW_CERTS_PATH" echo "CGW ALLOW CERT MISMATCH : $CGW_ALLOW_CERT_MISMATCH" echo "CGW NB INFRA CERTS PATH : $CGW_NB_INFRA_CERTS_PATH" +echo "CGW NB INFRA TLS : $CGW_NB_INFRA_TLS" docker run \ --cap-add=SYS_PTRACE --security-opt seccomp=unconfined \ @@ -121,11 +130,14 @@ docker run \ -e CGW_DB_PORT \ -e CGW_DB_USERNAME \ -e CGW_DB_PASSWORD \ + -e CGW_DB_TLS \ -e CGW_REDIS_HOST \ -e CGW_REDIS_PORT \ -e CGW_REDIS_USERNAME \ -e CGW_REDIS_PASSWORD \ + -e CGW_REDIS_TLS \ -e CGW_FEATURE_TOPOMAP_ENABLE \ -e CGW_METRICS_PORT \ -e CGW_ALLOW_CERT_MISMATCH \ + -e CGW_NB_INFRA_TLS \ -d -t --network=host --name $2 $1 ucentral-cgw diff --git a/src/cgw_app_args.rs b/src/cgw_app_args.rs index 5e6ce9f..3875bf1 100644 --- a/src/cgw_app_args.rs +++ b/src/cgw_app_args.rs @@ -26,11 +26,14 @@ const CGW_DEFAULT_DB_PORT: u16 = 6379; const CGW_DEFAULT_DB_NAME: &str = "cgw"; const CGW_DEFAULT_DB_USERNAME: &str = "cgw"; const CGW_DEFAULT_DB_PASSWORD: &str = "123"; +const CGW_DEFAULT_DB_TLS: &str = "no"; const CGW_DEFAULT_REDIS_HOST: &str = "localhost"; const CGW_DEFAULT_REDIS_PORT: u16 = 6379; +const CGW_DEFAULT_REDIS_TLS: &str = "no"; const CGW_DEFAULT_ALLOW_CERT_MISMATCH: &str = "no"; const CGW_DEFAULT_METRICS_PORT: u16 = 8080; const CGW_DEFAULT_TOPOMAP_STATE: bool = false; +const CGW_DEFAULT_NB_INFRA_TLS: &str = "no"; pub struct CGWWSSArgs { /// Number of thread in a threadpool dedicated for handling secure websocket connections @@ -252,6 +255,8 @@ pub struct CGWDBArgs { pub db_username: String, /// DB user password use with connection to in DB (PSQL) pub db_password: String, + /// Utilize TLS connection with DB server + pub db_tls: bool, } impl CGWDBArgs { @@ -289,12 +294,16 @@ impl CGWDBArgs { let db_password: String = env::var("CGW_DB_PASSWORD").unwrap_or(CGW_DEFAULT_DB_PASSWORD.to_string()); + let db_tls_var: String = env::var("CGW_DB_TLS").unwrap_or(CGW_DEFAULT_DB_TLS.to_string()); + let db_tls = db_tls_var == "yes"; + Ok(CGWDBArgs { db_host, db_port, db_name, db_username, db_password, + db_tls, }) } } @@ -308,6 +317,8 @@ pub struct CGWRedisArgs { pub redis_username: Option, /// REDIS password pub redis_password: Option, + /// Utilize TLS connection with DB server + pub redis_tls: bool, } impl CGWRedisArgs { @@ -361,11 +372,16 @@ impl CGWRedisArgs { Err(_) => None, }; + let redis_tls_var: String = + env::var("CGW_REDIS_TLS").unwrap_or(CGW_DEFAULT_REDIS_TLS.to_string()); + let redis_tls = redis_tls_var == "yes"; + Ok(CGWRedisArgs { redis_host, redis_port, redis_username, redis_password, + redis_tls, }) } } @@ -404,6 +420,9 @@ pub struct AppArgs { /// Topomap featue status (enabled/disabled) pub feature_topomap_enabled: bool, + /// Utilize TLS connection with NB infrastructure (Redis, PostgreSQL) + pub nb_infra_tls: bool, + pub wss_args: CGWWSSArgs, pub grpc_args: CGWGRPCArgs, @@ -450,17 +469,27 @@ impl AppArgs { Err(_) => CGW_DEFAULT_TOPOMAP_STATE, }; + let nb_infra_tls_var: String = + env::var("CGW_NB_INFRA_TLS").unwrap_or(CGW_DEFAULT_NB_INFRA_TLS.to_string()); + let nb_infra_tls = nb_infra_tls_var == "yes"; + let wss_args = CGWWSSArgs::parse()?; let grpc_args = CGWGRPCArgs::parse()?; let kafka_args = CGWKafkaArgs::parse()?; - let db_args = CGWDBArgs::parse()?; - let redis_args = CGWRedisArgs::parse()?; + let mut db_args = CGWDBArgs::parse()?; + let mut redis_args = CGWRedisArgs::parse()?; let metrics_args = CGWMetricsArgs::parse()?; + if nb_infra_tls { + redis_args.redis_tls = nb_infra_tls; + db_args.db_tls = nb_infra_tls; + } + Ok(AppArgs { log_level, cgw_id, feature_topomap_enabled, + nb_infra_tls, wss_args, grpc_args, kafka_args, diff --git a/src/cgw_db_accessor.rs b/src/cgw_db_accessor.rs index 6e4f3a9..91ced45 100644 --- a/src/cgw_db_accessor.rs +++ b/src/cgw_db_accessor.rs @@ -8,6 +8,7 @@ use crate::{ use eui48::MacAddress; +use tokio_postgres::NoTls; use tokio_postgres::{row::Row, Client}; #[derive(Clone)] @@ -60,46 +61,77 @@ impl CGWDBAccessor { user = db_args.db_username, db = db_args.db_name, pass = db_args.db_password, - sslmode = "require", + sslmode = match db_args.db_tls { + true => "require", + false => "disable", + } ); debug!( "Trying to connect to remote db ({}:{})...\nConn args {}", db_args.db_host, db_args.db_port, conn_str ); - let tls = match cgw_tls_create_db_connect().await { - Ok(tls_connect) => tls_connect, - Err(e) => { - error!( - "Failed to build TLS connection with remote DB, reason: {}", - e.to_string() - ); - return Err(Error::DbAccessor( - "Failed to build TLS connection with remote DB", - )); - } - }; + let client: Client; + if db_args.db_tls { + let tls = match cgw_tls_create_db_connect().await { + Ok(tls_connect) => tls_connect, + Err(e) => { + error!( + "Failed to build TLS connection with remote DB, reason: {}", + e.to_string() + ); + return Err(Error::DbAccessor( + "Failed to build TLS connection with remote DB", + )); + } + }; - let (client, connection) = match tokio_postgres::connect(&conn_str, tls).await { - Ok((cl, conn)) => (cl, conn), - Err(e) => { - error!("Failed to establish connection with DB, reason: {:?}", e); - return Err(Error::DbAccessor("Failed to establish connection with DB")); - } - }; + let (db_client, connection) = match tokio_postgres::connect(&conn_str, tls).await { + Ok((cl, conn)) => (cl, conn), + Err(e) => { + error!("Failed to establish connection with DB, reason: {:?}", e); + return Err(Error::DbAccessor("Failed to establish connection with DB")); + } + }; - tokio::spawn(async move { - if let Err(e) = connection.await { - let err_msg = format!("Connection to DB broken: {}", e); - error!("{}", err_msg); - CGWMetrics::get_ref() - .change_component_health_status( - CGWMetricsHealthComponent::DBConnection, - CGWMetricsHealthComponentStatus::NotReady(err_msg), - ) - .await; - } - }); + tokio::spawn(async move { + if let Err(e) = connection.await { + let err_msg = format!("Connection to DB broken: {}", e); + error!("{}", err_msg); + CGWMetrics::get_ref() + .change_component_health_status( + CGWMetricsHealthComponent::DBConnection, + CGWMetricsHealthComponentStatus::NotReady(err_msg), + ) + .await; + } + }); + + client = db_client; + } else { + let (db_client, connection) = match tokio_postgres::connect(&conn_str, NoTls).await { + Ok((cl, conn)) => (cl, conn), + Err(e) => { + error!("Failed to establish connection with DB, reason: {:?}", e); + return Err(Error::DbAccessor("Failed to establish connection with DB")); + } + }; + + tokio::spawn(async move { + if let Err(e) = connection.await { + let err_msg = format!("Connection to DB broken: {}", e); + error!("{}", err_msg); + CGWMetrics::get_ref() + .change_component_health_status( + CGWMetricsHealthComponent::DBConnection, + CGWMetricsHealthComponentStatus::NotReady(err_msg), + ) + .await; + } + }); + + client = db_client; + } tokio::spawn(async move { CGWMetrics::get_ref() diff --git a/src/cgw_remote_discovery.rs b/src/cgw_remote_discovery.rs index a66b5dc..854e1cf 100644 --- a/src/cgw_remote_discovery.rs +++ b/src/cgw_remote_discovery.rs @@ -151,12 +151,18 @@ pub struct CGWRemoteDiscovery { async fn cgw_create_redis_client(redis_args: &CGWRedisArgs) -> Result { let redis_client_info = ConnectionInfo { - addr: redis::ConnectionAddr::TcpTls { - host: redis_args.redis_host.clone(), - port: redis_args.redis_port, - insecure: true, - tls_params: None, + addr: match redis_args.redis_tls { + true => redis::ConnectionAddr::TcpTls { + host: redis_args.redis_host.clone(), + port: redis_args.redis_port, + insecure: true, + tls_params: None, + }, + false => { + redis::ConnectionAddr::Tcp(redis_args.redis_host.clone(), redis_args.redis_port) + } }, + redis: RedisConnectionInfo { username: redis_args.redis_username.clone(), password: redis_args.redis_password.clone(), @@ -164,16 +170,24 @@ async fn cgw_create_redis_client(redis_args: &CGWRedisArgs) -> Result { }, }; - let root_cert = cgw_read_root_certs_dir().await.ok(); + match redis_args.redis_tls { + true => { + let root_cert = cgw_read_root_certs_dir().await.ok(); - let tls_certs: TlsCertificates = TlsCertificates { - client_tls: None, - root_cert, - }; + let tls_certs: TlsCertificates = TlsCertificates { + client_tls: None, + root_cert, + }; - match redis::Client::build_with_tls(redis_client_info, tls_certs) { - Ok(client) => Ok(client), - Err(e) => Err(Error::Redis(format!("Failed to start Redis Client: {}", e))), + match redis::Client::build_with_tls(redis_client_info, tls_certs) { + Ok(client) => Ok(client), + Err(e) => Err(Error::Redis(format!("Failed to start Redis Client: {}", e))), + } + } + false => match redis::Client::open(redis_client_info) { + Ok(client) => Ok(client), + Err(e) => Err(Error::Redis(format!("Failed to start Redis Client: {}", e))), + }, } } From a02c3a87e8fb1506c2081a40980f048bfac6bfed Mon Sep 17 00:00:00 2001 From: Sviatoslav Boichuk Date: Tue, 6 Aug 2024 11:06:43 +0300 Subject: [PATCH 2/2] Do not use TLS connection to NB services --- utils/docker/docker-compose.yml | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/utils/docker/docker-compose.yml b/utils/docker/docker-compose.yml index 654b513..38de6ae 100644 --- a/utils/docker/docker-compose.yml +++ b/utils/docker/docker-compose.yml @@ -33,31 +33,21 @@ services: ports: - "5432:5432" user: postgres - command: > - bash -c " - chown 999:999 /var/lib/postgresql/certs/server.key && - chmod 600 /var/lib/postgresql/certs/server.key && - postgres -c max_connections=400 -c shared_buffers=20MB -c ssl=on -c ssl_cert_file=/var/lib/postgresql/certs/server.crt -c ssl_key_file=/var/lib/postgresql/certs/server.key - " + command: + - "postgres" + - "-c" + - "max_connections=400" + - "-c" + - "shared_buffers=20MB" env_file: - postgresql.env restart: always volumes: - ./postgresql/init-db.sh:/docker-entrypoint-initdb.d/init-db.sh - - ./certs/:/var/lib/postgresql/certs/ redis: image: 'bitnami/redis:latest' ports: - "6379:6379" - volumes: - - ./certs:/usr/local/etc/certs environment: - ALLOW_EMPTY_PASSWORD=yes - - REDIS_PORT_NUMBER=0 - - REDIS_TLS_ENABLED=yes - - REDIS_TLS_PORT_NUMBER=6379 - - REDIS_TLS_CERT_FILE=/usr/local/etc/certs/server.crt - - REDIS_TLS_KEY_FILE=/usr/local/etc/certs/server_redis.key - - REDIS_TLS_CA_DIR=/usr/local/etc/certs - - REDIS_TLS_AUTH_CLIENTS=no