# Enforce rules with a ValidatingAdmissionPolicy

> Roll out a CEL admission policy safely: warn first, scope it to production namespaces, then deny Deployments that break the rules.

Level: Advanced · Topic: Security · About 12 minutes
Try it in the browser: https://k8wiz.com/playground/enforce-rules-with-a-validatingadmissionpolicy

The playground is a simulated Kubernetes cluster that runs in the browser. kubectl output and errors follow the real ones.

## The situation

Production Deployments must pin their image tags and run at most 5 replicas. `policy.yaml` has a ValidatingAdmissionPolicy for that, checked by the API server with CEL, no webhook to run.

Its binding only warns for now, and it applies to every namespace. The `dev` namespace runs `nginx:latest` on purpose and must keep working.

Apply it, see what it warns about, limit it to namespaces labelled `env=prod`, then make it deny.

## Objectives

1. Apply the policy and see it warn (Change a Deployment, for example `kubectl scale deployment tools -n dev --replicas=2`)
2. The binding only covers namespaces labelled env=prod
3. The binding denies, not just warns
4. A :latest image is rejected in prod (Try `kubectl set image deployment/web -n prod nginx=nginx:latest`)
5. dev and prod keep running

## Hints

1. `kubectl apply -f policy.yaml`, then change any Deployment: the API server answers with `Warning: Validation failed for ValidatingAdmissionPolicy ...`.
2. The binding's `matchResources.namespaceSelector` limits where it applies: `matchLabels: {env: prod}`.
3. `validationActions: [Deny]` rejects the request. Deny and Warn can't be used together, since Deny already returns the message.
4. kubectl patch validatingadmissionpolicybinding prod-deployments --type=merge -p '{"spec":{"validationActions":["Deny"],"matchResources":{"namespaceSelector":{"matchLabels":{"env":"prod"}}}}}'

## Solution

```bash
kubectl apply -f policy.yaml
```
```bash
kubectl scale deployment tools -n dev --replicas=2
```
```bash
kubectl patch validatingadmissionpolicybinding prod-deployments --type=merge -p '{"spec":{"validationActions":["Deny"],"matchResources":{"namespaceSelector":{"matchLabels":{"env":"prod"}}}}}'
```
```bash
kubectl set image deployment/web -n prod nginx=nginx:latest
```
```bash
kubectl scale deployment tools -n dev --replicas=1
```

## What it teaches

- A ValidatingAdmissionPolicy holds the rules in CEL; a binding decides where they apply and what happens when one fails: `Deny`, `Warn` or `Audit`.
- Start with `Warn` (or `Audit`) to see what would break, then switch to `Deny`.
- Policies only check requests. A Deployment that already breaks a rule keeps running until someone changes it.
- An image with no tag at all also means `:latest`, which this expression misses. Test rules against the cases you care about, as you would code.
