Skip to content

Commit 95a09f3

Browse files
MariamFahmy98realshutingchipzoller
authored
add docs for exception enhancements (#1157)
* add docs for exception enhancements Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com> * Update content/en/docs/Writing policies/exceptions.md Co-authored-by: Chip Zoller <chipzoller@gmail.com> Signed-off-by: shuting <shuting@nirmata.com> * Update content/en/docs/Writing policies/exceptions.md Co-authored-by: Chip Zoller <chipzoller@gmail.com> Signed-off-by: shuting <shuting@nirmata.com> * fix: add the usecase of service mesh Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com> * fix Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com> * Update content/en/docs/Writing policies/exceptions.md Signed-off-by: Chip Zoller <chipzoller@gmail.com> --------- Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com> Signed-off-by: shuting <shuting@nirmata.com> Signed-off-by: Chip Zoller <chipzoller@gmail.com> Co-authored-by: shuting <shuting@nirmata.com> Co-authored-by: Chip Zoller <chipzoller@gmail.com>
1 parent 2103550 commit 95a09f3

File tree

1 file changed

+246
-2
lines changed

1 file changed

+246
-2
lines changed

content/en/docs/Writing policies/exceptions.md

+246-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ weight: 80
66
---
77

88
{{% alert title="Warning" color="warning" %}}
9-
Policy exceptions are a **beta** feature and requires setting certain container flags to enable. It is not ready for production usage and there may be breaking changes. Normal semantic versioning and compatibility rules will not apply.
9+
Policy exceptions are a **beta** feature. Normal semantic versioning and compatibility rules will not apply.
1010
{{% /alert %}}
1111

1212
Although Kyverno policies contain multiple methods to provide fine-grained control as to which resources they act upon in the form of [`match`/`exclude` blocks](/docs/writing-policies/match-exclude/#match-statements), [preconditions](/docs/writing-policies/preconditions/) at multiple hierarchies, [anchors](/docs/writing-policies/validate/#anchors), and more, all these mechanisms have in common that the resources which they are intended to exclude must occur in the same rule definition. This may be limiting in situations where policies may not be directly editable, or doing so imposes an operational burden.
@@ -15,7 +15,7 @@ For example, in organizations where multiple teams must interact with the same c
1515

1616
Imagine a validate policy exists in `Enforce` mode which mandates all Pods must not mount host namespaces. A separate team has a legitimate need to run a specific tool in this cluster for a limited time which violates this policy. Normally, the policy would block such a "bad" Pod if the policy was not previously altered in such a way to allow said Pod to run. Rather than making adjustments to the policy, an exception may be granted. Both of these examples are use cases for a **PolicyException** resource described below.
1717

18-
A `PolicyException` is a Namespaced Custom Resource which allows a resource(s) to be allowed past a given policy and rule combination. It can be used to exempt any resource from any Kyverno rule type although it is primarily intended for use with validate rules. A PolicyException encapsulates the familiar `match`/`exclude` statements used in `Policy` and `ClusterPolicy` resources but adds an `exceptions{}` object to select the policy and rule name(s) used to form the exception. The logical flow of how a PolicyException works in tandem with a validate policy is depicted below.
18+
A `PolicyException` is a Namespaced Custom Resource which allows a resource(s) to be allowed past a given policy and rule combination. It can be used to exempt any resource from any Kyverno rule type although it is primarily intended for use with validate rules. A PolicyException encapsulates the familiar `match`/`exclude` statements used in `Policy` and `ClusterPolicy` resources but adds an `exceptions{}` object to select the policy and rule name(s) used to form the exception. A `conditions{}` block (optional) uses common expressions similar to those found in [preconditions](/docs/writing-policies/preconditions/) and [deny rules](/docs/writing-policies/validate/#deny-rules) to query the contents of the selected resources in order to refine the selection process. The logical flow of how a PolicyException works in tandem with a validate policy is depicted below.
1919

2020
```mermaid
2121
graph TD
@@ -84,6 +84,11 @@ spec:
8484
- delta
8585
names:
8686
- important-tool*
87+
conditions:
88+
any:
89+
- key: "{{ request.object.metadata.labels.app || '' }}"
90+
operator: Equals
91+
value: busybox
8792
```
8893

8994
A Deployment matching the characteristics defined in the PolicyException, shown below, will be allowed creation even though it technically violates the rule's definition.
@@ -166,3 +171,242 @@ spec:
166171
- resources:
167172
names: "?*"
168173
```
174+
175+
## Pod Security Exemptions
176+
177+
Kyverno policies can be used to apply Pod Security Standards profiles and controls via the [validate.podSecurity](/docs/writing-policies/validate/#pod-security) subrule. However, there are cases where certain Pods need to be exempted from these policies. For example, a Pod may need to run as `root` or require privileged access. In such cases, a PolicyException can be used to define an exemption for the Pod through the `podSecurity{}` block. It can be used to define controls that are exempted from the policy.
178+
179+
Given the following policy that enforces the latest version of the Pod Security Standards restricted profile in a single rule across the entire cluster.
180+
181+
```yaml
182+
apiVersion: kyverno.io/v1
183+
kind: ClusterPolicy
184+
metadata:
185+
name: psa
186+
spec:
187+
background: true
188+
validationFailureAction: Enforce
189+
rules:
190+
- name: restricted
191+
match:
192+
any:
193+
- resources:
194+
kinds:
195+
- Pod
196+
validate:
197+
podSecurity:
198+
level: restricted
199+
version: latest
200+
```
201+
202+
In this use case, all Pods in the `delta` Namespace need to run as a root. A PolicyException can be used to exempt all Pods whose Namespace is `delta` from the policy by excluding the `runAsNonRoot` control.
203+
204+
```yaml
205+
apiVersion: kyverno.io/v2beta1
206+
kind: PolicyException
207+
metadata:
208+
name: pod-security-exception
209+
namespace: policy-exception-ns
210+
spec:
211+
exceptions:
212+
- policyName: psa
213+
ruleNames:
214+
- restricted
215+
match:
216+
any:
217+
- resources:
218+
namespaces:
219+
- delta
220+
podSecurity:
221+
- controlName: "Running as Non-root"
222+
```
223+
224+
The following Pod satisfies all controls in the restricted profile except the `Running as Non-root` control but it matches the exception. Hence, it will be successfully created.
225+
226+
```yaml
227+
apiVersion: v1
228+
kind: Pod
229+
metadata:
230+
name: nginx-pod
231+
namespace: delta
232+
spec:
233+
containers:
234+
- name: nginx
235+
image: nginx
236+
args:
237+
- sleep
238+
- 1d
239+
securityContext:
240+
seccompProfile:
241+
type: RuntimeDefault
242+
runAsNonRoot: false
243+
allowPrivilegeEscalation: false
244+
capabilities:
245+
drop:
246+
- ALL
247+
```
248+
249+
PolicyExceptions `podSecurity{}` block has the same functionality as the [validate.podSecurity.exclude](/docs/writing-policies/validate/#exemptions) block in the policy itself. They can be used to exempt controls that can only be defined in the container level fields.
250+
251+
For example, the following PolicyException exempts the containers running either the `nginx` or `redis` image from following the Capabilities control.
252+
253+
```yaml
254+
apiVersion: kyverno.io/v2beta1
255+
kind: PolicyException
256+
metadata:
257+
name: pod-security-exception
258+
namespace: policy-exception-ns
259+
spec:
260+
exceptions:
261+
- policyName: psa
262+
ruleNames:
263+
- restricted
264+
match:
265+
any:
266+
- resources:
267+
namespaces:
268+
- delta
269+
podSecurity:
270+
- controlName: Capabilities
271+
images:
272+
- nginx*
273+
- redis*
274+
```
275+
276+
There might be a case where it is required to have specific values for the controls in the PodSecurity profile. In such cases, the `podSecurity.restrictedField` field can be used to define these values for the controls that are exempted from the policy.
277+
278+
For example, service meshes like Istio and Linkerd employ an `initContainer` that requires some privileges which are very often problematic in security-conscious clusters. Minimally, these initContainers must add two [Linux capabilities](https://man7.org/linux/man-pages/man7/capabilities.7.html) which allow them to make modifications to the networking stack: `NET_ADMIN` and `NET_RAW`. These initContainers may go even further by running as a root user, something which is a big no-no in the world of containers.
279+
280+
In this case, the `podSecurity.restrictedField` can be used to enforce the entire baseline profile of the Pod Security Standards but only exclude Istio’s and Linkerd’s images from specifically the initContainers list.
281+
282+
The following PolicyException grants an exemption to the `initContainers` that use istio or linkerd images, allowing them to bypass the `Capabilities` control. This is achieved by permitting the values of `NET_ADMIN` and `NET_RAW` in the `securityContext.capabilities.add` field.
283+
284+
```yaml
285+
apiVersion: kyverno.io/v2beta1
286+
kind: PolicyException
287+
metadata:
288+
name: pod-security-exception
289+
namespace: policy-exception-ns
290+
spec:
291+
exceptions:
292+
- policyName: psa
293+
ruleNames:
294+
- baseline
295+
match:
296+
any:
297+
- resources:
298+
kinds:
299+
- Pod
300+
podSecurity:
301+
- controlName: Capabilities
302+
images:
303+
- "*/istio/proxyv2*"
304+
- "*/linkerd/proxy-init*"
305+
restrictedField: spec.initContainers[*].securityContext.capabilities.add
306+
values:
307+
- NET_ADMIN
308+
- NET_RAW
309+
```
310+
311+
The following Pod meets all requirements outlined in the baseline profile, except the `Capabilities` control in the `initContainer`. However, it matches the exception that permits the configuration of `spec.initContainers[*].securityContext.capabilities.add` to include `NET_ADMIN` and `NET_RAW`. Hence, it will be successfully created.
312+
313+
```yaml
314+
apiVersion: v1
315+
kind: Pod
316+
metadata:
317+
name: istio-pod
318+
spec:
319+
initContainers:
320+
- name: istio-init
321+
image: docker.io/istio/proxyv2:1.20.2
322+
args:
323+
- istio-iptables
324+
- -p
325+
- "15001"
326+
- -z
327+
- "15006"
328+
- -u
329+
- "1337"
330+
- -m
331+
- REDIRECT
332+
- -i
333+
- '*'
334+
- -x
335+
- ""
336+
- -b
337+
- '*'
338+
- -d
339+
- 15090,15021,15020
340+
- --log_output_level=default:info
341+
securityContext:
342+
allowPrivilegeEscalation: false
343+
capabilities:
344+
add:
345+
- NET_ADMIN
346+
- NET_RAW
347+
drop:
348+
- ALL
349+
privileged: false
350+
readOnlyRootFilesystem: false
351+
runAsGroup: 0
352+
runAsNonRoot: false
353+
runAsUser: 0
354+
containers:
355+
- name: busybox
356+
image: busybox:1.35
357+
args:
358+
- sleep
359+
- infinity
360+
```
361+
362+
The following Pod meets all requirements outlined in the baseline profile, except the `Capabilities` control in the `initContainer` and it matches the exception but it sets the `spec.initContainers[*].securityContext.capabilities.add` to `SYS_ADMIN` which isn't an allowed value. Hence, it will be rejected.
363+
364+
```yaml
365+
apiVersion: v1
366+
kind: Pod
367+
metadata:
368+
name: istio-pod
369+
spec:
370+
initContainers:
371+
- name: istio-init
372+
image: docker.io/istio/proxyv2:1.20.2
373+
args:
374+
- istio-iptables
375+
- -p
376+
- "15001"
377+
- -z
378+
- "15006"
379+
- -u
380+
- "1337"
381+
- -m
382+
- REDIRECT
383+
- -i
384+
- '*'
385+
- -x
386+
- ""
387+
- -b
388+
- '*'
389+
- -d
390+
- 15090,15021,15020
391+
- --log_output_level=default:info
392+
securityContext:
393+
allowPrivilegeEscalation: false
394+
capabilities:
395+
add:
396+
- NET_ADMIN
397+
- NET_RAW
398+
- SYS_ADMIN
399+
drop:
400+
- ALL
401+
privileged: false
402+
readOnlyRootFilesystem: false
403+
runAsGroup: 0
404+
runAsNonRoot: false
405+
runAsUser: 0
406+
containers:
407+
- name: busybox
408+
image: busybox:1.35
409+
args:
410+
- sleep
411+
- infinity
412+
```

0 commit comments

Comments
 (0)