Skip to content

Commit 72540d1

Browse files
committed
Add Tenancy API design suggestions.
Signed-off-by: Nadia Pinaeva <[email protected]>
1 parent f6c1cf2 commit 72540d1

File tree

1 file changed

+339
-2
lines changed

1 file changed

+339
-2
lines changed

npeps/npep-122.md

Lines changed: 339 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# NPEP-122: Tenancy API
22

33
* Issue: [#122](https://github.com/kubernetes-sigs/network-policy-api/issues/122)
4-
* Status: Provisional
4+
* Status: Implementable
55

66
## TLDR
77

@@ -158,7 +158,344 @@ Fourth, the ANP subject allows using pod selectors, while tenancy use cases only
158158

159159
## API
160160

161-
TBD
161+
### Tenant definition
162+
163+
For the purposes of this NPEP we define a Tenant as a set of namespaces.
164+
`tenancyLabels` is a set of label keys, based on which all Namespaces affected by Tenancy are be split into Tenants.
165+
A Tenant is identified by values of `tenancyLabels`, which are shared by all namespaces in a given Tenant.
166+
167+
There are 2 ways to select which namespaces should be affected by Tenancy rules:
168+
169+
1. Use a distinct new `namespaceSelector` field to define which namespaces should be affected by Tenancy,
170+
while the `tenancyLabels` field can be used to define how the selected namespaces are split into Tenants.
171+
172+
**Cons**: selected namespace may not have some of the `tenancyLabels`, which will likely result in introducing "None" value
173+
for `tenancyLabels`. It brings more complexity and is not required for any of the listed use cases.
174+
175+
```yaml
176+
spec:
177+
matchExpression:
178+
- key: system-namespace
179+
operator: DoesNotExist
180+
- key: user
181+
operator: Exists
182+
tenancyLabels:
183+
- user
184+
```
185+
186+
2. Overload `tenancyLabels` and implicitly apply tenancy rules only to namespaces where `tenancyLabels` are present.
187+
188+
**Cons**: the simplest option that covers all given use cases.
189+
190+
```yaml
191+
spec:
192+
tenancyLabels:
193+
- user
194+
```
195+
196+
### Peers and actions
197+
198+
Based on the existing User Stories, Tenancy only needs Allow and Deny actions (Skip is still discussed), and the only 2 types of peers are
199+
`SameTenant` and `NotSameTenant`.
200+
201+
From the user stories (and common sense) looks like the only useful combinations are `SameTenant: Allow/Skip` and `NotSameTenant: Deny`.
202+
We can always replace `NotSameTenant: Deny` with Tenancy using `SameTenant: Allow/Skip` and lower priority
203+
and (B)ANP `Deny` policy for the same tenancy selector (or maybe even wider selector, e.g. all user pods).
204+
This helps focus on which policy is defined inside one tenant, and then "everything else"/"other tenants"/etc
205+
may be defined with existing CRDs.
206+
207+
Whether `NotSameTenant` action makes API any better/easier to understand is still to be discussed.
208+
**PROS** of using only `SameTenant`
209+
- no need to specify egress and ingress
210+
- flexibility with Deny rules provided by ANP/BANP (e.g. unifying deny not same tenant with deny all in the same rule)
211+
212+
Ingress and Egress don't need to be separated is we only define `SameTenant`, as subject and peer are the same set of pods (sameTenant pods).
213+
214+
Therefore, Tenancy rules may look something like:
215+
216+
```yaml
217+
spec:
218+
actions: Allow
219+
peer: SameTenant
220+
```
221+
222+
### Priorities
223+
224+
Based on User Story 4.4, we need to have Tenancy in the same priority range as ANP and BANP. There are multiple ways to do so:
225+
226+
1. Reuse ANP and BANP to define priority, insert Tenancy rules to `ingress` and `egress`.
227+
Current (B)ANP semantics is: `subject` selects pod to which all `ingress` and `egress` rules are applied.
228+
Tenancy can't be used in this semantics, because it has its own "subject" defined by the tenancy labels.
229+
There are multiple ways to "turn on" tenancy mode in B(ANP) and allow tenancy rules.
230+
231+
Exclusive fields `subject`/`tenancySubject`
232+
```yaml
233+
kind: AdminNetworkPolicy
234+
spec:
235+
# this field turns on tenancy
236+
tenancySubject:
237+
labels: ["user"]
238+
ingress:
239+
- action: Allow
240+
from:
241+
- SameTenant
242+
- pods:
243+
podSelector: {}
244+
```
245+
246+
A similar, but slightly different option with pushing `tenantNamespace` as an alternative subject selector to existing
247+
`pods` and `namespaces`
248+
```yaml
249+
kind: AdminNetworkPolicy
250+
spec:
251+
# this field turns on tenancy
252+
subject:
253+
tenantNamespaces:
254+
labels: ["user"]
255+
ingress:
256+
- action: Allow
257+
from:
258+
- SameTenant
259+
- pods:
260+
podSelector: {}
261+
```
262+
**CONS**
263+
- "switch" that enables some peer types is not the best API design
264+
- gives more flexibility than intended (multiple tenancy definitions)
265+
- conflicts with singleton BANP, meaning that if Tenancy is defined on BANP level, general-purpose BANP selecting different
266+
pods can't be created.
267+
268+
2. Reuse ANP and BANP to define priority, insert Tenancy definition and Rules to `ingress` and `egress`.
269+
270+
It splits the tenancy labels and namespace selector which defines the namespace that are affected by the tenancy.
271+
272+
```yaml
273+
kind: AdminNetworkPolicy
274+
spec:
275+
priority: 10
276+
subject:
277+
namespaces:
278+
matchLabels:
279+
kubernetes.io/metadata.name: sensitive-ns
280+
ingress:
281+
- action: Allow
282+
from:
283+
- tenant:
284+
labels: ["user"]
285+
tenant: Same
286+
```
287+
288+
**CONS** complicates selection or affected namespaces, allows strange configuration, where namespaces selected by
289+
`subject` have no tenancy labels. Has the same problem as the original design.
290+
291+
3. Create 2 objects with ANP and BANP priorities (let's say NetworkTenancy and BaselineNetworkTenancy)
292+
293+
```yaml
294+
kind: NetworkTenancy
295+
spec:
296+
priority: 10
297+
tenancyLabels: ["user"]
298+
actions: Allow
299+
peer: SameTenant
300+
---
301+
kind: BaselineNetworkTenancy
302+
spec:
303+
priority: 10
304+
tenancyLabels: ["user"]
305+
actions: Allow
306+
peer: SameTenant
307+
```
308+
309+
While multiple ANPs with the same priority are allowed, we probably can allow multiple Tenancies or Tenancy and ANP
310+
with the same priority, but if we decide to only allow ANP per priority, Tenancy needs to be accounted for in the same range.
311+
312+
**CONS**: BANP doesn't have a priority, to use this method we would need to define a priority for BANP.
313+
314+
4. Create 1 new object with implicit priorities.
315+
316+
`precedence` field + reserved highest-priority rule before (B)ANP
317+
Similar to the previous one, but a bit more flexible:
318+
```yaml
319+
kind: NetworkTenancy
320+
spec:
321+
tenancyLabels: ["user"]
322+
precedence: ANP/BANP
323+
action: Allow/Skip
324+
```
325+
**CONS** Priorities are implicit and need to be added as extra layers between ANP/NP/BANP.
326+
**PROS**
327+
- No changes to the existing ANP/BANP objects
328+
- Limited to the use cases we designed it for (smaller chance to shoot yourself in a foot)
329+
- Users that don't care about tenancy can just ignore this CRD
330+
- We can throw it away if we want to change API again
331+
332+
333+
#### Final suggestion
334+
335+
Considering we agree with option 4 from the previous section on priorities specification, we can outline further details here.
336+
337+
For
338+
```yaml
339+
kind: NetworkTenancy
340+
spec:
341+
tenancyLabels: ["user"]
342+
precedence: ANP/BANP
343+
action: Allow/Skip
344+
```
345+
there are only 3 useful combinations of precedence+action (BANP+Skip is the same as BANP+Allow), so we can express these
346+
options in a different way, e.g. define 3 modes
347+
- always-allow (ANP+Allow)
348+
- delegate-to-NP (ANP+Skip)
349+
- baseline-allow (BANP+Allow)
350+
351+
<details>
352+
<summary>Full yaml examples (with the initial fields, will be updates as we agree on the final CRD format)</summary>
353+
354+
* 4.1 "overridable isolation"
355+
```yaml
356+
kind: NetworkTenancy
357+
spec:
358+
tenancyLabels:
359+
- "user"
360+
precedence: BANP
361+
action: Allow
362+
---
363+
kind: BaselineAdminNetworkPolicy
364+
spec:
365+
subject:
366+
namespaces:
367+
matchExpression:
368+
- key: user
369+
operator: Exists
370+
ingress:
371+
- action: Deny
372+
from:
373+
- namespaces: {}
374+
egress:
375+
- action: Deny
376+
to:
377+
- namespaces: {}
378+
```
379+
BANP can also be replaced with deny-all BANP
380+
```yaml
381+
kind: BaselineAdminNetworkPolicy
382+
spec:
383+
subject:
384+
namespaces: {}
385+
ingress:
386+
- action: Deny
387+
from:
388+
- namespaces: {}
389+
egress:
390+
- action: Deny
391+
to:
392+
- namespaces: {}
393+
```
394+
395+
* 4.2 strict isolation
396+
```yaml
397+
kind: NetworkTenancy
398+
spec:
399+
tenancyLabels:
400+
- "user"
401+
precedence: ANP
402+
action: Skip
403+
---
404+
kind: AdminNetworkPolicy
405+
spec:
406+
priority: 1
407+
subject:
408+
namespaces:
409+
matchExpression:
410+
- key: user
411+
operator: Exists
412+
ingress:
413+
- action: Deny
414+
from:
415+
- namespaces: {}
416+
egress:
417+
- action: Deny
418+
to:
419+
- namespaces: {}
420+
```
421+
422+
* 4.3 Allow internal connections for tenants
423+
```yaml
424+
kind: NetworkTenancy
425+
spec:
426+
tenancyLabels:
427+
- "user"
428+
precedence: ANP
429+
action: Allow
430+
---
431+
kind: BaselineAdminNetworkPolicy
432+
spec:
433+
subject:
434+
namespaces:
435+
matchExpression:
436+
- key: user
437+
operator: Exists
438+
ingress:
439+
- action: Deny
440+
from:
441+
- namespaces: {}
442+
egress:
443+
- action: Deny
444+
to:
445+
- namespaces: {}
446+
```
447+
448+
* 4.4 Tenants interaction with (B)ANP
449+
* 4.4.1 allow from monitoring + deny from not same tenant
450+
```yaml
451+
kind: NetworkTenancy
452+
spec:
453+
tenancyLabels:
454+
- "user"
455+
precedence: ANP
456+
action: Skip
457+
---
458+
kind: AdminNetworkPolicy
459+
spec:
460+
priority: 1
461+
subject:
462+
namespaces:
463+
matchExpression:
464+
- key: user
465+
operator: Exists
466+
ingress:
467+
- action: Allow
468+
from:
469+
- namespaces:
470+
namespaceSelector:
471+
matchLabels:
472+
kubernetes.io/metadata.name: monitoring-ns
473+
- action: Deny
474+
from:
475+
- namespaces: {}
476+
```
477+
* 4.4.2 allow from same tenant + BANP deny all
478+
```yaml
479+
kind: NetworkTenancy
480+
spec:
481+
tenancyLabels:
482+
- "user"
483+
precedence: ANP
484+
action: Allow
485+
---
486+
kind: BaselineAdminNetworkPolicy
487+
spec:
488+
subject:
489+
namespaces:
490+
matchExpression:
491+
- key: user
492+
operator: Exists
493+
ingress:
494+
- action: Deny
495+
from:
496+
- namespaces: {}
497+
```
498+
</details>
162499

163500
## Conformance Details
164501

0 commit comments

Comments
 (0)