mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-01 11:06:50 +08:00
feat(tls): add support for https in actix web (#5089)
Co-authored-by: noagbmn <>
This commit is contained in:
64
Cargo.lock
generated
64
Cargo.lock
generated
@ -43,6 +43,7 @@ dependencies = [
|
||||
"actix-codec",
|
||||
"actix-rt",
|
||||
"actix-service",
|
||||
"actix-tls",
|
||||
"actix-utils",
|
||||
"ahash 0.8.11",
|
||||
"base64 0.21.7",
|
||||
@ -187,8 +188,10 @@ dependencies = [
|
||||
"http 1.1.0",
|
||||
"impl-more",
|
||||
"pin-project-lite",
|
||||
"rustls-pki-types",
|
||||
"tokio 1.37.0",
|
||||
"tokio-rustls 0.23.4",
|
||||
"tokio-rustls 0.25.0",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
"webpki-roots 0.22.6",
|
||||
@ -217,6 +220,7 @@ dependencies = [
|
||||
"actix-rt",
|
||||
"actix-server",
|
||||
"actix-service",
|
||||
"actix-tls",
|
||||
"actix-utils",
|
||||
"actix-web-codegen",
|
||||
"ahash 0.8.11",
|
||||
@ -5800,7 +5804,7 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"rustls 0.21.10",
|
||||
"rustls-pemfile",
|
||||
"rustls-pemfile 1.0.4",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
@ -5990,6 +5994,8 @@ dependencies = [
|
||||
"roxmltree",
|
||||
"rust_decimal",
|
||||
"rustc-hash",
|
||||
"rustls 0.22.4",
|
||||
"rustls-pemfile 2.1.2",
|
||||
"scheduler",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@ -6219,10 +6225,24 @@ checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba"
|
||||
dependencies = [
|
||||
"log",
|
||||
"ring 0.17.8",
|
||||
"rustls-webpki",
|
||||
"rustls-webpki 0.101.7",
|
||||
"sct",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.22.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432"
|
||||
dependencies = [
|
||||
"log",
|
||||
"ring 0.17.8",
|
||||
"rustls-pki-types",
|
||||
"rustls-webpki 0.102.3",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-native-certs"
|
||||
version = "0.6.3"
|
||||
@ -6230,7 +6250,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00"
|
||||
dependencies = [
|
||||
"openssl-probe",
|
||||
"rustls-pemfile",
|
||||
"rustls-pemfile 1.0.4",
|
||||
"schannel",
|
||||
"security-framework",
|
||||
]
|
||||
@ -6244,6 +6264,22 @@ dependencies = [
|
||||
"base64 0.21.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "2.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d"
|
||||
dependencies = [
|
||||
"base64 0.22.0",
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pki-types"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "beb461507cee2c2ff151784c52762cf4d9ff6a61f3e80968600ed24fa837fa54"
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.101.7"
|
||||
@ -6254,6 +6290,17 @@ dependencies = [
|
||||
"untrusted 0.9.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.102.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3bce581c0dd41bce533ce695a1437fa16a7ab5ac3ccfa99fe1a620a7885eabf"
|
||||
dependencies = [
|
||||
"ring 0.17.8",
|
||||
"rustls-pki-types",
|
||||
"untrusted 0.9.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.14"
|
||||
@ -7625,6 +7672,17 @@ dependencies = [
|
||||
"tokio 1.37.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f"
|
||||
dependencies = [
|
||||
"rustls 0.22.4",
|
||||
"rustls-pki-types",
|
||||
"tokio 1.37.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-stream"
|
||||
version = "0.1.15"
|
||||
|
||||
@ -11,6 +11,15 @@ host = "127.0.0.1"
|
||||
shutdown_timeout = 30
|
||||
# HTTP Request body limit. Defaults to 32kB
|
||||
request_body_limit = 32_768
|
||||
|
||||
# HTTPS Server Configuration
|
||||
# Self-signed Private Key and Certificate can be generated with mkcert for local development
|
||||
[server.tls]
|
||||
port = 8081
|
||||
host = "127.0.0.1"
|
||||
private_key = "/path/to/private_key.pem"
|
||||
certificate = "/path/to/certificate.pem"
|
||||
|
||||
# Proxy server configuration for connecting to payment gateways.
|
||||
# Don't define the fields if a Proxy isn't needed. Empty strings will cause failure.
|
||||
[proxy]
|
||||
|
||||
@ -265,6 +265,14 @@ shutdown_timeout = 30
|
||||
# HTTP Request body limit. Defaults to 32kB
|
||||
request_body_limit = 32_768
|
||||
|
||||
# HTTPS Server Configuration
|
||||
# Self-signed Private Key and Certificate can be generated with mkcert for local development
|
||||
[server.tls]
|
||||
port = 8081
|
||||
host = "127.0.0.1"
|
||||
private_key = "/path/to/private_key.pem"
|
||||
certificate = "/path/to/certificate.pem"
|
||||
|
||||
[secrets_management]
|
||||
secrets_manager = "aws_kms" # Secrets manager client to be used
|
||||
|
||||
|
||||
@ -9,7 +9,8 @@ readme = "README.md"
|
||||
license.workspace = true
|
||||
|
||||
[features]
|
||||
default = ["kv_store", "stripe", "oltp", "olap", "backwards_compatibility", "accounts_cache", "dummy_connector", "payouts", "payout_retry", "business_profile_routing", "connector_choice_mca_id", "profile_specific_fallback_routing", "retry", "frm"]
|
||||
default = ["kv_store", "stripe", "oltp", "olap", "backwards_compatibility", "accounts_cache", "dummy_connector", "payouts", "payout_retry", "business_profile_routing", "connector_choice_mca_id", "profile_specific_fallback_routing", "retry", "frm", "tls"]
|
||||
tls = ["actix-web/rustls-0_22"]
|
||||
email = ["external_services/email", "scheduler/email", "olap"]
|
||||
frm = ["api_models/frm", "hyperswitch_domain_models/frm"]
|
||||
stripe = ["dep:serde_qs"]
|
||||
@ -77,6 +78,8 @@ ring = "0.17.8"
|
||||
roxmltree = "0.19.0"
|
||||
rust_decimal = { version = "1.35.0", features = ["serde-with-float", "serde-with-str"] }
|
||||
rustc-hash = "1.1.0"
|
||||
rustls = "0.22"
|
||||
rustls-pemfile = "2"
|
||||
serde = { version = "1.0.197", features = ["derive"] }
|
||||
serde_json = "1.0.115"
|
||||
serde_path_to_error = "0.1.16"
|
||||
|
||||
@ -12,6 +12,8 @@ impl Default for super::settings::Server {
|
||||
host: "localhost".into(),
|
||||
request_body_limit: 16 * 1024, // POST request body is limited to 16KiB
|
||||
shutdown_timeout: 30,
|
||||
#[cfg(feature = "tls")]
|
||||
tls: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -547,6 +547,8 @@ pub struct Server {
|
||||
pub host: String,
|
||||
pub request_body_limit: usize,
|
||||
pub shutdown_timeout: u64,
|
||||
#[cfg(feature = "tls")]
|
||||
pub tls: Option<ServerTls>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
@ -826,6 +828,19 @@ pub struct PayPalOnboarding {
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
||||
#[cfg(feature = "tls")]
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct ServerTls {
|
||||
/// Port to host the TLS secure server on
|
||||
pub port: u16,
|
||||
/// Use a different host (optional) (defaults to the host provided in [`Server`] config)
|
||||
pub host: Option<String>,
|
||||
/// private key file path associated with TLS (path to the private key file (`pem` format))
|
||||
pub private_key: PathBuf,
|
||||
/// certificate file associated with TLS (path to the certificate file (`pem` format))
|
||||
pub certificate: PathBuf,
|
||||
}
|
||||
|
||||
fn deserialize_hashset_inner<T>(value: impl AsRef<str>) -> Result<HashSet<T>, String>
|
||||
where
|
||||
T: Eq + std::str::FromStr + std::hash::Hash,
|
||||
|
||||
@ -200,11 +200,65 @@ pub async fn start_server(conf: settings::Settings<SecuredSecret>) -> Applicatio
|
||||
);
|
||||
let state = Box::pin(AppState::new(conf, tx, api_client)).await;
|
||||
let request_body_limit = server.request_body_limit;
|
||||
let server = actix_web::HttpServer::new(move || mk_app(state.clone(), request_body_limit))
|
||||
.bind((server.host.as_str(), server.port))?
|
||||
.workers(server.workers)
|
||||
.shutdown_timeout(server.shutdown_timeout)
|
||||
.run();
|
||||
|
||||
let server_builder =
|
||||
actix_web::HttpServer::new(move || mk_app(state.clone(), request_body_limit))
|
||||
.bind((server.host.as_str(), server.port))?
|
||||
.workers(server.workers)
|
||||
.shutdown_timeout(server.shutdown_timeout);
|
||||
|
||||
#[cfg(feature = "tls")]
|
||||
let server = match server.tls {
|
||||
None => server_builder.run(),
|
||||
Some(tls_conf) => {
|
||||
let cert_file =
|
||||
&mut std::io::BufReader::new(std::fs::File::open(tls_conf.certificate).map_err(
|
||||
|err| errors::ApplicationError::InvalidConfigurationValueError(err.to_string()),
|
||||
)?);
|
||||
let key_file =
|
||||
&mut std::io::BufReader::new(std::fs::File::open(tls_conf.private_key).map_err(
|
||||
|err| errors::ApplicationError::InvalidConfigurationValueError(err.to_string()),
|
||||
)?);
|
||||
|
||||
let cert_chain = rustls_pemfile::certs(cert_file)
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(|err| {
|
||||
errors::ApplicationError::InvalidConfigurationValueError(err.to_string())
|
||||
})?;
|
||||
|
||||
let mut keys = rustls_pemfile::pkcs8_private_keys(key_file)
|
||||
.map(|key| key.map(rustls::pki_types::PrivateKeyDer::Pkcs8))
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(|err| {
|
||||
errors::ApplicationError::InvalidConfigurationValueError(err.to_string())
|
||||
})?;
|
||||
|
||||
// exit if no keys could be parsed
|
||||
if keys.is_empty() {
|
||||
return Err(errors::ApplicationError::InvalidConfigurationValueError(
|
||||
"Could not locate PKCS8 private keys.".into(),
|
||||
));
|
||||
}
|
||||
|
||||
let config_builder = rustls::ServerConfig::builder().with_no_client_auth();
|
||||
let config = config_builder
|
||||
.with_single_cert(cert_chain, keys.remove(0))
|
||||
.map_err(|err| {
|
||||
errors::ApplicationError::InvalidConfigurationValueError(err.to_string())
|
||||
})?;
|
||||
|
||||
server_builder
|
||||
.bind_rustls_0_22(
|
||||
(tls_conf.host.unwrap_or(server.host).as_str(), tls_conf.port),
|
||||
config,
|
||||
)?
|
||||
.run()
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "tls"))]
|
||||
let server = server_builder.run();
|
||||
|
||||
let _task_handle = tokio::spawn(receiver_for_error(rx, server.handle()).in_current_span());
|
||||
Ok(server)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user