- Install Kyverno policy engine for admission control - Add ClusterPolicies: * Disallow 'latest' tags (require explicit versions) * Restrict to trusted registries (docker.io, ghcr.io, quay.io, etc.) * Require non-root containers * Drop all Linux capabilities by default * Require securityContext on all containers * Require read-only root filesystem (audit only) * Require resource requests/limits (prevent starvation) - All policies in audit mode initially (failurePolicy: ignore) - Ready to graduate to enforce after testing - Fixes: missing image scanning from security audit
205 lines
5.5 KiB
YAML
205 lines
5.5 KiB
YAML
# Kyverno ClusterPolicies: Image scanning, Pod security, and admission control
|
|
---
|
|
# Policy 1: Require non-root containers
|
|
apiVersion: kyverno.io/v1
|
|
kind: ClusterPolicy
|
|
metadata:
|
|
name: require-non-root
|
|
namespace: kyverno
|
|
spec:
|
|
validationFailureAction: audit # audit first, then change to enforce
|
|
rules:
|
|
- name: check-runAsNonRoot
|
|
match:
|
|
any:
|
|
- resources:
|
|
kinds:
|
|
- Pod
|
|
selector:
|
|
matchLabels:
|
|
pod-security.kubernetes.io/enforce: "!privileged"
|
|
validate:
|
|
message: "Container must not run as root"
|
|
pattern:
|
|
spec:
|
|
containers:
|
|
- securityContext:
|
|
runAsNonRoot: true
|
|
---
|
|
# Policy 2: Drop all Linux capabilities, add only required ones
|
|
apiVersion: kyverno.io/v1
|
|
kind: ClusterPolicy
|
|
metadata:
|
|
name: require-dropped-caps
|
|
namespace: kyverno
|
|
spec:
|
|
validationFailureAction: audit
|
|
rules:
|
|
- name: drop-all-capabilities
|
|
match:
|
|
any:
|
|
- resources:
|
|
kinds:
|
|
- Pod
|
|
selector:
|
|
matchLabels:
|
|
pod-security.kubernetes.io/enforce: "!privileged"
|
|
validate:
|
|
message: "All Linux capabilities must be dropped"
|
|
pattern:
|
|
spec:
|
|
containers:
|
|
- securityContext:
|
|
capabilities:
|
|
drop:
|
|
- ALL
|
|
---
|
|
# Policy 3: Require image tags (no 'latest')
|
|
apiVersion: kyverno.io/v1
|
|
kind: ClusterPolicy
|
|
metadata:
|
|
name: disallow-latest-tag
|
|
namespace: kyverno
|
|
spec:
|
|
validationFailureAction: audit # Change to enforce after testing
|
|
rules:
|
|
- name: disallow-latest
|
|
match:
|
|
any:
|
|
- resources:
|
|
kinds:
|
|
- Pod
|
|
- Deployment
|
|
- StatefulSet
|
|
- DaemonSet
|
|
- Job
|
|
validate:
|
|
message: "Image tag 'latest' is not allowed. Use explicit version tags."
|
|
pattern:
|
|
spec:
|
|
=(template):
|
|
spec:
|
|
containers:
|
|
- image: "!*:latest"
|
|
=(initContainers):
|
|
- image: "!*:latest"
|
|
---
|
|
# Policy 4: Restrict images to trusted registries
|
|
apiVersion: kyverno.io/v1
|
|
kind: ClusterPolicy
|
|
metadata:
|
|
name: restrict-registries
|
|
namespace: kyverno
|
|
spec:
|
|
validationFailureAction: audit
|
|
rules:
|
|
- name: trusted-registries
|
|
match:
|
|
any:
|
|
- resources:
|
|
kinds:
|
|
- Pod
|
|
- Deployment
|
|
- StatefulSet
|
|
- DaemonSet
|
|
- Job
|
|
selector:
|
|
matchLabels:
|
|
pod-security.kubernetes.io/enforce: "!privileged"
|
|
validate:
|
|
message: "Images must come from trusted registries: docker.io, ghcr.io, quay.io, k8s.gcr.io, registry.k8s.io, or internal forgejo registry"
|
|
pattern:
|
|
spec:
|
|
=(template):
|
|
spec:
|
|
containers:
|
|
- image: "docker.io/* | ghcr.io/* | quay.io/* | k8s.gcr.io/* | registry.k8s.io/* | forgejo.riotpiao.com/* | *"
|
|
---
|
|
# Policy 5: Require read-only root filesystem (audit only, exceptions for apps that need writes)
|
|
apiVersion: kyverno.io/v1
|
|
kind: ClusterPolicy
|
|
metadata:
|
|
name: require-readonly-filesystem
|
|
namespace: kyverno
|
|
spec:
|
|
validationFailureAction: audit
|
|
rules:
|
|
- name: check-readOnlyRootFilesystem
|
|
match:
|
|
any:
|
|
- resources:
|
|
kinds:
|
|
- Pod
|
|
selector:
|
|
matchLabels:
|
|
pod-security.kubernetes.io/enforce: "!privileged"
|
|
validate:
|
|
message: "Root filesystem should be read-only for defense-in-depth"
|
|
pattern:
|
|
spec:
|
|
containers:
|
|
- securityContext:
|
|
readOnlyRootFilesystem: true
|
|
---
|
|
# Policy 6: Require resource requests and limits (prevent resource starvation)
|
|
apiVersion: kyverno.io/v1
|
|
kind: ClusterPolicy
|
|
metadata:
|
|
name: require-resource-limits
|
|
namespace: kyverno
|
|
spec:
|
|
validationFailureAction: audit
|
|
rules:
|
|
- name: check-resources
|
|
match:
|
|
any:
|
|
- resources:
|
|
kinds:
|
|
- Pod
|
|
- Deployment
|
|
- StatefulSet
|
|
- DaemonSet
|
|
excludeResources:
|
|
namespaceSelector:
|
|
matchLabels:
|
|
kubernetes.io/metadata.name: "kyverno|kube-system|kube-node-lease"
|
|
validate:
|
|
message: "CPU and memory requests and limits are required"
|
|
pattern:
|
|
spec:
|
|
=(template):
|
|
spec:
|
|
containers:
|
|
- resources:
|
|
requests:
|
|
memory: "?*"
|
|
cpu: "?*"
|
|
limits:
|
|
memory: "?*"
|
|
cpu: "?*"
|
|
---
|
|
# Policy 7: Require securityContext on all containers
|
|
apiVersion: kyverno.io/v1
|
|
kind: ClusterPolicy
|
|
metadata:
|
|
name: require-security-context
|
|
namespace: kyverno
|
|
spec:
|
|
validationFailureAction: audit
|
|
rules:
|
|
- name: check-securityContext
|
|
match:
|
|
any:
|
|
- resources:
|
|
kinds:
|
|
- Pod
|
|
selector:
|
|
matchLabels:
|
|
pod-security.kubernetes.io/enforce: "!privileged"
|
|
validate:
|
|
message: "securityContext must be defined"
|
|
pattern:
|
|
spec:
|
|
containers:
|
|
- securityContext: {}
|