Skip to content

Commit bd8c86e

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

File tree

1 file changed

+331
-2
lines changed

1 file changed

+331
-2
lines changed

npeps/npep-122.md

Lines changed: 331 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,336 @@ 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`. To only select namespaces with existing labels extra `key: X, operator: Exists` condition should
174+
be added to the selector.
175+
176+
```yaml
177+
kind: NetworkTenancy
178+
spec:
179+
matchExpression:
180+
- key: system-namespace
181+
operator: DoesNotExist
182+
- key: user
183+
operator: Exists
184+
tenancyLabels:
185+
- user
186+
```
187+
188+
2. Overload `tenancyLabels` and implicitly apply tenancy rules only to namespaces where `tenancyLabels` are present.
189+
190+
**Cons**: applying all labels from `tenancyLabels` to a namespaces automatically makes it affected by tenancy.
191+
No way to make sure ALL namespaces in a cluster are a part of some tenant, e.g. newly created namespace will not
192+
be limited/protected by Tenancy rules until it gets `tenancyLabels` assigned, may potentially be a security problem.
193+
194+
Example: by setting deny-from-other-tenants I want to ensure only namespaces with the same label `security-zone` value
195+
can send incoming connections. That policy will be violated if a new tenant is created without `security-zone` label,
196+
meaning it is not a part of any Tenant. This may potentially be solved by using allow-from-same-tenant + deny ALL
197+
ANP, but it is stricter, since it affects all incoming connections, not just from other pods.
198+
199+
```yaml
200+
kind: NetworkTenancy
201+
spec:
202+
tenancyLabels:
203+
- user
204+
```
205+
206+
### Peers and actions
207+
208+
Based on the existing User Stories, Tenancy only needs Allow and Deny actions, and the only 2 types of peers are
209+
`SameTenant` and `NotSameTenant`.
210+
211+
Therefore, Tenancy rules will look something like:
212+
213+
```yaml
214+
kind: NetworkTenancy
215+
spec:
216+
tenancyLabels: ['label1']
217+
ingress:
218+
- actions: Deny
219+
from: NotSameTenant
220+
- actions: Allow
221+
from: SameTenant
222+
egress:
223+
- actions: Deny
224+
to: NotSameTenant
225+
```
226+
227+
### Priorities
228+
229+
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:
230+
231+
1. Reuse ANP and BANP to define priority, link Tenancy API
232+
233+
```yaml
234+
kind: AdminNetworkPolicy
235+
spec:
236+
priority: 10
237+
# EITHER
238+
subject: <...>
239+
ingress: <...>
240+
egress: <...>
241+
# OR
242+
tenant: <tenant reference>
243+
```
244+
245+
```yaml
246+
kind: BaselineAdminNetworkPolicy
247+
spec:
248+
# EITHER
249+
subject: <...>
250+
ingress: <...>
251+
egress: <...>
252+
# OR
253+
tenant: <tenant reference>
254+
```
255+
256+
We may want to allow either `subject`+`ingress`/`egress` or `tenant`, since having both at the same priority
257+
is confusing (`tenancyLabels` and `subject` may select unrelated sets of pods) and may result in conflicting rules.
258+
259+
2. Create 2 objects with ANP and BANP priorities (let's say Tenancy and BaselineTenancy)
260+
261+
```yaml
262+
kind: NetworkTenancy
263+
spec:
264+
priority: 10
265+
ingress:
266+
- actions: Deny
267+
from: NotSameTenant
268+
- actions: Allow
269+
from: SameTenant
270+
egress:
271+
- actions: Deny
272+
to: NotSameTenant
273+
```
274+
275+
```yaml
276+
kind: BaselineNetworkTenancy
277+
spec:
278+
ingress:
279+
- actions: Deny
280+
from: NotSameTenant
281+
- actions: Allow
282+
from: SameTenant
283+
egress:
284+
- actions: Deny
285+
to: NotSameTenant
286+
```
287+
288+
While multiple ANPs with the same priority are allowed, we probably can allow multiple Tenancies or Tenancy and ANP
289+
with the same priority, but if we decide to only allow ANP per priority, Tenancy needs to be accounted for in the same range.
290+
291+
3. Create 1 object with extra `baselinePolicy` field or IntOrString value for priority.
292+
293+
```yaml
294+
kind: NetworkTenancy
295+
spec:
296+
baselinePolicy: false
297+
priority: 10
298+
ingress:
299+
- actions: Deny
300+
from: NotSameTenant
301+
- actions: Allow
302+
from: SameTenant
303+
egress:
304+
- actions: Deny
305+
to: NotSameTenant
306+
```
307+
308+
```yaml
309+
kind: NetworkTenancy
310+
spec:
311+
priority: baseline
312+
ingress:
313+
- actions: Deny
314+
from: NotSameTenant
315+
- actions: Allow
316+
from: SameTenant
317+
egress:
318+
- actions: Deny
319+
to: NotSameTenant
320+
```
321+
322+
### Another approach
323+
324+
There are 4 (6 if we consider Skip as an action, which I will do for now, but we can remove it later if we consider it
325+
unnecessary) option for tenancy rules: `SameTenant: Allow/Skip/Deny`, `NotSameTenant: Allow/Skip/Deny`.
326+
From the user stories (and common sense) looks like the only useful combinations are `SameTenant: Allow/Skip` and `NotSameTenant: Deny`.
327+
We can always replace `NotSameTenant: Deny` with Tenancy using `SameTenant: Allow/Skip` with higher priority
328+
and (B)ANP `Deny` policy for the same tenancy selector (or maybe even wider selector, e.g. all user pods).
329+
This helps focus on which policy is defined inside one tenant, and then "everything else"/"other tenants"/etc
330+
may be defined with existing CRDs.
331+
332+
In this case, we only need to define tenancy for the same tenant (which seems to be easier to understand).
333+
Tenancy itself only needs a set of `tenancyLabels` and one of the `Allow` or `Skip` actions in every direction.
334+
335+
If we consider tenancy to be always the highest-priority rule on ANP or BANP level, we could add one more field
336+
`precedence: ANP/BANP` to define at which precedence it should be evaluated (for BANP `Skip` and `Allow` actions
337+
actually mean the same, we can only allow value for it)
338+
339+
**Note** we could also have `Allow/Skip/DefaultAllow` actions without `precedence` filed, but I am still not sure if
340+
I like implying rule priority from the action.
341+
342+
we can express existing user stories as follows:
343+
344+
* 4.1 "overridable isolation"
345+
```yaml
346+
kind: NetworkTenancy
347+
spec:
348+
tenancyLabels:
349+
- "user"
350+
precedence: BANP
351+
ingress: Allow
352+
egress: Allow
353+
---
354+
kind: BaselineAdminNetworkPolicy
355+
spec:
356+
subject:
357+
namespaces:
358+
matchExpression:
359+
- key: user
360+
operator: Exists
361+
ingress:
362+
- action: Deny
363+
from:
364+
- namespaces: {}
365+
egress:
366+
- action: Deny
367+
to:
368+
- namespaces: {}
369+
```
370+
371+
* 4.2 strict isolation
372+
```yaml
373+
kind: NetworkTenancy
374+
spec:
375+
tenancyLabels:
376+
- "user"
377+
precedence: ANP
378+
ingress: Skip
379+
egress: Skip
380+
---
381+
kind: AdminNetworkPolicy
382+
spec:
383+
priority: 1
384+
subject:
385+
namespaces:
386+
matchExpression:
387+
- key: user
388+
operator: Exists
389+
ingress:
390+
- action: Deny
391+
from:
392+
- namespaces: {}
393+
egress:
394+
- action: Deny
395+
to:
396+
- namespaces: {}
397+
```
398+
399+
* 4.3 Allow internal connections for tenants
400+
```yaml
401+
kind: NetworkTenancy
402+
spec:
403+
tenancyLabels:
404+
- "user"
405+
precedence: ANP
406+
ingress: Allow
407+
egress: Allow
408+
---
409+
kind: BaselineAdminNetworkPolicy
410+
spec:
411+
subject:
412+
namespaces:
413+
matchExpression:
414+
- key: user
415+
operator: Exists
416+
ingress:
417+
- action: Deny
418+
from:
419+
- namespaces: {}
420+
egress:
421+
- action: Deny
422+
to:
423+
- namespaces: {}
424+
```
425+
426+
* 4.4 Tenants interaction with (B)ANP
427+
* 4.4.1 allow from monitoring + deny from not same tenant
428+
```yaml
429+
kind: NetworkTenancy
430+
spec:
431+
tenancyLabels:
432+
- "user"
433+
precedence: ANP
434+
ingress: Skip
435+
egress: Skip
436+
---
437+
kind: AdminNetworkPolicy
438+
spec:
439+
priority: 1
440+
subject:
441+
namespaces:
442+
matchExpression:
443+
- key: user
444+
operator: Exists
445+
ingress:
446+
- action: Allow
447+
from:
448+
- namespaces:
449+
namespaceSelector:
450+
matchLabels:
451+
kubernetes.io/metadata.name: monitoring-ns
452+
- action: Deny
453+
from:
454+
- namespaces: {}
455+
```
456+
* 4.4.2 allow from same tenant + BANP deny all
457+
```yaml
458+
kind: NetworkTenancy
459+
spec:
460+
tenancyLabels:
461+
- "user"
462+
precedence: ANP
463+
ingress: Allow
464+
---
465+
kind: BaselineAdminNetworkPolicy
466+
spec:
467+
subject:
468+
namespaces:
469+
matchExpression:
470+
- key: user
471+
operator: Exists
472+
ingress:
473+
- action: Deny
474+
from:
475+
- namespaces: {}
476+
```
477+
478+
This simplifies the tenancy to only define sameTenant rules, and you basically only have 3 options for every direction:
479+
strictly allow connections inside one tenant; delegate network policy inside one tenant to namespaces; .
480+
And the new object will be
481+
482+
```yaml
483+
kind: NetworkTenancy
484+
spec:
485+
tenancyLabels:
486+
- "user"
487+
precedence: ANP/BANP
488+
ingress: Allow/Skip
489+
egress: Allow/Skip
490+
```
162491

163492
## Conformance Details
164493

0 commit comments

Comments
 (0)