diff --git a/Cargo.lock b/Cargo.lock index 6d9476a..d7de5a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -232,6 +232,26 @@ dependencies = [ "tracing", ] +[[package]] +name = "axum-server" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "495c05f60d6df0093e8fb6e74aa5846a0ad06abaf96d76166283720bf740f8ab" +dependencies = [ + "arc-swap", + "bytes", + "fs-err", + "http", + "http-body", + "hyper", + "hyper-util", + "openssl", + "pin-project-lite", + "tokio", + "tokio-openssl", + "tower-service", +] + [[package]] name = "backtrace" version = "0.3.74" @@ -707,6 +727,16 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs-err" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d7be93788013f265201256d58f04936a8079ad5dc898743aa20525f503b683" +dependencies = [ + "autocfg", + "tokio", +] + [[package]] name = "fsevent-sys" version = "4.1.0" @@ -812,6 +842,7 @@ dependencies = [ "arc-swap", "async-trait", "axum", + "axum-server", "base16ct", "base64", "dashmap", diff --git a/Cargo.toml b/Cargo.toml index 644f10f..6184a97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ log = "0.4.27" futures = "0.3.31" notify = "8.0.0" axum = { version = "0.8.4" } +axum-server = { version = "0.7.2", features = ["tls-openssl"] } reqwest = { version = "0.12.15", features = ["json", "native-tls-alpn"] } #reqwest = { version = "0.12.15", features = ["json", "rustls-tls"] } #reqwest = { version = "0.12.15", default-features = false, features = ["rustls-tls", "json"] } diff --git a/etc/main.yaml b/etc/main.yaml index 9599a6d..5ea48e3 100644 --- a/etc/main.yaml +++ b/etc/main.yaml @@ -8,6 +8,9 @@ pid_file: /tmp/gazan.pid # Path to PID file error_log: /tmp/gazan_err.log # Path to error log upgrade_sock: /tmp/gazan.sock # Path to socket file config_address: 0.0.0.0:3000 # HTTP API address for pushing upstreams.yaml from remote location +config_tls_address: 0.0.0.0:3001 # HTTP TLS API address for pushing upstreams.yaml from remote location +config_tls_certificate: etc/server.crt # Mandatory if config_tls_address is set +config_tls_key_file: etc/key.pem # Mandatory if config_tls_address is set proxy_address_http: 0.0.0.0:6193 # Proxy HTTP bind address proxy_address_tls: 0.0.0.0:6194 # Optional, Proxy TLS bind address tls_certificate: etc/server.crt # Mandatory if proxy_address_tls is set diff --git a/src/utils/discovery.rs b/src/utils/discovery.rs index 1696869..2a8e001 100644 --- a/src/utils/discovery.rs +++ b/src/utils/discovery.rs @@ -11,6 +11,9 @@ pub struct FromFileProvider { pub struct APIUpstreamProvider { pub address: String, pub masterkey: String, + pub tls_address: Option, + pub tls_certificate: Option, + pub tls_key_file: Option, } pub struct ConsulProvider { @@ -25,7 +28,7 @@ pub trait Discovery { #[async_trait] impl Discovery for APIUpstreamProvider { async fn start(&self, toreturn: Sender) { - webserver::run_server(self.address.clone(), self.masterkey.clone(), toreturn).await; + webserver::run_server(self, toreturn).await; } } diff --git a/src/utils/parceyaml.rs b/src/utils/parceyaml.rs index 4a4754c..a97c6c7 100644 --- a/src/utils/parceyaml.rs +++ b/src/utils/parceyaml.rs @@ -150,5 +150,15 @@ pub fn parce_main_config(path: &str) -> AppConfig { } } }; + // match cfo.config_tls_address.clone() { + // Some(tls_cert) => { + // if let Some((ip, port_str)) = tls_cert.split_once(':') { + // if let Ok(port) = port_str.parse::() { + // cfo.local_tls_server = Option::from((ip.to_string(), port)); + // } + // } + // } + // None => {} + // }; cfo } diff --git a/src/utils/structs.rs b/src/utils/structs.rs index 6a50982..c46bf6e 100644 --- a/src/utils/structs.rs +++ b/src/utils/structs.rs @@ -65,9 +65,12 @@ pub struct AppConfig { pub hc_method: String, pub upstreams_conf: String, pub log_level: String, + pub master_key: String, pub config_address: String, pub proxy_address_http: String, - pub master_key: String, + pub config_tls_address: Option, + pub config_tls_certificate: Option, + pub config_tls_key_file: Option, pub proxy_address_tls: Option, pub proxy_port_tls: Option, pub tls_certificate: Option, diff --git a/src/web/bgservice.rs b/src/web/bgservice.rs index 96565aa..933b0d2 100644 --- a/src/web/bgservice.rs +++ b/src/web/bgservice.rs @@ -34,6 +34,9 @@ impl BackgroundService for LB { let api_load = APIUpstreamProvider { address: self.config.config_address.clone(), masterkey: self.config.master_key.clone(), + tls_address: self.config.config_tls_address.clone(), + tls_certificate: self.config.config_tls_certificate.clone(), + tls_key_file: self.config.config_tls_key_file.clone(), }; let tx_api = tx.clone(); let _ = tokio::spawn(async move { api_load.start(tx_api).await }); diff --git a/src/web/webserver.rs b/src/web/webserver.rs index 291fb1e..8f8c794 100644 --- a/src/web/webserver.rs +++ b/src/web/webserver.rs @@ -1,3 +1,4 @@ +use crate::utils::discovery::APIUpstreamProvider; use crate::utils::structs::Configuration; use axum::body::Body; use axum::extract::{Query, State}; @@ -5,6 +6,7 @@ use axum::http::{Response, StatusCode}; use axum::response::IntoResponse; use axum::routing::{delete, get, head, post, put}; use axum::{Json, Router}; +use axum_server::tls_openssl::OpenSSLConfig; use futures::channel::mpsc::Sender; use futures::SinkExt; use jsonwebtoken::{encode, EncodingKey, Header}; @@ -12,6 +14,7 @@ use log::{error, info, warn}; use prometheus::{gather, Encoder, TextEncoder}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use std::net::SocketAddr; use std::time::{Duration, SystemTime, UNIX_EPOCH}; use tokio::net::TcpListener; @@ -34,9 +37,9 @@ struct AppState { } #[allow(unused_mut)] -pub async fn run_server(bindaddress: String, master_key: String, mut to_return: Sender) { +pub async fn run_server(config: &APIUpstreamProvider, mut to_return: Sender) { let app_state = AppState { - master_key: master_key.clone(), + master_key: config.masterkey.clone(), config_sender: to_return.clone(), }; let app = Router::new() @@ -49,8 +52,21 @@ pub async fn run_server(bindaddress: String, master_key: String, mut to_return: .route("/conf", post(conf)) .route("/metrics", get(metrics)) .with_state(app_state); - let listener = TcpListener::bind(bindaddress.clone()).await.unwrap(); - info!("Starting the API server on: {}", bindaddress); + + if let Some(value) = &config.tls_address { + let cf = OpenSSLConfig::from_pem_file(config.tls_certificate.clone().unwrap(), config.tls_key_file.clone().unwrap()).unwrap(); + let addr: SocketAddr = value.parse().expect("Unable to parse socket address"); + let tls_app = app.clone(); + tokio::spawn(async move { + if let Err(e) = axum_server::bind_openssl(addr, cf).serve(tls_app.into_make_service()).await { + eprintln!("TLS server failed: {}", e); + } + }); + info!("Starting the TLS API server on: {}", value); + } + + let listener = TcpListener::bind(config.address.clone()).await.unwrap(); + info!("Starting the API server on: {}", config.address); axum::serve(listener, app).await.unwrap(); }