Skip to content

Commit 7e1da17

Browse files
committed
address comments and monitoring section.
1 parent 5903e11 commit 7e1da17

File tree

1 file changed

+80
-13
lines changed
  • content/en/blog/_posts/2024-04-24-validating-admission-policy-ga

1 file changed

+80
-13
lines changed

content/en/blog/_posts/2024-04-01-validating-admission-policy-ga/index.md renamed to content/en/blog/_posts/2024-04-24-validating-admission-policy-ga/index.md

Lines changed: 80 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,21 @@
22
layout: blog
33
title: "Kubernetes 1.30: Validating Admission Policy Is Generally Available"
44
slug: validating-admission-policy-ga
5-
date: 2024-04-01
6-
canonicalUrl: https://www.k8s.dev/blog/2024/04/01/validating-admission-policy/
5+
date: 2024-04-24
76
---
87

98
**Author:** Jiahui Feng (Google)
109

11-
We are excited to announce that Validating Admission Policy has reached its General Availability
10+
On behalf of the Kubernetes project, I am excited to announce that ValidatingAdmissionPolicy has reached
11+
**general availability**
1212
as part of Kubernetes 1.30 release. If you have not yet read about this new declarative alternative to
1313
validating admission webhooks, it may be interesting to read our
1414
[previous post](/blog/2022/12/20/validating-admission-policies-alpha/) about the new feature.
1515
If you have already heard about Validating Admission Policy and you are eager to try it out, there is no better time to do it now.
1616

1717
Let's have a taste of Validating Admission Policy by replacing a simple webhook.
1818

19-
# The Webhook
19+
## Example admission webhook
2020
First, let's take a look at an example of a simple webhook. Here is an excerpt from a webhook that
2121
enforce `runAsNonRoot`, `readOnlyRootFilesystem`, `allowPrivilegeEscalation`, and `privileged` to be set to the least permissive values.
2222

@@ -47,10 +47,9 @@ func verifyDeployment(deploy *appsv1.Deployment) error {
4747
}
4848
```
4949

50-
Check out [the doc](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#what-are-admission-webhooks)
51-
for a refresher on how admission webhooks work. Or, see the [full code](https://gist.github.com/jiahuif/2653f2ce41fe6a2e5739ea7cd76b182b) of this webhook to follow along this walkthrough.
50+
Check out [What are admission webhooks?](/docs/reference/access-authn-authz/extensible-admission-controllers/#what-are-admission-webhooks) Or, see the [full code](https://gist.github.com/jiahuif/2653f2ce41fe6a2e5739ea7cd76b182b) of this webhook to follow along this walkthrough.
5251

53-
# The Policy
52+
## The policy
5453
Now let's try to recreate the validation faithfully with a ValidatingAdmissionPolicy.
5554
```yaml
5655
apiVersion: admissionregistration.k8s.io/v1
@@ -127,8 +126,9 @@ Next, let's create a namespace for our tests.
127126
```shell
128127
kubectl create namespace policy-test
129128
```
130-
Then, bind the policy to the namespace. But at this point, we set the action to `Warn`
131-
so that the policy prints out warnings instead of rejecting the requests.
129+
Then, I bind the policy to the namespace. But at this point, I set the action to `Warn`
130+
so that the policy prints out [warnings](/blog/2020/09/03/warnings/) instead of rejecting the requests.
131+
This is especially useful to collect results from all expressions during development and automated testing.
132132
```yaml
133133
apiVersion: admissionregistration.k8s.io/v1
134134
kind: ValidatingAdmissionPolicyBinding
@@ -178,12 +178,12 @@ Error from server: error when creating "STDIN": admission webhook "webhook.examp
178178
Looks great! The policy and the webhook give equivalent results.
179179
After a few other cases, when we are confident with our policy, maybe it is time to do some cleanup.
180180

181-
- For every expression, we repeat access to `object.spec.template.spec.containers` and each `securityContext` in every expression;
181+
- For every expression, we repeat access to `object.spec.template.spec.containers` and to each `securityContext`;
182182
- There is a pattern of checking presence of a field and then accessing it, which looks a bit verbose.
183183

184-
Fortunately, with the release of Kubernetes 1.28, we have new solutions for both issues.
184+
Fortunately, since Kubernetes 1.28, we have new solutions for both issues.
185185
Variable Composition allows us to extract repeated sub-expressions into their own variables.
186-
CEL library has also added support for [optionals](https://github.com/google/cel-spec/wiki/proposal-246), which are excellent to work with fields that are, well, optional.
186+
Kubernetes enables [the optional library](https://github.com/google/cel-spec/wiki/proposal-246) for CEL, which are excellent to work with fields that are, you guessed it, optional.
187187

188188
With both features in mind, let's refactor the policy a bit.
189189
```yaml
@@ -213,4 +213,71 @@ spec:
213213
message: 'all containers must NOT set allowPrivilegeEscalation to true'
214214
- expression: variables.securityContexts.all(c, c.?privileged != optional.of(true))
215215
message: 'all containers must NOT set privileged to true'
216-
```
216+
```
217+
The policy is now much cleaner and more readable. Update the policy, and you should see
218+
it function the same as before.
219+
220+
Now let's change the policy binding from warning to actually denying requests that fail validation.
221+
```yaml
222+
apiVersion: admissionregistration.k8s.io/v1
223+
kind: ValidatingAdmissionPolicyBinding
224+
metadata:
225+
name: "pod-security.policy-binding.example.com"
226+
spec:
227+
policyName: "pod-security.policy.example.com"
228+
validationActions: ["Deny"]
229+
matchResources:
230+
namespaceSelector:
231+
matchLabels:
232+
"kubernetes.io/metadata.name": "policy-test"
233+
```
234+
And finally, remove the webhook. Now the result should include only messages from
235+
the policy.
236+
```shell
237+
kubectl create -n policy-test -f- <<EOF
238+
apiVersion: apps/v1
239+
kind: Deployment
240+
metadata:
241+
labels:
242+
app: nginx
243+
name: nginx
244+
spec:
245+
selector:
246+
matchLabels:
247+
app: nginx
248+
template:
249+
metadata:
250+
labels:
251+
app: nginx
252+
spec:
253+
containers:
254+
- image: nginx
255+
name: nginx
256+
securityContext:
257+
privileged: true
258+
allowPrivilegeEscalation: true
259+
EOF
260+
```
261+
```text
262+
The deployments "nginx" is invalid: : ValidatingAdmissionPolicy 'pod-security.policy.example.com' with binding 'pod-security.policy-binding.example.com' denied request: all containers must set runAsNonRoot to true
263+
```
264+
Please notice that, by design, the policy will stop evaluation after the first expression that causes the request to be denied.
265+
This is different from what happens when the expressions generate only warnings.
266+
267+
## Set up monitoring
268+
Unlike a webhook, a policy is not a dedicated process that can expose its own metrics.
269+
Instead, you can use metrics from the API server in their place.
270+
271+
Here are some examples in Prometheus Query Language of common monitoring tasks.
272+
273+
To find the 95th percentile execution duration of the policy shown above.
274+
```text
275+
histogram_quantile(0.95, sum(rate(apiserver_validating_admission_policy_check_duration_seconds_bucket{policy="pod-security.policy.example.com"}[5m])) by (le))
276+
```
277+
278+
To find the rate of the policy evaluation.
279+
```text
280+
rate(apiserver_validating_admission_policy_check_total{policy="pod-security.policy.example.com"}[5m])
281+
```
282+
283+
You can read [the metrics reference](/docs/reference/instrumentation/metrics/) to learn more about the metrics above.

0 commit comments

Comments
 (0)