use linkerd_policy_controller_k8s_api::{ self as api, policy::server_authorization::{ Client, MeshTls, Network, Server, ServerAuthorization, ServerAuthorizationSpec, }, }; use linkerd_policy_test::admission; #[tokio::test(flavor = "current_thread")] async fn accepts_valid() { admission::accepts(|ns| ServerAuthorization { metadata: api::ObjectMeta { namespace: Some(ns), name: Some("test".to_string()), ..Default::default() }, spec: ServerAuthorizationSpec { server: Server { name: Some("test".to_string()), selector: None, }, client: Client { networks: Some(vec![ Network { cidr: "10.1.0.0/24".parse().unwrap(), except: None, }, Network { cidr: "10.1.1.0/24".parse().unwrap(), except: Some(vec!["10.1.1.0/28".parse().unwrap()]), }, ]), unauthenticated: true, mesh_tls: None, }, }, }) .await; } #[tokio::test(flavor = "current_thread")] async fn rejects_except_whole_cidr() { admission::rejects(|ns| ServerAuthorization { metadata: api::ObjectMeta { namespace: Some(ns), name: Some("test".to_string()), ..Default::default() }, spec: ServerAuthorizationSpec { server: Server { name: Some("test".to_string()), selector: None, }, client: Client { networks: Some(vec![Network { cidr: "10.1.1.0/24".parse().unwrap(), except: Some(vec!["10.1.0.0/16".parse().unwrap()]), }]), unauthenticated: true, mesh_tls: None, }, }, }) .await; } #[tokio::test(flavor = "current_thread")] async fn rejects_unauthenciated_and_mtls() { admission::rejects(|ns| ServerAuthorization { metadata: api::ObjectMeta { namespace: Some(ns), name: Some("test".to_string()), ..Default::default() }, spec: ServerAuthorizationSpec { server: Server { name: Some("test".to_string()), selector: None, }, client: Client { unauthenticated: true, mesh_tls: Some(MeshTls { identities: Some(vec!["*".to_string()]), ..Default::default() }), networks: None, }, }, }) .await; } #[tokio::test(flavor = "current_thread")] async fn rejects_unauthenciated_tls_and_identities() { admission::rejects(|ns| ServerAuthorization { metadata: api::ObjectMeta { namespace: Some(ns), name: Some("test".to_string()), ..Default::default() }, spec: ServerAuthorizationSpec { server: Server { name: Some("test".to_string()), selector: None, }, client: Client { mesh_tls: Some(MeshTls { unauthenticated_tls: true, identities: Some(vec!["*".to_string()]), ..Default::default() }), networks: None, ..Default::default() }, }, }) .await; } #[tokio::test(flavor = "current_thread")] async fn accepts_network_as_ip() { admission::accepts(|ns| ServerAuthorization { metadata: api::ObjectMeta { namespace: Some(ns), name: Some("test".to_string()), ..Default::default() }, spec: ServerAuthorizationSpec { server: Server { name: Some("test".to_string()), selector: None, }, client: Client { networks: Some(vec![ Network { cidr: "10.1.0.2".parse().unwrap(), except: None, }, Network { cidr: "10.1.1.0/24".parse().unwrap(), except: Some(vec!["10.1.1.3".parse().unwrap()]), }, ]), unauthenticated: true, mesh_tls: None, }, }, }) .await; } #[tokio::test(flavor = "current_thread")] async fn rejects_except_not_in_cidr() { admission::rejects(|ns| ServerAuthorization { metadata: api::ObjectMeta { namespace: Some(ns), name: Some("test".to_string()), ..Default::default() }, spec: ServerAuthorizationSpec { server: Server { name: Some("test".to_string()), selector: None, }, client: Client { networks: Some(vec![Network { cidr: "10.1.1.0/24".parse().unwrap(), except: Some(vec!["10.1.2.0/24".parse().unwrap()]), }]), unauthenticated: true, mesh_tls: None, }, }, }) .await; } #[tokio::test(flavor = "current_thread")] async fn rejects_invalid_cidr() { // Duplicate the CRD with relaxed validation so we can send an invalid CIDR value. #[derive( Clone, Debug, Default, kube::CustomResource, serde::Deserialize, serde::Serialize, schemars::JsonSchema, )] #[kube( group = "policy.linkerd.io", version = "v1alpha1", kind = "ServerAuthorization", namespaced )] #[serde(rename_all = "camelCase")] pub struct ServerAuthorizationSpec { pub server: Server, pub client: Client, } #[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize, schemars::JsonSchema)] #[serde(rename_all = "camelCase")] pub struct Client { pub networks: Option>, #[serde(default)] pub unauthenticated: bool, #[serde(rename = "meshTLS")] pub mesh_tls: Option, } #[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize, schemars::JsonSchema)] #[serde(rename_all = "camelCase")] pub struct Network { pub cidr: String, pub except: Option>, } admission::rejects(|ns| ServerAuthorization { metadata: api::ObjectMeta { namespace: Some(ns), name: Some("test".to_string()), ..Default::default() }, spec: ServerAuthorizationSpec { server: Server { name: Some("test".to_string()), selector: None, }, client: Client { networks: Some(vec![Network { cidr: "bogus".to_string(), except: None, }]), unauthenticated: true, mesh_tls: None, }, }, }) .await; }