Add Kyverno admission policies and CIS mappings
Kube-bench CIS scan / Scan ephemeral K3s cluster (push) Failing after 3m11s
Kube-bench CIS scan / Scan ephemeral K3s cluster (push) Failing after 3m11s
This commit is contained in:
@@ -34,7 +34,7 @@ It is not needed for the portfolio demo and is not run in CI.
|
|||||||
- [ ] Phase 2: ArgoCD app-of-apps deployment (scaffolded; runtime verification pending)
|
- [ ] Phase 2: ArgoCD app-of-apps deployment (scaffolded; runtime verification pending)
|
||||||
- [x] Phase 3: kube-bench CI scan
|
- [x] Phase 3: kube-bench CI scan
|
||||||
- [ ] Architecture revision: Flatcar hosts and Cilium kube-proxy replacement (configured; runtime verification pending)
|
- [ ] Architecture revision: Flatcar hosts and Cilium kube-proxy replacement (configured; runtime verification pending)
|
||||||
- [ ] Phase 4: Kyverno policy set and CIS mapping
|
- [ ] Phase 4: Kyverno policy set and CIS mapping (configured; runtime verification pending)
|
||||||
- [ ] Phase 5: Falco rules and webhook alerting
|
- [ ] Phase 5: Falco rules and webhook alerting
|
||||||
- [ ] Phase 6: test workloads and evidence capture
|
- [ ] Phase 6: test workloads and evidence capture
|
||||||
- [ ] Phase 7: architecture/design documentation
|
- [ ] Phase 7: architecture/design documentation
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# CIS control to Kyverno mapping
|
||||||
|
|
||||||
|
The policy set is scoped to namespaces carrying the
|
||||||
|
`security-baseline/open: "true"` label. This makes the local demo predictable
|
||||||
|
and avoids applying workload admission rules to platform namespaces.
|
||||||
|
|
||||||
|
| CIS control | Policy | What the demo proves | Boundary |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 5.2.2 | `disallow-privileged` | A Pod with `privileged: true` is rejected. | Does not replace host hardening or Linux capability review. |
|
||||||
|
| 5.2.3 | `disallow-host-network` | A Pod with `hostPID: true` is rejected. | Does not cover every host namespace or hostPath risk. |
|
||||||
|
| 5.2.5 | `disallow-host-network` | A Pod with `hostNetwork: true` is rejected. | Does not replace network policy. |
|
||||||
|
| 5.2.7 | `require-non-root` | A Pod without explicit non-root execution is rejected. | Does not prove the image cannot switch users internally. |
|
||||||
|
| 5.5.1 | `restrict-image-registries` | Images outside the approved registry set are rejected. | Full provenance needs signing, verification, and trusted build controls. |
|
||||||
|
| 5.7.3 supplemental | `require-resource-limits` | Pods must declare CPU and memory limits. | Resource limits are a defense-in-depth control, not a direct CIS test. |
|
||||||
|
|
||||||
|
The Kubernetes CIS Benchmark is broader than admission policy. kube-bench
|
||||||
|
covers node, control-plane, RBAC, audit, network policy, and manual review
|
||||||
|
areas that these Kyverno policies do not implement.
|
||||||
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# Kyverno policy baseline
|
||||||
|
|
||||||
|
These policies are `ClusterPolicy` resources, but they intentionally select
|
||||||
|
only namespaces labeled `security-baseline/open: "true"`. That keeps the
|
||||||
|
portfolio demo enforceable without blocking Kyverno, Falco, ArgoCD, or other
|
||||||
|
platform components. Expand the label scope deliberately for a real cluster.
|
||||||
|
|
||||||
|
All five policies use `validationFailureAction: Enforce`, so a matching Pod is
|
||||||
|
rejected at admission time. The policies use `background: false` because the
|
||||||
|
goal is to demonstrate admission enforcement, not retroactively evaluate
|
||||||
|
existing objects.
|
||||||
|
|
||||||
|
| Policy | CIS alignment | Enforcement |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `disallow-privileged` | 5.2.2 | Rejects privileged containers and init containers. |
|
||||||
|
| `require-non-root` | 5.2.7 | Requires `runAsNonRoot: true` on containers and init containers. |
|
||||||
|
| `require-resource-limits` | 5.7.3 supplemental | Requires CPU and memory limits. This is a supplemental control, not a one-to-one CIS test. |
|
||||||
|
| `restrict-image-registries` | 5.5.1 supplemental | Allows only approved registries. Full image provenance requires signing and verification as well. |
|
||||||
|
| `disallow-host-network` | 5.2.3 and 5.2.5 | Rejects host PID, host network, and host IPC access. |
|
||||||
|
|
||||||
|
The CIS benchmark includes manual checks and platform-specific exceptions.
|
||||||
|
The mapping above describes the control objective each policy supports, not a
|
||||||
|
claim that one Kyverno rule implements the entire benchmark control.
|
||||||
|
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: disallow-host-network
|
||||||
|
annotations:
|
||||||
|
policies.kyverno.io/title: Disallow host network and host PID
|
||||||
|
policies.kyverno.io/category: Pod Security Standards
|
||||||
|
policies.kyverno.io/severity: high
|
||||||
|
# CIS 5.2.3: minimize hostPID; CIS 5.2.5: minimize hostNetwork.
|
||||||
|
policies.kyverno.io/cis-control: "5.2.3, 5.2.5"
|
||||||
|
spec:
|
||||||
|
validationFailureAction: Enforce
|
||||||
|
background: false
|
||||||
|
failurePolicy: Fail
|
||||||
|
rules:
|
||||||
|
- name: no-host-network-or-pid
|
||||||
|
match:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
kinds:
|
||||||
|
- Pod
|
||||||
|
namespaceSelector:
|
||||||
|
matchLabels:
|
||||||
|
security-baseline/open: "true"
|
||||||
|
validate:
|
||||||
|
message: hostNetwork, hostPID, and hostIPC must be false or omitted.
|
||||||
|
pattern:
|
||||||
|
spec:
|
||||||
|
=(hostNetwork): false
|
||||||
|
=(hostPID): false
|
||||||
|
=(hostIPC): false
|
||||||
|
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: disallow-privileged
|
||||||
|
annotations:
|
||||||
|
policies.kyverno.io/title: Disallow privileged containers
|
||||||
|
policies.kyverno.io/category: Pod Security Standards
|
||||||
|
policies.kyverno.io/severity: high
|
||||||
|
# CIS 5.2.2: minimize admission of privileged containers.
|
||||||
|
policies.kyverno.io/cis-control: "5.2.2"
|
||||||
|
spec:
|
||||||
|
validationFailureAction: Enforce
|
||||||
|
background: false
|
||||||
|
failurePolicy: Fail
|
||||||
|
rules:
|
||||||
|
- name: privileged-containers
|
||||||
|
match:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
kinds:
|
||||||
|
- Pod
|
||||||
|
namespaceSelector:
|
||||||
|
matchLabels:
|
||||||
|
security-baseline/open: "true"
|
||||||
|
validate:
|
||||||
|
message: Privileged containers are not allowed in security-baseline namespaces.
|
||||||
|
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
|
||||||
|
|
||||||
@@ -2,5 +2,8 @@ apiVersion: kustomize.config.k8s.io/v1beta1
|
|||||||
kind: Kustomization
|
kind: Kustomization
|
||||||
resources:
|
resources:
|
||||||
- namespace.yaml
|
- namespace.yaml
|
||||||
- phase-2-placeholder.yaml
|
- disallow-privileged.yaml
|
||||||
|
- require-non-root.yaml
|
||||||
|
- require-resource-limits.yaml
|
||||||
|
- restrict-image-registries.yaml
|
||||||
|
- disallow-host-network.yaml
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: ConfigMap
|
|
||||||
metadata:
|
|
||||||
name: policy-baseline-status
|
|
||||||
namespace: security-baseline
|
|
||||||
data:
|
|
||||||
phase: "2"
|
|
||||||
status: "GitOps target established; Kyverno policies arrive in phase 4"
|
|
||||||
|
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
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 Standards
|
||||||
|
policies.kyverno.io/severity: high
|
||||||
|
# CIS 5.2.7: minimize admission of root containers.
|
||||||
|
policies.kyverno.io/cis-control: "5.2.7"
|
||||||
|
spec:
|
||||||
|
validationFailureAction: Enforce
|
||||||
|
background: false
|
||||||
|
failurePolicy: Fail
|
||||||
|
rules:
|
||||||
|
- name: containers-run-as-non-root
|
||||||
|
match:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
kinds:
|
||||||
|
- Pod
|
||||||
|
namespaceSelector:
|
||||||
|
matchLabels:
|
||||||
|
security-baseline/open: "true"
|
||||||
|
validate:
|
||||||
|
message: Containers must explicitly set runAsNonRoot=true.
|
||||||
|
foreach:
|
||||||
|
- list: request.object.spec.containers[]
|
||||||
|
deny:
|
||||||
|
conditions:
|
||||||
|
any:
|
||||||
|
- key: "{{ element.securityContext.runAsNonRoot || false }}"
|
||||||
|
operator: Equals
|
||||||
|
value: false
|
||||||
|
- list: request.object.spec.initContainers[]
|
||||||
|
deny:
|
||||||
|
conditions:
|
||||||
|
any:
|
||||||
|
- key: "{{ element.securityContext.runAsNonRoot || false }}"
|
||||||
|
operator: Equals
|
||||||
|
value: false
|
||||||
|
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: require-resource-limits
|
||||||
|
annotations:
|
||||||
|
policies.kyverno.io/title: Require CPU and memory limits
|
||||||
|
policies.kyverno.io/category: Resource governance
|
||||||
|
policies.kyverno.io/severity: medium
|
||||||
|
# Supplemental hardening aligned with CIS 5.7.3 workload controls. The
|
||||||
|
# CIS benchmark does not define a one-to-one resource-limit test.
|
||||||
|
policies.kyverno.io/cis-control: "5.7.3 supplemental"
|
||||||
|
spec:
|
||||||
|
validationFailureAction: Enforce
|
||||||
|
background: false
|
||||||
|
failurePolicy: Fail
|
||||||
|
rules:
|
||||||
|
- name: containers-have-resource-limits
|
||||||
|
match:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
kinds:
|
||||||
|
- Pod
|
||||||
|
namespaceSelector:
|
||||||
|
matchLabels:
|
||||||
|
security-baseline/open: "true"
|
||||||
|
validate:
|
||||||
|
message: Every container must define CPU and memory limits.
|
||||||
|
foreach:
|
||||||
|
- list: request.object.spec.containers[]
|
||||||
|
deny:
|
||||||
|
conditions:
|
||||||
|
any:
|
||||||
|
- key: "{{ element.resources.limits.cpu || '' }}"
|
||||||
|
operator: Equals
|
||||||
|
value: ""
|
||||||
|
- key: "{{ element.resources.limits.memory || '' }}"
|
||||||
|
operator: Equals
|
||||||
|
value: ""
|
||||||
|
- list: request.object.spec.initContainers[]
|
||||||
|
deny:
|
||||||
|
conditions:
|
||||||
|
any:
|
||||||
|
- key: "{{ element.resources.limits.cpu || '' }}"
|
||||||
|
operator: Equals
|
||||||
|
value: ""
|
||||||
|
- key: "{{ element.resources.limits.memory || '' }}"
|
||||||
|
operator: Equals
|
||||||
|
value: ""
|
||||||
|
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: restrict-image-registries
|
||||||
|
annotations:
|
||||||
|
policies.kyverno.io/title: Restrict image registries
|
||||||
|
policies.kyverno.io/category: Supply chain
|
||||||
|
policies.kyverno.io/severity: high
|
||||||
|
# CIS 5.5.1: image provenance. This is a concrete admission control that
|
||||||
|
# supports the broader provenance objective but is not the full CIS test.
|
||||||
|
policies.kyverno.io/cis-control: "5.5.1 supplemental"
|
||||||
|
spec:
|
||||||
|
validationFailureAction: Enforce
|
||||||
|
background: false
|
||||||
|
failurePolicy: Fail
|
||||||
|
rules:
|
||||||
|
- name: images-from-approved-registries
|
||||||
|
match:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
kinds:
|
||||||
|
- Pod
|
||||||
|
namespaceSelector:
|
||||||
|
matchLabels:
|
||||||
|
security-baseline/open: "true"
|
||||||
|
validate:
|
||||||
|
message: Images must come from ghcr.io, quay.io, or docker.io/library.
|
||||||
|
foreach:
|
||||||
|
- list: request.object.spec.containers[]
|
||||||
|
anyPattern:
|
||||||
|
- image: ghcr.io/*
|
||||||
|
- image: quay.io/*
|
||||||
|
- image: docker.io/library/*
|
||||||
|
- list: request.object.spec.initContainers[]
|
||||||
|
anyPattern:
|
||||||
|
- image: ghcr.io/*
|
||||||
|
- image: quay.io/*
|
||||||
|
- image: docker.io/library/*
|
||||||
|
|
||||||
Reference in New Issue
Block a user