1use linkerd_policy_controller_k8s_api::{
2 self as api,
3 policy::server_authorization::{
4 Client, MeshTls, Network, Server, ServerAuthorization, ServerAuthorizationSpec,
5 },
6};
7use linkerd_policy_test::admission;
8
9#[tokio::test(flavor = "current_thread")]
10async fn accepts_valid() {
11 admission::accepts(|ns| ServerAuthorization {
12 metadata: api::ObjectMeta {
13 namespace: Some(ns),
14 name: Some("test".to_string()),
15 ..Default::default()
16 },
17 spec: ServerAuthorizationSpec {
18 server: Server {
19 name: Some("test".to_string()),
20 selector: None,
21 },
22 client: Client {
23 networks: Some(vec![
24 Network {
25 cidr: "10.1.0.0/24".parse().unwrap(),
26 except: None,
27 },
28 Network {
29 cidr: "10.1.1.0/24".parse().unwrap(),
30 except: Some(vec!["10.1.1.0/28".parse().unwrap()]),
31 },
32 ]),
33 unauthenticated: true,
34 mesh_tls: None,
35 },
36 },
37 })
38 .await;
39}
40
41#[tokio::test(flavor = "current_thread")]
42async fn rejects_except_whole_cidr() {
43 admission::rejects(|ns| ServerAuthorization {
44 metadata: api::ObjectMeta {
45 namespace: Some(ns),
46 name: Some("test".to_string()),
47 ..Default::default()
48 },
49 spec: ServerAuthorizationSpec {
50 server: Server {
51 name: Some("test".to_string()),
52 selector: None,
53 },
54 client: Client {
55 networks: Some(vec![Network {
56 cidr: "10.1.1.0/24".parse().unwrap(),
57 except: Some(vec!["10.1.0.0/16".parse().unwrap()]),
58 }]),
59 unauthenticated: true,
60 mesh_tls: None,
61 },
62 },
63 })
64 .await;
65}
66
67#[tokio::test(flavor = "current_thread")]
68async fn rejects_unauthenciated_and_mtls() {
69 admission::rejects(|ns| ServerAuthorization {
70 metadata: api::ObjectMeta {
71 namespace: Some(ns),
72 name: Some("test".to_string()),
73 ..Default::default()
74 },
75 spec: ServerAuthorizationSpec {
76 server: Server {
77 name: Some("test".to_string()),
78 selector: None,
79 },
80 client: Client {
81 unauthenticated: true,
82 mesh_tls: Some(MeshTls {
83 identities: Some(vec!["*".to_string()]),
84 ..Default::default()
85 }),
86 networks: None,
87 },
88 },
89 })
90 .await;
91}
92
93#[tokio::test(flavor = "current_thread")]
94async fn rejects_unauthenciated_tls_and_identities() {
95 admission::rejects(|ns| ServerAuthorization {
96 metadata: api::ObjectMeta {
97 namespace: Some(ns),
98 name: Some("test".to_string()),
99 ..Default::default()
100 },
101 spec: ServerAuthorizationSpec {
102 server: Server {
103 name: Some("test".to_string()),
104 selector: None,
105 },
106 client: Client {
107 mesh_tls: Some(MeshTls {
108 unauthenticated_tls: true,
109 identities: Some(vec!["*".to_string()]),
110 ..Default::default()
111 }),
112 networks: None,
113 ..Default::default()
114 },
115 },
116 })
117 .await;
118}
119
120#[tokio::test(flavor = "current_thread")]
121async fn accepts_network_as_ip() {
122 admission::accepts(|ns| ServerAuthorization {
123 metadata: api::ObjectMeta {
124 namespace: Some(ns),
125 name: Some("test".to_string()),
126 ..Default::default()
127 },
128 spec: ServerAuthorizationSpec {
129 server: Server {
130 name: Some("test".to_string()),
131 selector: None,
132 },
133 client: Client {
134 networks: Some(vec![
135 Network {
136 cidr: "10.1.0.2".parse().unwrap(),
137 except: None,
138 },
139 Network {
140 cidr: "10.1.1.0/24".parse().unwrap(),
141 except: Some(vec!["10.1.1.3".parse().unwrap()]),
142 },
143 ]),
144 unauthenticated: true,
145 mesh_tls: None,
146 },
147 },
148 })
149 .await;
150}
151
152#[tokio::test(flavor = "current_thread")]
153async fn rejects_except_not_in_cidr() {
154 admission::rejects(|ns| ServerAuthorization {
155 metadata: api::ObjectMeta {
156 namespace: Some(ns),
157 name: Some("test".to_string()),
158 ..Default::default()
159 },
160 spec: ServerAuthorizationSpec {
161 server: Server {
162 name: Some("test".to_string()),
163 selector: None,
164 },
165 client: Client {
166 networks: Some(vec![Network {
167 cidr: "10.1.1.0/24".parse().unwrap(),
168 except: Some(vec!["10.1.2.0/24".parse().unwrap()]),
169 }]),
170 unauthenticated: true,
171 mesh_tls: None,
172 },
173 },
174 })
175 .await;
176}
177
178#[tokio::test(flavor = "current_thread")]
179async fn rejects_invalid_cidr() {
180 // Duplicate the CRD with relaxed validation so we can send an invalid CIDR value.
181 #[derive(
182 Clone,
183 Debug,
184 Default,
185 kube::CustomResource,
186 serde::Deserialize,
187 serde::Serialize,
188 schemars::JsonSchema,
189 )]
190 #[kube(
191 group = "policy.linkerd.io",
192 version = "v1alpha1",
193 kind = "ServerAuthorization",
194 namespaced
195 )]
196 #[serde(rename_all = "camelCase")]
197 pub struct ServerAuthorizationSpec {
198 pub server: Server,
199 pub client: Client,
200 }
201
202 #[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize, schemars::JsonSchema)]
203 #[serde(rename_all = "camelCase")]
204 pub struct Client {
205 pub networks: Option<Vec<Network>>,
206
207 #[serde(default)]
208 pub unauthenticated: bool,
209
210 #[serde(rename = "meshTLS")]
211 pub mesh_tls: Option<MeshTls>,
212 }
213
214 #[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize, schemars::JsonSchema)]
215 #[serde(rename_all = "camelCase")]
216 pub struct Network {
217 pub cidr: String,
218 pub except: Option<Vec<String>>,
219 }
220
221 admission::rejects(|ns| ServerAuthorization {
222 metadata: api::ObjectMeta {
223 namespace: Some(ns),
224 name: Some("test".to_string()),
225 ..Default::default()
226 },
227 spec: ServerAuthorizationSpec {
228 server: Server {
229 name: Some("test".to_string()),
230 selector: None,
231 },
232 client: Client {
233 networks: Some(vec![Network {
234 cidr: "bogus".to_string(),
235 except: None,
236 }]),
237 unauthenticated: true,
238 mesh_tls: None,
239 },
240 },
241 })
242 .await;
243}
View as plain text