feat: add support for custom CIDR ingress/egress rules #60
							
								
								
									
										4
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -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", | ||||
|  | ||||
| @ -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" | ||||
|  | ||||
| @ -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 { | ||||
|           } | ||||
|         }); | ||||
| 
 | ||||
|         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::<NetworkPolicyIngressRule>(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::<NetworkPolicyEgressRule>(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) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -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<cidr::Ipv4Cidr>, | ||||
|     pub additional_allowed_cidr_egress: Vec<cidr::Ipv4Cidr>, | ||||
| } | ||||
| 
 | ||||
| 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)] | ||||
|  | ||||
| @ -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"] } | ||||
|  | ||||
| @ -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::<cidr::Ipv4Cidr>() { | ||||
|         let expanded = quote! { #cidr_str.parse::<cidr::Ipv4Cidr>().unwrap() }; | ||||
|         return TokenStream::from(expanded); | ||||
|     } | ||||
| 
 | ||||
|     panic!("Invalid IPv4 CIDR : {}", cidr_str); | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user