Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions k8s/kyverno/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Kyverno

Policy engine for Kubernetes that validates, mutates, and generates resources.

## Installation

```bash
# Add Helm repo
helm repo add kyverno https://kyverno.github.io/kyverno/
helm repo update kyverno

# Install Kyverno
helm install kyverno kyverno/kyverno \
-n kyverno \
--create-namespace \
-f values.yaml \
--wait

# Apply policies
kubectl apply -f policies/
```

## Upgrade

```bash
helm repo update kyverno
helm upgrade kyverno kyverno/kyverno \
-n kyverno \
-f values.yaml \
--wait
```

## Uninstall

```bash
kubectl delete -f policies/
helm uninstall kyverno -n kyverno
kubectl delete ns kyverno
```

## Policies

| Policy | Mode | Description |
|--------|------|-------------|
| `restrict-image-registries` | Enforce | Only allow images from approved registries |
| `require-resource-limits` | Enforce | Block pods without resource limits |
| `disallow-privileged-containers` | Enforce | Block privileged containers |
| `require-probes` | Enforce | Block web services without readiness probes |

### Exclusions

The following are excluded from resource limits and probe requirements:
- System namespaces: `kube-system`, `kyverno`, `kube-flannel`, `grafana`
- CronJob pods (identified by `job-name` label)
- GitHub runner namespace
- Background workers: `*-discord-bot-*`, `*-pubsub-daemon-*`, `*-amqp-processor-*`, `*-processor-production-*`

## Checking Policy Violations

```bash
# View policy reports
kubectl get policyreport -A

# View cluster-wide policy reports
kubectl get clusterpolicyreport

# Describe a specific report for details
kubectl describe policyreport -n default
```
41 changes: 41 additions & 0 deletions k8s/kyverno/policies/disallow-privileged-containers.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-privileged-containers
annotations:
policies.kyverno.io/title: Disallow Privileged Containers
policies.kyverno.io/category: Security
policies.kyverno.io/description: >-
Privileged containers have full access to the host and should
be blocked except for specific system workloads.
spec:
validationFailureAction: Enforce
background: true
rules:
- name: disallow-privileged
match:
any:
- resources:
kinds:
- Pod
exclude:
any:
- resources:
namespaces:
- kube-system
- kube-flannel
- resources:
namespaces:
- github-runner
names:
- "github-runner-*"
validate:
message: "Privileged containers are not allowed."
pattern:
spec:
containers:
- =(securityContext):
=(privileged): false
=(initContainers):
- =(securityContext):
=(privileged): false
63 changes: 63 additions & 0 deletions k8s/kyverno/policies/require-probes.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-probes
annotations:
policies.kyverno.io/title: Require Probes
policies.kyverno.io/category: Best Practices
policies.kyverno.io/description: >-
Containers should have readiness and liveness probes defined
to ensure proper health checking and traffic management.
spec:
validationFailureAction: Enforce
background: true
rules:
- name: validate-probes
match:
any:
- resources:
kinds:
- Pod
exclude:
any:
# System namespaces
- resources:
namespaces:
- kube-system
- kyverno
- kube-flannel
- github-runner
- grafana
# CronJob pods (they run to completion)
- resources:
selector:
matchExpressions:
- key: job-name
operator: Exists
# Background workers - discord bots
- resources:
names:
- "*-discord-bot-*"
# Background workers - pubsub daemons
- resources:
names:
- "*-pubsub-daemon-*"
# Background workers - AMQP processors
- resources:
names:
- "*-amqp-processor-*"
# Background workers - other processors
- resources:
names:
- "*-processor-production-*"
# Background workers - cleanup crons (non-Job pods)
- resources:
names:
- "*-cleanup-cron-*"
validate:
message: "Web service containers must have readinessProbe defined."
pattern:
spec:
containers:
- readinessProbe:
periodSeconds: ">0"
43 changes: 43 additions & 0 deletions k8s/kyverno/policies/require-resource-limits.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-resource-limits
annotations:
policies.kyverno.io/title: Require Resource Limits
policies.kyverno.io/category: Best Practices
policies.kyverno.io/description: >-
Containers should have resource limits defined to prevent
resource exhaustion and ensure fair scheduling.
spec:
validationFailureAction: Enforce
background: true
rules:
- name: validate-resource-limits
match:
any:
- resources:
kinds:
- Pod
exclude:
any:
- resources:
namespaces:
- kube-system
- kyverno
- kube-flannel
- grafana
# Exclude CronJob pods (short-lived, run to completion)
- resources:
selector:
matchExpressions:
- key: job-name
operator: Exists
validate:
message: "Containers must have memory and CPU limits defined."
pattern:
spec:
containers:
- resources:
limits:
memory: "?*"
cpu: "?*"
88 changes: 88 additions & 0 deletions k8s/kyverno/policies/restrict-image-registries.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: restrict-image-registries
annotations:
policies.kyverno.io/title: Restrict Image Registries
policies.kyverno.io/category: Security
policies.kyverno.io/description: >-
Only allow container images from approved registries to ensure
supply chain security and prevent pulling from untrusted sources.
spec:
validationFailureAction: Enforce
background: true
rules:
- name: validate-registries
match:
any:
- resources:
kinds:
- Pod
validate:
message: >-
Image '{{ request.object.spec.containers[].image }}' is not from an approved registry.
Allowed registries: osuakatsuki/*, registry.k8s.io/*, docker.io/flannel/*,
docker.io/grafana/*, ghcr.io/grafana/*, quay.io/prometheus/*,
myoung34/github-runner*, phpmyadmin/phpmyadmin*
foreach:
- list: "request.object.spec.containers"
deny:
conditions:
all:
- key: "{{ element.image }}"
operator: NotEquals
value: ""
- key: "{{ element.image }}"
operator: AnyNotIn
value:
- "osuakatsuki/*"
- "docker.io/osuakatsuki/*"
- "registry.k8s.io/*"
- "docker.io/flannel/*"
- "flannel/*"
- "docker.io/grafana/*"
- "grafana/*"
- "ghcr.io/grafana/*"
- "quay.io/prometheus/*"
- "myoung34/github-runner*"
- "docker.io/myoung34/github-runner*"
- "phpmyadmin/phpmyadmin*"
- "docker.io/phpmyadmin/phpmyadmin*"
- name: validate-init-container-registries
match:
any:
- resources:
kinds:
- Pod
preconditions:
all:
- key: "{{ request.object.spec.initContainers || `[]` | length(@) }}"
operator: GreaterThan
value: 0
validate:
message: >-
Init container image is not from an approved registry.
foreach:
- list: "request.object.spec.initContainers"
deny:
conditions:
all:
- key: "{{ element.image }}"
operator: NotEquals
value: ""
- key: "{{ element.image }}"
operator: AnyNotIn
value:
- "osuakatsuki/*"
- "docker.io/osuakatsuki/*"
- "registry.k8s.io/*"
- "docker.io/flannel/*"
- "flannel/*"
- "docker.io/grafana/*"
- "grafana/*"
- "ghcr.io/grafana/*"
- "quay.io/prometheus/*"
- "myoung34/github-runner*"
- "docker.io/myoung34/github-runner*"
- "phpmyadmin/phpmyadmin*"
- "docker.io/phpmyadmin/phpmyadmin*"
38 changes: 38 additions & 0 deletions k8s/kyverno/values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Kyverno Helm values
# Minimal resource configuration for small clusters

admissionController:
replicas: 1
resources:
limits:
memory: 384Mi
requests:
cpu: 100m
memory: 128Mi

backgroundController:
replicas: 1
resources:
limits:
memory: 256Mi
requests:
cpu: 50m
memory: 64Mi

cleanupController:
replicas: 1
resources:
limits:
memory: 256Mi
requests:
cpu: 50m
memory: 64Mi

reportsController:
replicas: 1
resources:
limits:
memory: 256Mi
requests:
cpu: 50m
memory: 64Mi