Skip to content

Commit fc21030

Browse files
cmyuiclaude
andcommitted
Add Kyverno policy engine configuration
Adds declarative Kyverno setup with four security/best-practice policies: - restrict-image-registries: Block images from unapproved registries (Enforce) - require-resource-limits: Block pods without resource limits (Enforce) - disallow-privileged-containers: Block privileged containers (Enforce) - require-probes: Block web services without readiness probes (Enforce) Exclusions for legitimate cases: - System namespaces (kube-system, kyverno, kube-flannel, grafana) - CronJob pods (short-lived) - Background workers (discord bots, pubsub daemons, amqp processors) Includes Helm values for minimal resource footprint on small clusters. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent ab26ee3 commit fc21030

File tree

6 files changed

+336
-0
lines changed

6 files changed

+336
-0
lines changed

k8s/kyverno/README.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Kyverno
2+
3+
Policy engine for Kubernetes that validates, mutates, and generates resources.
4+
5+
## Installation
6+
7+
```bash
8+
# Add Helm repo
9+
helm repo add kyverno https://kyverno.github.io/kyverno/
10+
helm repo update kyverno
11+
12+
# Install Kyverno
13+
helm install kyverno kyverno/kyverno \
14+
-n kyverno \
15+
--create-namespace \
16+
-f values.yaml \
17+
--wait
18+
19+
# Apply policies
20+
kubectl apply -f policies/
21+
```
22+
23+
## Upgrade
24+
25+
```bash
26+
helm repo update kyverno
27+
helm upgrade kyverno kyverno/kyverno \
28+
-n kyverno \
29+
-f values.yaml \
30+
--wait
31+
```
32+
33+
## Uninstall
34+
35+
```bash
36+
kubectl delete -f policies/
37+
helm uninstall kyverno -n kyverno
38+
kubectl delete ns kyverno
39+
```
40+
41+
## Policies
42+
43+
| Policy | Mode | Description |
44+
|--------|------|-------------|
45+
| `restrict-image-registries` | Enforce | Only allow images from approved registries |
46+
| `require-resource-limits` | Enforce | Block pods without resource limits |
47+
| `disallow-privileged-containers` | Enforce | Block privileged containers |
48+
| `require-probes` | Enforce | Block web services without readiness probes |
49+
50+
### Exclusions
51+
52+
The following are excluded from resource limits and probe requirements:
53+
- System namespaces: `kube-system`, `kyverno`, `kube-flannel`, `grafana`
54+
- CronJob pods (identified by `job-name` label)
55+
- GitHub runner namespace
56+
- Background workers: `*-discord-bot-*`, `*-pubsub-daemon-*`, `*-amqp-processor-*`, `*-processor-production-*`
57+
58+
## Checking Policy Violations
59+
60+
```bash
61+
# View policy reports
62+
kubectl get policyreport -A
63+
64+
# View cluster-wide policy reports
65+
kubectl get clusterpolicyreport
66+
67+
# Describe a specific report for details
68+
kubectl describe policyreport -n default
69+
```
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
apiVersion: kyverno.io/v1
2+
kind: ClusterPolicy
3+
metadata:
4+
name: disallow-privileged-containers
5+
annotations:
6+
policies.kyverno.io/title: Disallow Privileged Containers
7+
policies.kyverno.io/category: Security
8+
policies.kyverno.io/description: >-
9+
Privileged containers have full access to the host and should
10+
be blocked except for specific system workloads.
11+
spec:
12+
validationFailureAction: Enforce
13+
background: true
14+
rules:
15+
- name: disallow-privileged
16+
match:
17+
any:
18+
- resources:
19+
kinds:
20+
- Pod
21+
exclude:
22+
any:
23+
- resources:
24+
namespaces:
25+
- kube-system
26+
- kube-flannel
27+
- resources:
28+
namespaces:
29+
- github-runner
30+
names:
31+
- "github-runner-*"
32+
validate:
33+
message: "Privileged containers are not allowed."
34+
pattern:
35+
spec:
36+
containers:
37+
- =(securityContext):
38+
=(privileged): false
39+
=(initContainers):
40+
- =(securityContext):
41+
=(privileged): false
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
apiVersion: kyverno.io/v1
2+
kind: ClusterPolicy
3+
metadata:
4+
name: require-probes
5+
annotations:
6+
policies.kyverno.io/title: Require Probes
7+
policies.kyverno.io/category: Best Practices
8+
policies.kyverno.io/description: >-
9+
Containers should have readiness and liveness probes defined
10+
to ensure proper health checking and traffic management.
11+
spec:
12+
validationFailureAction: Enforce
13+
background: true
14+
rules:
15+
- name: validate-probes
16+
match:
17+
any:
18+
- resources:
19+
kinds:
20+
- Pod
21+
exclude:
22+
any:
23+
- resources:
24+
namespaces:
25+
- kube-system
26+
- kyverno
27+
- kube-flannel
28+
- github-runner
29+
- grafana
30+
# Exclude CronJob pods (they run to completion)
31+
- resources:
32+
selector:
33+
matchExpressions:
34+
- key: job-name
35+
operator: Exists
36+
preconditions:
37+
all:
38+
# Only require probes for services (pods with app label ending in -api or -production that are NOT background workers)
39+
- key: "{{ request.object.metadata.name }}"
40+
operator: AnyNotIn
41+
value:
42+
- "*-discord-bot-*"
43+
- "*-pubsub-daemon-*"
44+
- "*-amqp-processor-*"
45+
- "*-processor-production-*"
46+
validate:
47+
message: "Web service containers must have readinessProbe defined."
48+
pattern:
49+
spec:
50+
containers:
51+
- readinessProbe:
52+
periodSeconds: ">0"
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
apiVersion: kyverno.io/v1
2+
kind: ClusterPolicy
3+
metadata:
4+
name: require-resource-limits
5+
annotations:
6+
policies.kyverno.io/title: Require Resource Limits
7+
policies.kyverno.io/category: Best Practices
8+
policies.kyverno.io/description: >-
9+
Containers should have resource limits defined to prevent
10+
resource exhaustion and ensure fair scheduling.
11+
spec:
12+
validationFailureAction: Enforce
13+
background: true
14+
rules:
15+
- name: validate-resource-limits
16+
match:
17+
any:
18+
- resources:
19+
kinds:
20+
- Pod
21+
exclude:
22+
any:
23+
- resources:
24+
namespaces:
25+
- kube-system
26+
- kyverno
27+
- kube-flannel
28+
- grafana
29+
# Exclude CronJob pods (short-lived, run to completion)
30+
- resources:
31+
selector:
32+
matchExpressions:
33+
- key: job-name
34+
operator: Exists
35+
validate:
36+
message: "Containers must have memory and CPU limits defined."
37+
pattern:
38+
spec:
39+
containers:
40+
- resources:
41+
limits:
42+
memory: "?*"
43+
cpu: "?*"
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
apiVersion: kyverno.io/v1
2+
kind: ClusterPolicy
3+
metadata:
4+
name: restrict-image-registries
5+
annotations:
6+
policies.kyverno.io/title: Restrict Image Registries
7+
policies.kyverno.io/category: Security
8+
policies.kyverno.io/description: >-
9+
Only allow container images from approved registries to ensure
10+
supply chain security and prevent pulling from untrusted sources.
11+
spec:
12+
validationFailureAction: Enforce
13+
background: true
14+
rules:
15+
- name: validate-registries
16+
match:
17+
any:
18+
- resources:
19+
kinds:
20+
- Pod
21+
validate:
22+
message: >-
23+
Image '{{ request.object.spec.containers[].image }}' is not from an approved registry.
24+
Allowed registries: osuakatsuki/*, registry.k8s.io/*, docker.io/flannel/*,
25+
docker.io/grafana/*, ghcr.io/grafana/*, quay.io/prometheus/*,
26+
myoung34/github-runner*, phpmyadmin/phpmyadmin*
27+
foreach:
28+
- list: "request.object.spec.containers"
29+
deny:
30+
conditions:
31+
all:
32+
- key: "{{ element.image }}"
33+
operator: NotEquals
34+
value: ""
35+
- key: "{{ element.image }}"
36+
operator: AnyNotIn
37+
value:
38+
- "osuakatsuki/*"
39+
- "docker.io/osuakatsuki/*"
40+
- "registry.k8s.io/*"
41+
- "docker.io/flannel/*"
42+
- "flannel/*"
43+
- "docker.io/grafana/*"
44+
- "grafana/*"
45+
- "ghcr.io/grafana/*"
46+
- "quay.io/prometheus/*"
47+
- "myoung34/github-runner*"
48+
- "docker.io/myoung34/github-runner*"
49+
- "phpmyadmin/phpmyadmin*"
50+
- "docker.io/phpmyadmin/phpmyadmin*"
51+
- name: validate-init-container-registries
52+
match:
53+
any:
54+
- resources:
55+
kinds:
56+
- Pod
57+
preconditions:
58+
all:
59+
- key: "{{ request.object.spec.initContainers || `[]` | length(@) }}"
60+
operator: GreaterThan
61+
value: 0
62+
validate:
63+
message: >-
64+
Init container image is not from an approved registry.
65+
foreach:
66+
- list: "request.object.spec.initContainers"
67+
deny:
68+
conditions:
69+
all:
70+
- key: "{{ element.image }}"
71+
operator: NotEquals
72+
value: ""
73+
- key: "{{ element.image }}"
74+
operator: AnyNotIn
75+
value:
76+
- "osuakatsuki/*"
77+
- "docker.io/osuakatsuki/*"
78+
- "registry.k8s.io/*"
79+
- "docker.io/flannel/*"
80+
- "flannel/*"
81+
- "docker.io/grafana/*"
82+
- "grafana/*"
83+
- "ghcr.io/grafana/*"
84+
- "quay.io/prometheus/*"
85+
- "myoung34/github-runner*"
86+
- "docker.io/myoung34/github-runner*"
87+
- "phpmyadmin/phpmyadmin*"
88+
- "docker.io/phpmyadmin/phpmyadmin*"

k8s/kyverno/values.yaml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Kyverno Helm values
2+
# Minimal resource configuration for small clusters
3+
4+
admissionController:
5+
replicas: 1
6+
resources:
7+
limits:
8+
memory: 384Mi
9+
requests:
10+
cpu: 100m
11+
memory: 128Mi
12+
13+
backgroundController:
14+
replicas: 1
15+
resources:
16+
limits:
17+
memory: 256Mi
18+
requests:
19+
cpu: 50m
20+
memory: 64Mi
21+
22+
cleanupController:
23+
replicas: 1
24+
resources:
25+
limits:
26+
memory: 256Mi
27+
requests:
28+
cpu: 50m
29+
memory: 64Mi
30+
31+
reportsController:
32+
replicas: 1
33+
resources:
34+
limits:
35+
memory: 256Mi
36+
requests:
37+
cpu: 50m
38+
memory: 64Mi
39+
40+
# Fail open if Kyverno is unavailable (prevents blocking deployments)
41+
config:
42+
webhooks:
43+
- failurePolicy: Ignore

0 commit comments

Comments
 (0)