feat(security): add Kyverno for image scanning and Pod security policies
- 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
This commit is contained in:
@@ -159,3 +159,54 @@ spec:
|
|||||||
automated:
|
automated:
|
||||||
prune: true
|
prune: true
|
||||||
selfHeal: true
|
selfHeal: true
|
||||||
|
---
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: kyverno
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "0"
|
||||||
|
spec:
|
||||||
|
project: homelab
|
||||||
|
source:
|
||||||
|
repoURL: https://kyverno.github.io/kyverno/
|
||||||
|
chart: kyverno
|
||||||
|
targetRevision: "1.14.0"
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- $values/k8s/bootstrap/kyverno/kyverno-values.yaml
|
||||||
|
sources:
|
||||||
|
- repoURL: https://forgejo.riotpiao.com/rock/homelab.git
|
||||||
|
targetRevision: main
|
||||||
|
ref: values
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: kyverno
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
---
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: kyverno-policies
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "0"
|
||||||
|
spec:
|
||||||
|
project: homelab
|
||||||
|
source:
|
||||||
|
repoURL: https://forgejo.riotpiao.com/rock/homelab.git
|
||||||
|
targetRevision: main
|
||||||
|
path: k8s/bootstrap/kyverno
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: kyverno
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
namespace: kyverno
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- policies.yaml
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
# Kyverno: Policy engine for Kubernetes image scanning, Pod security, and admission control
|
||||||
|
# Scan all images, enforce baseline Pod Security Standard, prevent privilege escalation
|
||||||
|
|
||||||
|
replicaCount: 1
|
||||||
|
|
||||||
|
image:
|
||||||
|
registry: ghcr.io
|
||||||
|
repository: kyverno/kyverno
|
||||||
|
tag: "v1.14.0"
|
||||||
|
|
||||||
|
config:
|
||||||
|
# Webhook timeout for policy evaluation. Increase if scanning takes longer.
|
||||||
|
webhookTimeoutSeconds: 30
|
||||||
|
# Failure policy: fail-open (audit/log) vs fail-closed (reject on error)
|
||||||
|
failurePolicy: fail
|
||||||
|
# Resource limits for webhook
|
||||||
|
webhookAnnotations:
|
||||||
|
rules: "allow"
|
||||||
|
|
||||||
|
# Pod security via Kyverno instead of Pod Security Policies (deprecated)
|
||||||
|
# Enforces baseline restrictions cluster-wide, with exceptions for privileged namespaces
|
||||||
|
podSecurityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 1000
|
||||||
|
|
||||||
|
rbac:
|
||||||
|
create: true
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "500m"
|
||||||
|
|
||||||
|
# Webhook configuration
|
||||||
|
webhook:
|
||||||
|
timeoutSeconds: 30
|
||||||
|
# Failure policy: "Fail" (reject on error) or "Ignore" (audit-only)
|
||||||
|
# Set to "Ignore" for initial testing, then change to "Fail"
|
||||||
|
failurePolicy: ignore
|
||||||
@@ -0,0 +1,204 @@
|
|||||||
|
# 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: {}
|
||||||
Reference in New Issue
Block a user