mirror of
https://github.com/ghndrx/homelab-gitops.git
synced 2026-02-10 06:44:57 +00:00
feat(kyverno): add policy engine with security baseline
- Kyverno 3.3.4 via Helm (HA config: 3 admission, 2 background replicas) - Validation policies: - disallow-privileged-containers (Enforce) - require-resource-limits (Enforce) - require-labels (Audit - standard k8s labels) - require-run-as-non-root (Audit) - disallow-latest-tag (Enforce - GitOps reproducibility) - Mutating policy: - add-default-securitycontext (seccomp, drop caps, read-only fs) - System namespaces excluded (kube-system, kyverno, istio-system) - Auto-discovered by ArgoCD ApplicationSet Reference: CIS Kubernetes Benchmark, Pod Security Standards
This commit is contained in:
22
README.md
22
README.md
@@ -34,6 +34,7 @@ See [docs/BOOTSTRAP.md](docs/BOOTSTRAP.md) for full setup guide.
|
|||||||
│ └── dev/
|
│ └── dev/
|
||||||
├── infrastructure/ # Cluster infrastructure
|
├── infrastructure/ # Cluster infrastructure
|
||||||
│ ├── cert-manager/ # ✅ TLS with Let's Encrypt
|
│ ├── cert-manager/ # ✅ TLS with Let's Encrypt
|
||||||
|
│ ├── kyverno/ # ✅ Policy engine (security + best practices)
|
||||||
│ ├── networking/ # Istio gateway, NetworkPolicies
|
│ ├── networking/ # Istio gateway, NetworkPolicies
|
||||||
│ ├── storage/ # NFS StorageClass
|
│ ├── storage/ # NFS StorageClass
|
||||||
│ └── monitoring/ # Prometheus, Grafana, Loki
|
│ └── monitoring/ # Prometheus, Grafana, Loki
|
||||||
@@ -69,6 +70,27 @@ Uses **ArgoCD ApplicationSets** with Git Directory Generator:
|
|||||||
- 🏠 Home Assistant
|
- 🏠 Home Assistant
|
||||||
- 📊 Homepage, Uptime Kuma
|
- 📊 Homepage, Uptime Kuma
|
||||||
|
|
||||||
|
## Policy Engine (Kyverno)
|
||||||
|
|
||||||
|
Kyverno enforces security and best practices across the cluster. Policies include:
|
||||||
|
|
||||||
|
| Policy | Mode | Description |
|
||||||
|
|--------|------|-------------|
|
||||||
|
| `disallow-privileged` | Enforce | Blocks privileged containers |
|
||||||
|
| `require-resource-limits` | Enforce | Requires CPU/memory limits |
|
||||||
|
| `require-labels` | Audit | Standard labeling for workloads |
|
||||||
|
| `require-non-root` | Audit | Non-root container requirement |
|
||||||
|
| `disallow-latest-tag` | Enforce | Requires explicit image tags |
|
||||||
|
| `add-default-securitycontext` | Mutate | Adds secure defaults automatically |
|
||||||
|
|
||||||
|
Policies in **Audit** mode generate reports without blocking. Promote to **Enforce** after validating existing workloads.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check policy reports
|
||||||
|
kubectl get policyreports -A
|
||||||
|
kubectl get clusterpolicyreports
|
||||||
|
```
|
||||||
|
|
||||||
## Secrets Management
|
## Secrets Management
|
||||||
|
|
||||||
Encrypted with **SOPS + age**. Configuration in `.sops.yaml`.
|
Encrypted with **SOPS + age**. Configuration in `.sops.yaml`.
|
||||||
|
|||||||
62
infrastructure/kyverno/kustomization.yaml
Normal file
62
infrastructure/kyverno/kustomization.yaml
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
# infrastructure/kyverno/kustomization.yaml
|
||||||
|
# Kyverno Policy Engine - GitOps-native Kubernetes policy enforcement
|
||||||
|
# CNCF Graduated project, integrates seamlessly with ArgoCD
|
||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
|
||||||
|
namespace: kyverno
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- namespace.yaml
|
||||||
|
- policies/
|
||||||
|
|
||||||
|
# Kyverno deployment via Helm
|
||||||
|
helmCharts:
|
||||||
|
- name: kyverno
|
||||||
|
repo: https://kyverno.github.io/kyverno/
|
||||||
|
version: "3.3.4"
|
||||||
|
releaseName: kyverno
|
||||||
|
namespace: kyverno
|
||||||
|
valuesInline:
|
||||||
|
# Admission controller replicas for HA
|
||||||
|
admissionController:
|
||||||
|
replicas: 3
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 512Mi
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 256Mi
|
||||||
|
# Background controller for generate/mutate policies
|
||||||
|
backgroundController:
|
||||||
|
replicas: 2
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 256Mi
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 128Mi
|
||||||
|
# Reports controller for policy reports
|
||||||
|
reportsController:
|
||||||
|
replicas: 2
|
||||||
|
# Cleanup controller
|
||||||
|
cleanupController:
|
||||||
|
replicas: 2
|
||||||
|
# Enable policy exception support
|
||||||
|
features:
|
||||||
|
policyExceptions:
|
||||||
|
enabled: true
|
||||||
|
namespace: "kyverno"
|
||||||
|
# Webhooks config
|
||||||
|
config:
|
||||||
|
webhooks:
|
||||||
|
# Exclude system namespaces from validation
|
||||||
|
- namespaceSelector:
|
||||||
|
matchExpressions:
|
||||||
|
- key: kubernetes.io/metadata.name
|
||||||
|
operator: NotIn
|
||||||
|
values:
|
||||||
|
- kube-system
|
||||||
|
- kube-public
|
||||||
|
- kube-node-lease
|
||||||
|
- kyverno
|
||||||
10
infrastructure/kyverno/namespace.yaml
Normal file
10
infrastructure/kyverno/namespace.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# infrastructure/kyverno/namespace.yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: kyverno
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: kyverno
|
||||||
|
app.kubernetes.io/component: policy-engine
|
||||||
|
# Exempt from Pod Security Standards (Kyverno needs privileges)
|
||||||
|
pod-security.kubernetes.io/enforce: privileged
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
# infrastructure/kyverno/policies/add-default-securitycontext.yaml
|
||||||
|
# Mutating policy: adds secure defaults to pods missing securityContext
|
||||||
|
# Implements defense-in-depth by setting secure defaults
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: add-default-securitycontext
|
||||||
|
annotations:
|
||||||
|
policies.kyverno.io/title: Add Default Security Context
|
||||||
|
policies.kyverno.io/category: Best Practices
|
||||||
|
policies.kyverno.io/severity: low
|
||||||
|
policies.kyverno.io/subject: Pod
|
||||||
|
policies.kyverno.io/description: >-
|
||||||
|
Mutating policy that adds secure default securityContext to pods
|
||||||
|
that don't specify one. Reduces attack surface by dropping
|
||||||
|
capabilities and making filesystem read-only where possible.
|
||||||
|
pod-policies.kyverno.io/autogen-controllers: DaemonSet,Deployment,Job,StatefulSet,ReplicaSet
|
||||||
|
spec:
|
||||||
|
# Mutate rules apply during admission
|
||||||
|
rules:
|
||||||
|
- name: add-pod-security-context
|
||||||
|
match:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
kinds:
|
||||||
|
- Pod
|
||||||
|
exclude:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
namespaces:
|
||||||
|
- kube-system
|
||||||
|
- kyverno
|
||||||
|
- istio-system
|
||||||
|
mutate:
|
||||||
|
patchStrategicMerge:
|
||||||
|
spec:
|
||||||
|
# Add pod-level securityContext if missing
|
||||||
|
+(securityContext):
|
||||||
|
seccompProfile:
|
||||||
|
type: RuntimeDefault
|
||||||
|
# Don't allow privilege escalation by default
|
||||||
|
runAsNonRoot: true
|
||||||
|
- name: add-container-security-context
|
||||||
|
match:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
kinds:
|
||||||
|
- Pod
|
||||||
|
exclude:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
namespaces:
|
||||||
|
- kube-system
|
||||||
|
- kyverno
|
||||||
|
- istio-system
|
||||||
|
mutate:
|
||||||
|
foreach:
|
||||||
|
- list: "request.object.spec.containers"
|
||||||
|
patchStrategicMerge:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: "{{ element.name }}"
|
||||||
|
+(securityContext):
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
60
infrastructure/kyverno/policies/disallow-latest-tag.yaml
Normal file
60
infrastructure/kyverno/policies/disallow-latest-tag.yaml
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
# infrastructure/kyverno/policies/disallow-latest-tag.yaml
|
||||||
|
# Prevents use of 'latest' image tag for reproducibility
|
||||||
|
# GitOps best practice: always use explicit image versions
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: disallow-latest-tag
|
||||||
|
annotations:
|
||||||
|
policies.kyverno.io/title: Disallow Latest Tag
|
||||||
|
policies.kyverno.io/category: Best Practices
|
||||||
|
policies.kyverno.io/severity: medium
|
||||||
|
policies.kyverno.io/subject: Pod
|
||||||
|
policies.kyverno.io/description: >-
|
||||||
|
The 'latest' tag is mutable and can change unexpectedly, making
|
||||||
|
deployments non-reproducible. This policy requires explicit
|
||||||
|
image tags for GitOps traceability.
|
||||||
|
spec:
|
||||||
|
validationFailureAction: Enforce
|
||||||
|
background: true
|
||||||
|
rules:
|
||||||
|
- name: require-image-tag
|
||||||
|
match:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
kinds:
|
||||||
|
- Pod
|
||||||
|
exclude:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
namespaces:
|
||||||
|
- kube-system
|
||||||
|
- kyverno
|
||||||
|
validate:
|
||||||
|
message: "Images must use an explicit tag (not 'latest'). Specify a version tag like ':v1.2.3' or SHA digest."
|
||||||
|
pattern:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: "*:*"
|
||||||
|
=(initContainers):
|
||||||
|
- image: "*:*"
|
||||||
|
- name: validate-not-latest
|
||||||
|
match:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
kinds:
|
||||||
|
- Pod
|
||||||
|
exclude:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
namespaces:
|
||||||
|
- kube-system
|
||||||
|
- kyverno
|
||||||
|
validate:
|
||||||
|
message: "The 'latest' tag is not allowed. Use a specific version tag."
|
||||||
|
pattern:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: "!*:latest"
|
||||||
|
=(initContainers):
|
||||||
|
- image: "!*:latest"
|
||||||
47
infrastructure/kyverno/policies/disallow-privileged.yaml
Normal file
47
infrastructure/kyverno/policies/disallow-privileged.yaml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# infrastructure/kyverno/policies/disallow-privileged.yaml
|
||||||
|
# Prevents pods from running as privileged containers
|
||||||
|
# Security baseline: CIS Benchmark 5.2.1
|
||||||
|
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 Standards (Baseline)
|
||||||
|
policies.kyverno.io/severity: high
|
||||||
|
policies.kyverno.io/subject: Pod
|
||||||
|
policies.kyverno.io/description: >-
|
||||||
|
Privileged containers have all Linux capabilities and can access
|
||||||
|
host resources. This policy prevents privileged containers from
|
||||||
|
being created except in system namespaces.
|
||||||
|
spec:
|
||||||
|
validationFailureAction: Enforce
|
||||||
|
background: true
|
||||||
|
rules:
|
||||||
|
- name: privileged-containers
|
||||||
|
match:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
kinds:
|
||||||
|
- Pod
|
||||||
|
exclude:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
namespaces:
|
||||||
|
- kube-system
|
||||||
|
- kyverno
|
||||||
|
- istio-system
|
||||||
|
- cert-manager
|
||||||
|
validate:
|
||||||
|
message: "Privileged containers are not allowed. Set securityContext.privileged to false."
|
||||||
|
pattern:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- securityContext:
|
||||||
|
privileged: "false"
|
||||||
|
=(initContainers):
|
||||||
|
- securityContext:
|
||||||
|
privileged: "false"
|
||||||
|
=(ephemeralContainers):
|
||||||
|
- securityContext:
|
||||||
|
privileged: "false"
|
||||||
12
infrastructure/kyverno/policies/kustomization.yaml
Normal file
12
infrastructure/kyverno/policies/kustomization.yaml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# infrastructure/kyverno/policies/kustomization.yaml
|
||||||
|
# Security policies for cluster-wide enforcement
|
||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- disallow-privileged.yaml
|
||||||
|
- require-resource-limits.yaml
|
||||||
|
- require-labels.yaml
|
||||||
|
- require-non-root.yaml
|
||||||
|
- disallow-latest-tag.yaml
|
||||||
|
- add-default-securitycontext.yaml
|
||||||
69
infrastructure/kyverno/policies/require-labels.yaml
Normal file
69
infrastructure/kyverno/policies/require-labels.yaml
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
# infrastructure/kyverno/policies/require-labels.yaml
|
||||||
|
# Enforces standard labeling for all workloads
|
||||||
|
# Enables proper resource organization and cost tracking
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: require-labels
|
||||||
|
annotations:
|
||||||
|
policies.kyverno.io/title: Require Labels
|
||||||
|
policies.kyverno.io/category: Best Practices
|
||||||
|
policies.kyverno.io/severity: medium
|
||||||
|
policies.kyverno.io/subject: Pod, Deployment, StatefulSet, DaemonSet
|
||||||
|
policies.kyverno.io/description: >-
|
||||||
|
Labels are essential for organizing, filtering, and managing
|
||||||
|
Kubernetes resources. This policy requires standard labels on
|
||||||
|
all workloads.
|
||||||
|
spec:
|
||||||
|
validationFailureAction: Audit # Start in audit mode
|
||||||
|
background: true
|
||||||
|
rules:
|
||||||
|
- name: check-deployment-labels
|
||||||
|
match:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
kinds:
|
||||||
|
- Deployment
|
||||||
|
- StatefulSet
|
||||||
|
- DaemonSet
|
||||||
|
exclude:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
namespaces:
|
||||||
|
- kube-system
|
||||||
|
- kyverno
|
||||||
|
validate:
|
||||||
|
message: "Workloads must have 'app.kubernetes.io/name' and 'app.kubernetes.io/part-of' labels."
|
||||||
|
pattern:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: "?*"
|
||||||
|
app.kubernetes.io/part-of: "?*"
|
||||||
|
- name: check-pod-labels
|
||||||
|
match:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
kinds:
|
||||||
|
- Pod
|
||||||
|
exclude:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
namespaces:
|
||||||
|
- kube-system
|
||||||
|
- kyverno
|
||||||
|
# Exclude pods created by controllers (they inherit parent labels)
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/managed-by: "*"
|
||||||
|
preconditions:
|
||||||
|
all:
|
||||||
|
# Only check standalone pods (not owned by ReplicaSet, etc.)
|
||||||
|
- key: "{{ request.object.metadata.ownerReferences[] || `[]` | length(@) }}"
|
||||||
|
operator: Equals
|
||||||
|
value: 0
|
||||||
|
validate:
|
||||||
|
message: "Pods must have 'app.kubernetes.io/name' label."
|
||||||
|
pattern:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: "?*"
|
||||||
54
infrastructure/kyverno/policies/require-non-root.yaml
Normal file
54
infrastructure/kyverno/policies/require-non-root.yaml
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# infrastructure/kyverno/policies/require-non-root.yaml
|
||||||
|
# Requires containers to run as non-root user
|
||||||
|
# Security baseline: CIS Benchmark 5.2.6
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: require-run-as-non-root
|
||||||
|
annotations:
|
||||||
|
policies.kyverno.io/title: Require Run As Non-Root
|
||||||
|
policies.kyverno.io/category: Pod Security Standards (Restricted)
|
||||||
|
policies.kyverno.io/severity: high
|
||||||
|
policies.kyverno.io/subject: Pod
|
||||||
|
policies.kyverno.io/description: >-
|
||||||
|
Running as root inside a container is a security risk. If a
|
||||||
|
container breakout occurs, root in the container could become
|
||||||
|
root on the host. This policy requires containers to run as
|
||||||
|
a non-root user.
|
||||||
|
spec:
|
||||||
|
validationFailureAction: Audit # Audit first, Enforce after baseline
|
||||||
|
background: true
|
||||||
|
rules:
|
||||||
|
- name: run-as-non-root
|
||||||
|
match:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
kinds:
|
||||||
|
- Pod
|
||||||
|
exclude:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
namespaces:
|
||||||
|
- kube-system
|
||||||
|
- kyverno
|
||||||
|
- istio-system
|
||||||
|
validate:
|
||||||
|
message: "Containers must run as non-root. Set runAsNonRoot: true or specify a non-root runAsUser."
|
||||||
|
anyPattern:
|
||||||
|
# Pattern 1: Pod-level runAsNonRoot
|
||||||
|
- spec:
|
||||||
|
securityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
# Pattern 2: Container-level runAsNonRoot
|
||||||
|
- spec:
|
||||||
|
containers:
|
||||||
|
- securityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
# Pattern 3: Explicit non-root UID (>= 1000)
|
||||||
|
- spec:
|
||||||
|
securityContext:
|
||||||
|
runAsUser: ">999"
|
||||||
|
- spec:
|
||||||
|
containers:
|
||||||
|
- securityContext:
|
||||||
|
runAsUser: ">999"
|
||||||
41
infrastructure/kyverno/policies/require-resource-limits.yaml
Normal file
41
infrastructure/kyverno/policies/require-resource-limits.yaml
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# infrastructure/kyverno/policies/require-resource-limits.yaml
|
||||||
|
# Ensures all pods have resource limits defined
|
||||||
|
# Prevents resource exhaustion and enables proper scheduling
|
||||||
|
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/severity: medium
|
||||||
|
policies.kyverno.io/subject: Pod
|
||||||
|
policies.kyverno.io/description: >-
|
||||||
|
Resource limits prevent a single workload from consuming excessive
|
||||||
|
cluster resources. This policy requires all containers to define
|
||||||
|
CPU and memory limits.
|
||||||
|
spec:
|
||||||
|
validationFailureAction: Enforce
|
||||||
|
background: true
|
||||||
|
rules:
|
||||||
|
- name: validate-resources
|
||||||
|
match:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
kinds:
|
||||||
|
- Pod
|
||||||
|
exclude:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
namespaces:
|
||||||
|
- kube-system
|
||||||
|
- kyverno
|
||||||
|
validate:
|
||||||
|
message: "CPU and memory limits are required. Add resources.limits.cpu and resources.limits.memory."
|
||||||
|
pattern:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- resources:
|
||||||
|
limits:
|
||||||
|
memory: "?*"
|
||||||
|
cpu: "?*"
|
||||||
Reference in New Issue
Block a user