diff --git a/Cargo.lock b/Cargo.lock index a2d8c40..3252aa2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -394,6 +394,9 @@ name = "cidr" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bdf600c45bd958cf2945c445264471cca8b6c8e67bc87b71affd6d7e5682621" +dependencies = [ + "serde", +] [[package]] name = "cipher" @@ -1476,6 +1479,7 @@ dependencies = [ name = "harmony_macros" version = "0.1.0" dependencies = [ + "cidr", "harmony_types", "quote", "serde", diff --git a/Cargo.toml b/Cargo.toml index 8dd08bb..1512154 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ env_logger = "0.11.5" derive-new = "0.7.0" async-trait = "0.1.82" tokio = { version = "1.40.0", features = ["io-std", "fs", "macros", "rt-multi-thread"] } -cidr = "0.2.3" +cidr = { features = ["serde"], version = "0.2" } russh = "0.45.0" russh-keys = "0.45.0" rand = "0.8.5" diff --git a/harmony/src/domain/topology/tenant/k8s.rs b/harmony/src/domain/topology/tenant/k8s.rs index 93fc0c3..a68f84d 100644 --- a/harmony/src/domain/topology/tenant/k8s.rs +++ b/harmony/src/domain/topology/tenant/k8s.rs @@ -8,7 +8,7 @@ use async_trait::async_trait; use derive_new::new; use k8s_openapi::api::{ core::v1::{Namespace, ResourceQuota}, - networking::v1::NetworkPolicy, + networking::v1::{NetworkPolicy, NetworkPolicyEgressRule, NetworkPolicyIngressRule}, }; use kube::Resource; use log::{debug, info, warn}; @@ -191,12 +191,80 @@ impl K8sTenantManager { } }); - serde_json::from_value(network_policy).map_err(|e| { - ExecutorError::ConfigurationError(format!( - "Could not build TenantManager NetworkPolicy. {}", - e - )) - }) + let mut network_policy: NetworkPolicy = + serde_json::from_value(network_policy).map_err(|e| { + ExecutorError::ConfigurationError(format!( + "Could not build TenantManager NetworkPolicy. {}", + e + )) + })?; + + config + .network_policy + .additional_allowed_cidr_ingress + .iter() + .try_for_each(|c| -> Result<(), ExecutorError> { + let rule = serde_json::from_value::(json!({ + "from": [ + { + "ipBlock": { + + "cidr": c.to_string(), + } + } + ] + })) + .map_err(|e| { + ExecutorError::ConfigurationError(format!( + "Could not build TenantManager NetworkPolicyIngressRule. {}", + e + )) + })?; + + network_policy + .spec + .as_mut() + .unwrap() + .ingress + .as_mut() + .unwrap() + .push(rule); + Ok(()) + })?; + + config + .network_policy + .additional_allowed_cidr_egress + .iter() + .try_for_each(|c| -> Result<(), ExecutorError> { + let rule = serde_json::from_value::(json!({ + "to": [ + { + "ipBlock": { + + "cidr": c.to_string(), + } + } + ] + })) + .map_err(|e| { + ExecutorError::ConfigurationError(format!( + "Could not build TenantManager NetworkPolicyEgressRule. {}", + e + )) + })?; + network_policy + .spec + .as_mut() + .unwrap() + .egress + .as_mut() + .unwrap() + .push(rule); + Ok(()) + })?; + + Ok(network_policy) } } diff --git a/harmony/src/domain/topology/tenant/mod.rs b/harmony/src/domain/topology/tenant/mod.rs index 35326fb..8fd5fea 100644 --- a/harmony/src/domain/topology/tenant/mod.rs +++ b/harmony/src/domain/topology/tenant/mod.rs @@ -27,22 +27,18 @@ impl Default for TenantConfig { Self { name: format!("tenant_{id}"), id, - resource_limits: ResourceLimits { - cpu_request_cores: 4.0, - cpu_limit_cores: 4.0, - memory_request_gb: 4.0, - memory_limit_gb: 4.0, - storage_total_gb: 20.0, - }, + resource_limits: ResourceLimits::default(), network_policy: TenantNetworkPolicy { default_inter_tenant_ingress: InterTenantIngressPolicy::DenyAll, default_internet_egress: InternetEgressPolicy::AllowAll, + additional_allowed_cidr_ingress: vec![], + additional_allowed_cidr_egress: vec![], }, } } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct ResourceLimits { /// Requested/guaranteed CPU cores (e.g., 2.0). pub cpu_request_cores: f32, @@ -58,6 +54,18 @@ pub struct ResourceLimits { pub storage_total_gb: f32, } +impl Default for ResourceLimits { + fn default() -> Self { + Self { + cpu_request_cores: 4.0, + cpu_limit_cores: 4.0, + memory_request_gb: 4.0, + memory_limit_gb: 4.0, + storage_total_gb: 20.0, + } + } +} + #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct TenantNetworkPolicy { /// Policy for ingress traffic originating from other tenants within the same Harmony-managed environment. @@ -65,6 +73,20 @@ pub struct TenantNetworkPolicy { /// Policy for egress traffic destined for the public internet. pub default_internet_egress: InternetEgressPolicy, + + pub additional_allowed_cidr_ingress: Vec, + pub additional_allowed_cidr_egress: Vec, +} + +impl Default for TenantNetworkPolicy { + fn default() -> Self { + TenantNetworkPolicy { + default_inter_tenant_ingress: InterTenantIngressPolicy::DenyAll, + default_internet_egress: InternetEgressPolicy::DenyAll, + additional_allowed_cidr_ingress: vec![], + additional_allowed_cidr_egress: vec![], + } + } } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] diff --git a/harmony_macros/Cargo.toml b/harmony_macros/Cargo.toml index 1a314c3..7185d0b 100644 --- a/harmony_macros/Cargo.toml +++ b/harmony_macros/Cargo.toml @@ -14,6 +14,7 @@ quote = "1.0.37" serde = "1.0.217" serde_yaml = "0.9.34" syn = "2.0.90" +cidr.workspace = true [dev-dependencies] serde = { version = "1.0.217", features = ["derive"] } diff --git a/harmony_macros/src/lib.rs b/harmony_macros/src/lib.rs index 7e9ee47..7a2748d 100644 --- a/harmony_macros/src/lib.rs +++ b/harmony_macros/src/lib.rs @@ -132,3 +132,16 @@ pub fn ingress_path(input: TokenStream) -> TokenStream { false => panic!("Invalid ingress path"), } } + +#[proc_macro] +pub fn cidrv4(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as LitStr); + let cidr_str = input.value(); + + if let Ok(_) = cidr_str.parse::() { + let expanded = quote! { #cidr_str.parse::().unwrap() }; + return TokenStream::from(expanded); + } + + panic!("Invalid IPv4 CIDR : {}", cidr_str); +}