From 79013024ff371efc6062310564b8b56e9bb22701 Mon Sep 17 00:00:00 2001 From: Kartikeya Hegde Date: Mon, 6 Jan 2025 20:37:20 +0530 Subject: [PATCH] chore(keymanager): add tenant-id to keymanager requests (#6968) Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> --- config/config.example.toml | 2 +- config/deployments/env_specific.toml | 2 +- config/development.toml | 2 +- config/docker_compose.toml | 2 +- crates/common_utils/src/consts.rs | 3 +++ crates/common_utils/src/id_type/tenant.rs | 12 ++++++++- crates/common_utils/src/keymanager.rs | 15 ++++++++--- crates/common_utils/src/types/keymanager.rs | 30 +++++++++++++++++++++ crates/router/src/configs/defaults.rs | 12 +++++++++ crates/router/src/configs/settings.rs | 6 +++-- crates/router/src/types/domain/types.rs | 2 ++ loadtest/config/development.toml | 2 +- 12 files changed, 79 insertions(+), 11 deletions(-) diff --git a/config/config.example.toml b/config/config.example.toml index 999266321144..eb30435d5f8f 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -762,7 +762,7 @@ sdk_eligible_payment_methods = "card" [multitenancy] enabled = false -global_tenant = { schema = "public", redis_key_prefix = "", clickhouse_database = "default"} +global_tenant = { tenant_id = "global", schema = "public", redis_key_prefix = "", clickhouse_database = "default"} [multitenancy.tenants.public] base_url = "http://localhost:8080" # URL of the tenant diff --git a/config/deployments/env_specific.toml b/config/deployments/env_specific.toml index 967b847dae51..809edf1bac60 100644 --- a/config/deployments/env_specific.toml +++ b/config/deployments/env_specific.toml @@ -303,7 +303,7 @@ region = "kms_region" # The AWS region used by the KMS SDK for decrypting data. [multitenancy] enabled = false -global_tenant = { schema = "public", redis_key_prefix = "", clickhouse_database = "default"} +global_tenant = { tenant_id = "global", schema = "public", redis_key_prefix = "", clickhouse_database = "default"} [multitenancy.tenants.public] base_url = "http://localhost:8080" diff --git a/config/development.toml b/config/development.toml index 4c9b8516b5ad..e3631b96b173 100644 --- a/config/development.toml +++ b/config/development.toml @@ -794,7 +794,7 @@ sdk_eligible_payment_methods = "card" [multitenancy] enabled = false -global_tenant = { schema = "public", redis_key_prefix = "", clickhouse_database = "default"} +global_tenant = { tenant_id = "global" ,schema = "public", redis_key_prefix = "global", clickhouse_database = "default"} [multitenancy.tenants.public] base_url = "http://localhost:8080" diff --git a/config/docker_compose.toml b/config/docker_compose.toml index 75699d0a9674..6f95380d2db3 100644 --- a/config/docker_compose.toml +++ b/config/docker_compose.toml @@ -635,7 +635,7 @@ sdk_eligible_payment_methods = "card" [multitenancy] enabled = false -global_tenant = { schema = "public", redis_key_prefix = "", clickhouse_database = "default" } +global_tenant = { tenant_id = "global", schema = "public", redis_key_prefix = "", clickhouse_database = "default" } [multitenancy.tenants.public] base_url = "http://localhost:8080" diff --git a/crates/common_utils/src/consts.rs b/crates/common_utils/src/consts.rs index 3b437b703bef..fdda26cc77c7 100644 --- a/crates/common_utils/src/consts.rs +++ b/crates/common_utils/src/consts.rs @@ -149,3 +149,6 @@ pub const APPLEPAY_VALIDATION_URL: &str = /// Request ID pub const X_REQUEST_ID: &str = "x-request-id"; + +/// Default Tenant ID for the `Global` tenant +pub const DEFAULT_GLOBAL_TENANT_ID: &str = "global"; diff --git a/crates/common_utils/src/id_type/tenant.rs b/crates/common_utils/src/id_type/tenant.rs index 953bf82287af..0584496332a5 100644 --- a/crates/common_utils/src/id_type/tenant.rs +++ b/crates/common_utils/src/id_type/tenant.rs @@ -1,4 +1,7 @@ -use crate::errors::{CustomResult, ValidationError}; +use crate::{ + consts::DEFAULT_GLOBAL_TENANT_ID, + errors::{CustomResult, ValidationError}, +}; crate::id_type!( TenantId, @@ -15,6 +18,13 @@ crate::impl_queryable_id_type!(TenantId); crate::impl_to_sql_from_sql_id_type!(TenantId); impl TenantId { + /// Get the default global tenant ID + pub fn get_default_global_tenant_id() -> Self { + Self(super::LengthId::new_unchecked( + super::AlphaNumericId::new_unchecked(DEFAULT_GLOBAL_TENANT_ID.to_string()), + )) + } + /// Get tenant id from String pub fn try_from_string(tenant_id: String) -> CustomResult { Self::try_from(std::borrow::Cow::from(tenant_id)) diff --git a/crates/common_utils/src/keymanager.rs b/crates/common_utils/src/keymanager.rs index 53761951791c..0dc05b22fd76 100644 --- a/crates/common_utils/src/keymanager.rs +++ b/crates/common_utils/src/keymanager.rs @@ -11,11 +11,11 @@ use once_cell::sync::OnceCell; use router_env::{instrument, logger, tracing}; use crate::{ - consts::BASE64_ENGINE, + consts::{BASE64_ENGINE, TENANT_HEADER}, errors, types::keymanager::{ BatchDecryptDataRequest, DataKeyCreateResponse, DecryptDataRequest, - EncryptionCreateRequest, EncryptionTransferRequest, KeyManagerState, + EncryptionCreateRequest, EncryptionTransferRequest, GetKeymanagerTenant, KeyManagerState, TransientBatchDecryptDataRequest, TransientDecryptDataRequest, }, }; @@ -100,7 +100,7 @@ pub async fn call_encryption_service( request_body: T, ) -> errors::CustomResult where - T: ConvertRaw + Send + Sync + 'static + Debug, + T: GetKeymanagerTenant + ConvertRaw + Send + Sync + 'static + Debug, R: serde::de::DeserializeOwned, { let url = format!("{}/{endpoint}", &state.url); @@ -122,6 +122,15 @@ where .change_context(errors::KeyManagerClientError::FailedtoConstructHeader)?, )) } + + //Add Tenant ID + header.push(( + HeaderName::from_str(TENANT_HEADER) + .change_context(errors::KeyManagerClientError::FailedtoConstructHeader)?, + HeaderValue::from_str(request_body.get_tenant_id(state).get_string_repr()) + .change_context(errors::KeyManagerClientError::FailedtoConstructHeader)?, + )); + let response = send_encryption_request( state, HeaderMap::from_iter(header.into_iter()), diff --git a/crates/common_utils/src/types/keymanager.rs b/crates/common_utils/src/types/keymanager.rs index 09d26bd91ef8..f18c66562070 100644 --- a/crates/common_utils/src/types/keymanager.rs +++ b/crates/common_utils/src/types/keymanager.rs @@ -23,8 +23,23 @@ use crate::{ transformers::{ForeignFrom, ForeignTryFrom}, }; +macro_rules! impl_get_tenant_for_request { + ($ty:ident) => { + impl GetKeymanagerTenant for $ty { + fn get_tenant_id(&self, state: &KeyManagerState) -> id_type::TenantId { + match self.identifier { + Identifier::User(_) | Identifier::UserAuth(_) => state.global_tenant_id.clone(), + Identifier::Merchant(_) => state.tenant_id.clone(), + } + } + } + }; +} + #[derive(Debug, Clone)] pub struct KeyManagerState { + pub tenant_id: id_type::TenantId, + pub global_tenant_id: id_type::TenantId, pub enabled: bool, pub url: String, pub client_idle_timeout: Option, @@ -35,6 +50,11 @@ pub struct KeyManagerState { #[cfg(feature = "keymanager_mtls")] pub cert: Secret, } + +pub trait GetKeymanagerTenant { + fn get_tenant_id(&self, state: &KeyManagerState) -> id_type::TenantId; +} + #[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)] #[serde(tag = "data_identifier", content = "key_identifier")] pub enum Identifier { @@ -70,6 +90,10 @@ pub struct BatchEncryptDataRequest { pub data: DecryptedDataGroup, } +impl_get_tenant_for_request!(EncryptionCreateRequest); +impl_get_tenant_for_request!(EncryptionTransferRequest); +impl_get_tenant_for_request!(BatchEncryptDataRequest); + impl From<(Secret, S>, Identifier)> for EncryptDataRequest where S: Strategy>, @@ -219,6 +243,12 @@ pub struct DecryptDataRequest { pub data: StrongSecret, } +impl_get_tenant_for_request!(EncryptDataRequest); +impl_get_tenant_for_request!(TransientBatchDecryptDataRequest); +impl_get_tenant_for_request!(TransientDecryptDataRequest); +impl_get_tenant_for_request!(BatchDecryptDataRequest); +impl_get_tenant_for_request!(DecryptDataRequest); + impl ForeignFrom<(FxHashMap>, BatchEncryptDataResponse)> for FxHashMap>> where diff --git a/crates/router/src/configs/defaults.rs b/crates/router/src/configs/defaults.rs index 74f6502159da..3c38fa2a7751 100644 --- a/crates/router/src/configs/defaults.rs +++ b/crates/router/src/configs/defaults.rs @@ -1,6 +1,7 @@ use std::collections::{HashMap, HashSet}; use api_models::{enums, payment_methods::RequiredFieldInfo}; +use common_utils::id_type; #[cfg(feature = "payouts")] pub mod payout_required_fields; @@ -138,6 +139,17 @@ impl Default for super::settings::KvConfig { } } +impl Default for super::settings::GlobalTenant { + fn default() -> Self { + Self { + tenant_id: id_type::TenantId::get_default_global_tenant_id(), + schema: String::from("global"), + redis_key_prefix: String::from("global"), + clickhouse_database: String::from("global"), + } + } +} + #[allow(clippy::derivable_impls)] impl Default for super::settings::ApiKeys { fn default() -> Self { diff --git a/crates/router/src/configs/settings.rs b/crates/router/src/configs/settings.rs index ad5d9e89aaae..737f8dfb980e 100644 --- a/crates/router/src/configs/settings.rs +++ b/crates/router/src/configs/settings.rs @@ -137,7 +137,7 @@ pub struct Platform { pub enabled: bool, } -#[derive(Debug, Deserialize, Clone, Default)] +#[derive(Debug, Clone, Default, Deserialize)] pub struct Multitenancy { pub tenants: TenantConfig, pub enabled: bool, @@ -195,8 +195,10 @@ impl storage_impl::config::TenantConfig for Tenant { } } -#[derive(Debug, Deserialize, Clone, Default)] +#[derive(Debug, Deserialize, Clone)] pub struct GlobalTenant { + #[serde(default = "id_type::TenantId::get_default_global_tenant_id")] + pub tenant_id: id_type::TenantId, pub schema: String, pub redis_key_prefix: String, pub clickhouse_database: String, diff --git a/crates/router/src/types/domain/types.rs b/crates/router/src/types/domain/types.rs index d4cd9ef62d7d..bb123659060d 100644 --- a/crates/router/src/types/domain/types.rs +++ b/crates/router/src/types/domain/types.rs @@ -7,6 +7,8 @@ impl From<&crate::SessionState> for KeyManagerState { fn from(state: &crate::SessionState) -> Self { let conf = state.conf.key_manager.get_inner(); Self { + global_tenant_id: state.conf.multitenancy.global_tenant.tenant_id.clone(), + tenant_id: state.tenant.tenant_id.clone(), enabled: conf.enabled, url: conf.url.clone(), client_idle_timeout: state.conf.proxy.idle_pool_connection_timeout, diff --git a/loadtest/config/development.toml b/loadtest/config/development.toml index ec58ab08b878..b26b5b2e438d 100644 --- a/loadtest/config/development.toml +++ b/loadtest/config/development.toml @@ -400,7 +400,7 @@ keys = "accept-language,user-agent,x-profile-id" [multitenancy] enabled = false -global_tenant = { schema = "public", redis_key_prefix = "" } +global_tenant = { tenant_id = "global", schema = "public", redis_key_prefix = "" } [multitenancy.tenants.public] base_url = "http://localhost:8080"