add kyverno policies

Signed-off-by: gwg313 <gwg313@pm.me>
This commit is contained in:
gwg313 2026-05-27 19:23:54 -04:00
parent 4be877e419
commit baa0216960
Signed by: gwg313
GPG key ID: 60FF63B4826B7400
35 changed files with 843 additions and 39 deletions

View file

@ -15,8 +15,16 @@ spec:
labels:
app: audiobookshelf
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
containers:
- name: audiobookshelf
securityContext:
allowPrivilegeEscalation: false
runAsNonRoot: true
runAsUser: 1000
image: ghcr.io/advplyr/audiobookshelf:2.35.0
imagePullPolicy: IfNotPresent
ports:

View file

@ -15,8 +15,17 @@ spec:
labels:
app: navidrome
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
containers:
- name: navidrome
securityContext:
allowPrivilegeEscalation: false
runAsNonRoot: true
runAsUser: 1000
readOnlyRootFilesystem: false
image: deluan/navidrome:pr-5495
ports:
- containerPort: 4533

View file

@ -14,9 +14,15 @@ spec:
app: stirling-pdf
spec:
securityContext:
fsGroup: 1000
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
containers:
- name: stirling-pdf
securityContext:
allowPrivilegeEscalation: false
runAsNonRoot: true
runAsUser: 1000
image: docker.stirlingpdf.com/stirlingtools/stirling-pdf:2.11.0-fat
resources:
requests:
@ -43,7 +49,25 @@ spec:
- name: stirling-data
mountPath: /pipeline
subPath: pipeline
- name: stirling-user
mountPath: /home
- name: tmp
mountPath: /tmp
- name: stirling
mountPath: /tmp/stirling-pdf
- name: app-data
mountPath: /usr/local/bin
volumes:
- name: stirling-data
persistentVolumeClaim:
claimName: stirling-data
- name: tmp
emptyDir: {}
- name: stirling
emptyDir: {}
- name: app-data
emptyDir: {}
- name: stirling-user
emptyDir: {}

View file

@ -12,8 +12,17 @@ spec:
labels:
app.kubernetes.io/name: yopass
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
containers:
- name: yopass
securityContext:
allowPrivilegeEscalation: false
runAsNonRoot: true
runAsUser: 1000
readOnlyRootFilesystem: false
image: jhaals/yopass:13.1.0
args:
- "--memcached=localhost:11211"

View file

@ -0,0 +1,49 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: kyverno:cleanup-extra-resources
labels:
rbac.kyverno.io/aggregate-to-cleanup-controller: "true"
annotations:
argocd.argoproj.io/sync-wave: "-1"
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- watch
- delete
- apiGroups:
- batch
resources:
- jobs
- cronjobs
verbs:
- get
- list
- watch
- delete
- apiGroups:
- apps
resources:
- replicasets
verbs:
- get
- list
- watch
- delete
- apiGroups:
- apps
resources:
- deployments
verbs:
- get
- list
- watch

View file

@ -0,0 +1,13 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- cleanup-rbac.yaml
- kyverno-cilium-rbac.yaml
commonLabels:
app.kubernetes.io/part-of: kyverno-policies
policy-tier: meta
commonAnnotations:
argocd.argoproj.io/sync-wave: "-1"

View file

@ -5,6 +5,7 @@ metadata:
labels:
kyverno.io/aggregate-to-background: "true"
kyverno.io/aggregate-to-reports: "true"
app.kubernetes.io/component: kyverno
annotations:
argocd.argoproj.io/sync-wave: "-1"
rules:

View file

@ -0,0 +1,42 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: default-container-resources
spec:
background: true
rules:
- name: default-container-resources
match:
any:
- resources:
kinds:
- Pod
mutate:
foreach:
- list: "request.object.spec.containers"
patchStrategicMerge:
spec:
containers:
- (name): "{{ element.name }}"
resources:
requests:
+(cpu): "100m"
+(memory): "128Mi"
limits:
+(cpu): "200m"
+(memory): "512Mi"
- list: "request.object.spec.initContainers || []"
patchStrategicMerge:
spec:
initContainers:
- (name): "{{ element.name }}"
resources:
requests:
+(cpu): "100m"
+(memory): "128Mi"
limits:
+(cpu): "200m"
+(memory): "512Mi"

View file

@ -0,0 +1,18 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: default-cronjob-history
spec:
rules:
- name: set-cronjob-history
match:
any:
- resources:
kinds:
- CronJob
mutate:
patchStrategicMerge:
spec:
+(successfulJobsHistoryLimit): 1
+(failedJobsHistoryLimit): 2

View file

@ -0,0 +1,17 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: default-deployment-revision-history
spec:
rules:
- name: set-revision-history-limit
match:
any:
- resources:
kinds:
- Deployment
mutate:
patchStrategicMerge:
spec:
+(revisionHistoryLimit): 3

View file

@ -0,0 +1,36 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: default-drop-all-capabilities
spec:
background: true
rules:
- name: default-drop-all-capabilities
match:
any:
- resources:
kinds:
- Pod
mutate:
foreach:
- list: "request.object.spec.containers"
patchStrategicMerge:
spec:
containers:
- (name): "{{ element.name }}"
securityContext:
+(capabilities):
drop:
- ALL
- list: "request.object.spec.initContainers || []"
patchStrategicMerge:
spec:
initContainers:
- (name): "{{ element.name }}"
securityContext:
+(capabilities):
drop:
- ALL

View file

@ -0,0 +1,17 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: default-job-ttl
spec:
rules:
- name: set-job-ttl
match:
any:
- resources:
kinds:
- Job
mutate:
patchStrategicMerge:
spec:
+(ttlSecondsAfterFinished): 86400

View file

@ -0,0 +1,46 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: default-run-as-non-root
spec:
background: true
rules:
- name: default-pod-run-as-non-root
match:
any:
- resources:
kinds:
- Pod
mutate:
patchStrategicMerge:
spec:
securityContext:
+(runAsNonRoot): true
- name: default-container-run-as-non-root
match:
any:
- resources:
kinds:
- Pod
mutate:
foreach:
- list: "request.object.spec.containers"
patchStrategicMerge:
spec:
containers:
- (name): "{{ element.name }}"
securityContext:
+(runAsNonRoot): true
- list: "request.object.spec.initContainers || []"
patchStrategicMerge:
spec:
initContainers:
- (name): "{{ element.name }}"
securityContext:
+(runAsNonRoot): true

View file

@ -0,0 +1,49 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: default-seccomp-runtime-default
spec:
background: true
rules:
- name: default-pod-seccomp-runtime-default
match:
any:
- resources:
kinds:
- Pod
mutate:
patchStrategicMerge:
spec:
securityContext:
seccompProfile:
type: RuntimeDefault
- name: default-container-seccomp-runtime-default
match:
any:
- resources:
kinds:
- Pod
mutate:
foreach:
- list: "request.object.spec.containers"
patchStrategicMerge:
spec:
containers:
- (name): "{{ element.name }}"
securityContext:
seccompProfile:
type: RuntimeDefault
- list: "request.object.spec.initContainers || []"
patchStrategicMerge:
spec:
initContainers:
- (name): "{{ element.name }}"
securityContext:
seccompProfile:
type: RuntimeDefault

View file

@ -0,0 +1,18 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- default-container-resources.yaml
- default-cronjob-history.yaml
- default-deployment-revision-history.yaml
- default-drop-all-capabilities.yaml
- default-job-ttl.yaml
- default-run-as-non-root.yaml
- default-seccomp-runtime-default.yaml
commonLabels:
app.kubernetes.io/part-of: kyverno-policies
policy-tier: defaults
commonAnnotations:
argocd.argoproj.io/sync-wave: "0"

View file

@ -0,0 +1,17 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- require-drop-all-capabilities.yaml
- require-no-privilege-escalation.yaml
- require-non-root.yaml
- require-readonly-root-filesystem.yaml
- require-requests-limits.yaml
- require-seccomp-runtime-default.yaml
commonLabels:
app.kubernetes.io/part-of: kyverno-policies
policy-tier: require
commonAnnotations:
argocd.argoproj.io/sync-wave: "1"

View file

@ -0,0 +1,44 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-drop-all-capabilities
annotations:
policies.kyverno.io/title: Require Dropping Linux Capabilities
policies.kyverno.io/category: Pod Security
policies.kyverno.io/severity: high
spec:
validationFailureAction: Enforce
background: true
rules:
- name: require-drop-all-capabilities
match:
any:
- resources:
kinds:
- Pod
validate:
message: "All containers must drop ALL Linux capabilities."
foreach:
- list: "request.object.spec.containers"
pattern:
securityContext:
capabilities:
drop:
- ALL
- list: "request.object.spec.initContainers"
pattern:
securityContext:
capabilities:
drop:
- ALL
- list: "request.object.spec.ephemeralContainers"
pattern:
securityContext:
capabilities:
drop:
- ALL

View file

@ -0,0 +1,43 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-no-privilege-escalation
spec:
validationFailureAction: Enforce
background: true
rules:
- name: require-no-privilege-escalation
match:
any:
- resources:
kinds:
- Pod
validate:
message: "allowPrivilegeEscalation must be false."
foreach:
- list: "request.object.spec.containers"
deny:
conditions:
any:
- key: "{{ element.securityContext.allowPrivilegeEscalation || `false` }}"
operator: Equals
value: true
- list: "request.object.spec.initContainers || []"
deny:
conditions:
any:
- key: "{{ element.securityContext.allowPrivilegeEscalation || `false` }}"
operator: Equals
value: true
- list: "request.object.spec.ephemeralContainers || []"
deny:
conditions:
any:
- key: "{{ element.securityContext.allowPrivilegeEscalation || `false` }}"
operator: Equals
value: true

View file

@ -0,0 +1,52 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-non-root
annotations:
policies.kyverno.io/title: Require Non-Root Containers
policies.kyverno.io/category: Pod Security
policies.kyverno.io/severity: high
spec:
validationFailureAction: Enforce
background: true
rules:
- name: require-pod-run-as-non-root
match:
any:
- resources:
kinds:
- Pod
validate:
message: "Pods must set runAsNonRoot=true."
pattern:
spec:
securityContext:
runAsNonRoot: true
- name: require-container-run-as-non-root
match:
any:
- resources:
kinds:
- Pod
validate:
message: "All containers must set runAsNonRoot=true."
foreach:
- list: "request.object.spec.containers"
pattern:
securityContext:
runAsNonRoot: true
- list: "request.object.spec.initContainers"
pattern:
securityContext:
runAsNonRoot: true
- list: "request.object.spec.ephemeralContainers"
pattern:
securityContext:
runAsNonRoot: true

View file

@ -0,0 +1,38 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-readonly-root-filesystem
annotations:
policies.kyverno.io/title: Require Read-Only Root Filesystem
policies.kyverno.io/category: Pod Security
policies.kyverno.io/severity: high
spec:
validationFailureAction: Audit
background: true
rules:
- name: require-readonly-root-filesystem
match:
any:
- resources:
kinds:
- Pod
validate:
message: "Containers must use readOnlyRootFilesystem=true."
foreach:
- list: "request.object.spec.containers"
pattern:
securityContext:
readOnlyRootFilesystem: true
- list: "request.object.spec.initContainers"
pattern:
securityContext:
readOnlyRootFilesystem: true
- list: "request.object.spec.ephemeralContainers"
pattern:
securityContext:
readOnlyRootFilesystem: true

View file

@ -0,0 +1,52 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-seccomp-runtime-default
spec:
validationFailureAction: Enforce
background: true
rules:
- name: require-pod-seccomp-runtime-default
match:
any:
- resources:
kinds:
- Pod
validate:
message: "Pod seccompProfile.type must be RuntimeDefault."
pattern:
spec:
securityContext:
seccompProfile:
type: RuntimeDefault
- name: require-container-seccomp-runtime-default
match:
any:
- resources:
kinds:
- Pod
validate:
message: "All containers must use RuntimeDefault seccomp."
foreach:
- list: "request.object.spec.containers"
pattern:
securityContext:
seccompProfile:
type: RuntimeDefault
- list: "request.object.spec.initContainers"
pattern:
securityContext:
seccompProfile:
type: RuntimeDefault
- list: "request.object.spec.ephemeralContainers"
pattern:
securityContext:
seccompProfile:
type: RuntimeDefault

View file

@ -0,0 +1,35 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-host-namespace
spec:
validationFailureAction: Enforce
background: true
rules:
- name: no-host-namespaces
match:
any:
- resources:
kinds:
- Pod
- Deployment
- StatefulSet
- DaemonSet
validate:
message: "Host networking, PID, and IPC are not allowed."
deny:
conditions:
any:
- key: "{{ request.object.spec.hostNetwork || false }}"
operator: Equals
value: true
- key: "{{ request.object.spec.hostPID || false }}"
operator: Equals
value: true
- key: "{{ request.object.spec.hostIPC || false }}"
operator: Equals
value: true

View file

@ -0,0 +1,20 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-hostpath-volumes
spec:
validationFailureAction: Enforce
rules:
- name: no-hostpath
match:
any:
- resources:
kinds: ["Pod"]
validate:
message: "hostPath volumes are not allowed (escape risk)."
pattern:
spec:
volumes:
- (hostPath): null

View file

@ -0,0 +1,48 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-privileged-containers
annotations:
policies.kyverno.io/title: Disallow Privileged Containers
policies.kyverno.io/category: Pod Security
policies.kyverno.io/severity: critical
spec:
validationFailureAction: Enforce
background: true
rules:
- name: disallow-privileged
match:
any:
- resources:
kinds:
- Pod
validate:
message: "Privileged containers are not allowed."
foreach:
- list: "request.object.spec.containers"
deny:
conditions:
any:
- key: "{{ element.securityContext.privileged || `false` }}"
operator: Equals
value: true
- list: "request.object.spec.initContainers || []"
deny:
conditions:
any:
- key: "{{ element.securityContext.privileged || `false` }}"
operator: Equals
value: true
- list: "request.object.spec.ephemeralContainers || []"
deny:
conditions:
any:
- key: "{{ element.securityContext.privileged || `false` }}"
operator: Equals
value: true

View file

@ -0,0 +1,15 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- disallow-host-namespace.yaml
- disallow-hostpath-volumes.yaml
- disallow-latest-tag.yaml
- disallow-privileged-containers.yaml
commonLabels:
app.kubernetes.io/part-of: kyverno-policies
policy-tier: disallow
commonAnnotations:
argocd.argoproj.io/sync-wave: "2"

View file

@ -1,21 +1,28 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: generate-ns-network-baseline
name: generate-namespace-network-baseline
annotations:
policies.kyverno.io/title: Inject Namespace Baseline CNP
policies.kyverno.io/description: Automatically provisions a local default-deny + DNS egress CNP inside new application namespaces.
policies.kyverno.io/title: Generate Namespace Network Baseline
policies.kyverno.io/category: Network Security
policies.kyverno.io/severity: high
policies.kyverno.io/description: >-
Automatically provisions a baseline CiliumNetworkPolicy
with default deny ingress and controlled DNS egress.
argocd.argoproj.io/sync-options: Force=true,Replace=true
spec:
background: true
rules:
- name: inject-local-cnp
- name: generate-baseline-cnp
match:
any:
- resources:
kinds:
- Namespace
exclude:
any:
- resources:
@ -24,37 +31,53 @@ spec:
- kube-system
- kube-public
- kube-node-lease
- argocd
- kyverno
- cilium-ingress
- cilium-secrets
- argocd
- cert-manager
- sealed-secrets
- nfs-subdir-external-provisioner
- monitoring
- tekton-pipelines-resolvers
- cilium-secrets
- cilium-ingress
- sealed-secrets
- tekton-pipelines
- tekton-pipelines-resolvers
- pipelines-as-code
generate:
synchronize: true
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
name: baseline-network-security
namespace: "{{request.object.metadata.name}}"
synchronize: true
namespace: "{{ request.object.metadata.name }}"
data:
metadata:
labels:
security-tier: baseline
spec:
endpointSelector: {}
ingress:
- {}
policyTypes:
- Ingress
- Egress
ingress: []
egress:
- toEndpoints:
- matchLabels:
k8s:io.kubernetes.pod.namespace: kube-system
k8s-app: kube-dns
toPorts:
- ports:
- port: "53"
protocol: ANY
protocol: UDP
- port: "53"
protocol: TCP
rules:
dns:
- matchPattern: "*"

View file

@ -0,0 +1,12 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- generate-namespace-network-baseline.yaml
commonLabels:
app.kubernetes.io/part-of: kyverno-policies
policy-tier: generate
commonAnnotations:
argocd.argoproj.io/sync-wave: "3"

View file

@ -0,0 +1,22 @@
apiVersion: kyverno.io/v2beta1
kind: ClusterCleanupPolicy
metadata:
name: cleanup-evicted-pods
spec:
match:
any:
- resources:
kinds:
- Pod
conditions:
all:
- key: "{{ target.status.reason }}"
operator: Equals
value: Evicted
- key: "{{ time_diff('{{ target.metadata.creationTimestamp }}','{{ time_now_utc() }}') }}"
operator: GreaterThan
value: 1h
schedule: "0 * * * *"

View file

@ -0,0 +1,22 @@
apiVersion: kyverno.io/v2beta1
kind: ClusterCleanupPolicy
metadata:
name: cleanup-old-replicasets
spec:
match:
any:
- resources:
kinds:
- ReplicaSet
conditions:
all:
- key: "{{ target.spec.replicas || `0` }}"
operator: Equals
value: 0
- key: "{{ time_diff('{{ target.metadata.creationTimestamp }}','{{ time_now_utc() }}') }}"
operator: GreaterThan
value: 168h
schedule: "0 3 * * *"

View file

@ -1,21 +1,24 @@
apiVersion: kyverno.io/v2beta1
kind: ClusterCleanupPolicy
metadata:
name: purge-terminal-pods
name: cleanup-terminal-pods
spec:
match:
any:
- resources:
kinds:
- Pod
schedule: "*/15 * * * *"
conditions:
all:
- key: "{{ request.object.status.phase }}"
- key: "{{ target.status.phase }}"
operator: AnyIn
value:
- Succeeded
- Failed
- key: "{{ request.object.metadata.creationTimestamp }}"
operator: DurationGreaterThan
- key: "{{ time_diff('{{ target.metadata.creationTimestamp }}','{{ time_now_utc() }}') }}"
operator: GreaterThan
value: 30m
schedule: "*/15 * * * *"

View file

@ -0,0 +1,14 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- cleanup-evicted-pods.yaml
- cleanup-old-replicasets.yaml
- cleanup-terminal-pods.yaml
commonLabels:
app.kubernetes.io/part-of: kyverno-policies
policy-tier: cleanup
commonAnnotations:
argocd.argoproj.io/sync-wave: "4"

View file

@ -1,12 +0,0 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: kyverno:cleanup-pods
labels:
rbac.kyverno.io/aggregate-to-cleanup-controller: "true"
annotations:
argocd.argoproj.io/sync-wave: "-1"
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch", "delete"]

View file

@ -2,9 +2,9 @@ apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- cleanup-rbac.yaml
- purge-terminal-pods.yaml
- disallow-latest-tag.yaml
- kyverno-cilium-rbac.yaml
- generate-ns-network-baseline.yaml
- require-requests-limits.yaml
- 00-meta
- 10-defaults
- 20-require
- 30-disallow
- 40-generate
- 50-cleanup