Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .github/kyverno/exceptions/kates-chaos-litmus.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Why: litmus-core, the upstream LitmusChaos chart kates-chaos wraps, renders
# its chaos operator (and, with litmus-core.exporter.enabled, its exporter)
# with no securityContext and takes none from values, so neither pod can set
# seccomp, runAsNonRoot, allowPrivilegeEscalation or drop capabilities. Exactly
# those four controls are excepted, for those two images only; every other
# control of pss-restricted, and the other policies, still apply to them.
# Removed by: litmus-core.enabled=false on charts/kates-chaos (no chaos
# operator: Kates then cannot run Litmus faults), or by a litmus-core release
# that takes a securityContext. A cluster that enforces the profile exempts
# them with the chart's own kyvernoPolicy.exceptions instead.
# Names the Deployments and their pods as scripts/check-chart-policies.sh
# renders them: release kates-chaos in namespace kates-chaos (the operator's
# name is litmus-core's fullname, litmus, whatever the release is called).
apiVersion: kyverno.io/v2
kind: PolicyException
metadata:
name: kates-chaos-litmus
namespace: kates-chaos
spec:
exceptions:
- policyName: pss-restricted
ruleNames: [restricted, autogen-restricted]
match:
any:
- resources:
kinds: [Deployment]
namespaces: [kates-chaos]
names: [litmus, litmus-monitor]
- resources:
kinds: [Pod]
namespaces: [kates-chaos]
names: ["litmus-*-?????", "litmus-monitor-*-?????"]
podSecurity:
- controlName: Privilege Escalation
images: ["*litmuschaos/chaos-operator:*", "*litmuschaos/chaos-exporter:*"]
- controlName: Capabilities
images: ["*litmuschaos/chaos-operator:*", "*litmuschaos/chaos-exporter:*"]
- controlName: Running as Non-root
images: ["*litmuschaos/chaos-operator:*", "*litmuschaos/chaos-exporter:*"]
- controlName: Seccomp
images: ["*litmuschaos/chaos-operator:*", "*litmuschaos/chaos-exporter:*"]
36 changes: 36 additions & 0 deletions .github/kyverno/exceptions/monitoring-node-exporter.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Why: the node exporter reports the node, not itself. It reads the host's
# /proc, /sys and root filesystem through hostPath volumes and joins the host's
# network and PID namespaces, and a pod on the host network gets its container
# port as a host port. No value of the chart makes that pass the restricted
# profile, so exactly those four controls are excepted; every other control of
# pss-restricted, and the other policies, still apply to it.
# Removed by: kube-prometheus-stack.nodeExporter.enabled=false on charts/monitoring
# (the cluster then has no node metrics).
# Names the DaemonSet and its pods as scripts/check-chart-policies.sh renders
# them: release monitoring in namespace monitoring. On a cluster, install it
# where the release runs and edit the names if the release is called otherwise.
apiVersion: kyverno.io/v2
kind: PolicyException
metadata:
name: monitoring-node-exporter
namespace: monitoring
spec:
exceptions:
- policyName: pss-restricted
ruleNames: [restricted, autogen-restricted]
match:
any:
- resources:
kinds: [DaemonSet]
namespaces: [monitoring]
names: [monitoring-prometheus-node-exporter]
- resources:
kinds: [Pod]
namespaces: [monitoring]
names: ["monitoring-prometheus-node-exporter-?????"]
podSecurity:
- controlName: Host Namespaces
- controlName: HostPath Volumes
- controlName: Volume Types
- controlName: Host Ports
images: ["*prometheus/node-exporter:*"]
44 changes: 44 additions & 0 deletions .github/kyverno/exceptions/velero-node-agent.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Why: the node agent backs pod volumes up from the node itself. It reads them
# through hostPath mounts of /var/lib/kubelet/pods and /var/lib/kubelet/plugins,
# and runs as root (uid 0) with the runtime's default capabilities, which it
# needs to read, and on restore write and chown, files whatever user owns
# them: dropping ALL would leave it a root that cannot. Its container security
# context is empty, as upstream ships it, so it does not forbid privilege
# escalation either (a default of false would clash with privileged: true).
# No value of the chart makes that pass the restricted profile, so exactly
# those controls are excepted; every other control of pss-restricted
# (seccomp, ...), and the other policies, still apply to it.
# Removed by: deployNodeAgent=false on charts/velero, the default (file-system
# backups and the CSI data mover then do not run).
# Names the DaemonSet and its pods as scripts/check-chart-policies.sh renders
# them: release velero in namespace velero. On a cluster, install it where the
# release runs.
apiVersion: kyverno.io/v2
kind: PolicyException
metadata:
name: velero-node-agent
namespace: velero
spec:
exceptions:
- policyName: pss-restricted
ruleNames: [restricted, autogen-restricted]
match:
any:
- resources:
kinds: [DaemonSet]
namespaces: [velero]
names: [node-agent]
- resources:
kinds: [Pod]
namespaces: [velero]
names: ["node-agent-?????"]
podSecurity:
- controlName: HostPath Volumes
- controlName: Volume Types
- controlName: Running as Non-root
images: ["*velero/velero:*"]
- controlName: Running as Non-root user
- controlName: Capabilities
images: ["*velero/velero:*"]
- controlName: Privilege Escalation
images: ["*velero/velero:*"]
35 changes: 35 additions & 0 deletions .github/kyverno/policies/disallow-latest-tag.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Every image names a tag or a digest, and the tag is not latest.
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-latest-tag
spec:
validationFailureAction: Enforce
background: true
rules:
- name: require-tag
match:
any:
- resources:
kinds: [Pod]
validate:
message: "Every image needs an explicit tag or digest."
pattern:
spec:
=(initContainers):
- image: "*:* | *@*"
containers:
- image: "*:* | *@*"
- name: no-latest
match:
any:
- resources:
kinds: [Pod]
validate:
message: "The latest tag is not allowed."
pattern:
spec:
=(initContainers):
- image: "!*:latest"
containers:
- image: "!*:latest"
20 changes: 20 additions & 0 deletions .github/kyverno/policies/pss-restricted.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# The Pod Security Standards "restricted" profile, as Kyverno evaluates it.
# scripts/check-chart-policies.sh holds every chart under charts/ to it; the
# workloads that cannot pass are named one by one in ../exceptions/.
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: pss-restricted
spec:
validationFailureAction: Enforce
background: true
rules:
- name: restricted
match:
any:
- resources:
kinds: [Pod]
validate:
podSecurity:
level: restricted
version: latest
25 changes: 25 additions & 0 deletions .github/kyverno/policies/require-pod-labels.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# A sample of a cluster's own labelling rule: every Pod carries a team label.
# The charts set no such label; a cluster that requires one sets it through
# each chart's podLabels value (and a wrapped subchart's own label keys), and
# scripts/check-chart-policies.sh sets team=ci through them in every render it
# makes to prove they reach every pod the chart renders, helm tests and jobs
# included.
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-pod-labels
spec:
validationFailureAction: Enforce
background: true
rules:
- name: require-team-label
match:
any:
- resources:
kinds: [Pod]
validate:
message: "Every Pod needs the label team (set it through the chart's podLabels value)."
pattern:
metadata:
labels:
team: "?*"
34 changes: 34 additions & 0 deletions .github/kyverno/policies/require-requests-limits.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# CPU and memory requests and a memory limit on every container and init
# container. No CPU limit is required: one throttles a pod even when the node
# has CPU to spare.
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-requests-limits
spec:
validationFailureAction: Enforce
background: true
rules:
- name: requests-and-memory-limit
match:
any:
- resources:
kinds: [Pod]
validate:
message: "Every container and init container needs CPU and memory requests and a memory limit."
pattern:
spec:
=(initContainers):
- resources:
requests:
memory: "?*"
cpu: "?*"
limits:
memory: "?*"
containers:
- resources:
requests:
memory: "?*"
cpu: "?*"
limits:
memory: "?*"
93 changes: 46 additions & 47 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ jobs:
helm:
- 'charts/**'
- 'versions.env'
- '.github/kyverno/**'
- 'scripts/check-chart-policies.sh'
- 'scripts/check-versions.sh'
# check-versions.sh now also asserts the kind node image tags in
# this file against versions.env, so editing it has to run it.
Expand Down Expand Up @@ -500,57 +502,54 @@ jobs:
with:
kyverno: "true"

# kates-chaos depends on litmus-core from the LitmusChaos repo. Only the
# Helm Lint job added the repo, so `helm dependency build
# charts/kates-chaos/` in the last step of this job died with "no
# repository definition for https://litmuschaos.github.io/litmus-helm/"
# — every run of this job that got that far was red.
# Every chart with dependencies from a repository. The Helm repositories
# (litmus-core, kube-prometheus-stack, seaweedfs) are added here;
# Strimzi's operator chart is an OCI chart and needs none. Not
# kates-platform: its Chart.lock pins its file:// subcharts' versions and
# is stale after any bump of one, so `helm dependency build` refuses it.
# The script updates it in a copy, after the subcharts, and builds no
# chart this step left current, so nothing is downloaded twice.
- name: Fetch chart dependencies
uses: ./.github/actions/helm-deps
with:
charts: kates kafka-cluster kates-chaos

- name: Validate kates policies
run: |
helm template kates charts/kates/ \
--set kyvernoPolicy.enabled=true \
--api-versions kyverno.io/v1 \
--show-only templates/kyverno-policies.yaml \
> /tmp/kates-policies.yaml
echo "--- Rendered kates policies ---"
head -5 /tmp/kates-policies.yaml
# `|| true` used to follow this: the step could not fail, so the
# policies were rendered and never actually applied to anything as
# far as CI could tell. The deployment manifest is meant to pass.
kyverno apply /tmp/kates-policies.yaml \
--resource kates/k8s/deployment.yaml

- name: Validate kates workload policies
run: |
helm template kates charts/kates/ \
--set kyvernoPolicy.enabled=true \
--api-versions kyverno.io/v1 \
--show-only templates/kyverno-policies.yaml \
> /tmp/kates-workload-policies.yaml
echo "✅ Kates workload policies render successfully"

- name: Validate kafka policies
charts: connect-cluster kafka-cluster kates-chaos mirror-maker2 monitoring strimzi-operator

# Every chart, with its defaults and with its optional workloads on, held
# to PSS restricted, requests and a memory limit, and pinned images, with
# only the host-level workloads in .github/kyverno/exceptions/ excepted.
- name: Check charts against the cluster policies
run: scripts/check-chart-policies.sh

# The policies kates, kafka-cluster and kates-chaos ship (kyvernoPolicy),
# applied to the workloads of the same render. They match the release
# namespace only, and Helm installs a template that names no namespace
# into it, so the workloads get it here: before, the kates step applied
# its policies to kates/k8s/deployment.yaml and matched nothing. A run
# where no rule matched anything fails too. yq ships on GitHub's Ubuntu
# runners.
- name: Apply each chart's own policies to its workloads
run: |
helm template kafka charts/kafka-cluster/ \
--set kyvernoPolicy.enabled=true \
--api-versions kyverno.io/v1 \
--show-only templates/kyverno-policy.yaml \
> /tmp/kafka-policies.yaml
echo "✅ Kafka policies render successfully"

- name: Validate chaos policies
run: |
helm template chaos charts/kates-chaos/ \
--set kyvernoPolicy.enabled=true \
--api-versions kyverno.io/v1 \
--show-only templates/kyverno-policies.yaml \
> /tmp/chaos-policies.yaml
echo "✅ Chaos policies render successfully"
rc=0
for chart in kates kafka-cluster kates-chaos; do
echo "==> ${chart}"
out="${RUNNER_TEMP}/${chart}"
if ! helm template "${chart}" "charts/${chart}" -n "${chart}" \
--set kyvernoPolicy.enabled=true --api-versions kyverno.io/v1 > "${out}.yaml"; then
rc=1; continue
fi
yq 'select(.kind == "ClusterPolicy" or .kind == "Policy")' "${out}.yaml" > "${out}-policies.yaml"
NS="${chart}" yq 'select(.kind == "Pod" or .kind == "Deployment" or .kind == "StatefulSet" or .kind == "DaemonSet" or .kind == "Job" or .kind == "CronJob")
| .metadata.namespace |= (. // strenv(NS))' "${out}.yaml" > "${out}-workloads.yaml"
# A directory: with more than one mutated resource the CLI writes one file each.
mkdir -p "${out}-mutated"
kyverno apply "${out}-policies.yaml" --resource "${out}-workloads.yaml" \
-o "${out}-mutated" > "${out}.log" 2>&1 || rc=1
cat "${out}.log"
if grep -q '^pass: 0, fail: 0,' "${out}.log"; then
echo "::error::${chart}: its own policies matched none of its workloads"; rc=1
fi
done
exit ${rc}

yaml-validation:
name: YAML Validation
Expand Down
28 changes: 14 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,20 +205,20 @@ When you install charts with Helm directly:
<!-- chart-table:start -->
| Chart | Version | App Version | Description |
|:------|:--------|:------------|:------------|
| [`apicurio-registry`](charts/apicurio-registry/) | 0.4.0 | 3.3.0 | Apicurio Registry, backed by the kafka-cluster chart (Strimzi) in this repository |
| [`connect-cluster`](charts/connect-cluster/) | 2.1.9 | 4.3.1 | A Helm chart for deploying Strimzi Kafka Connect clusters |
| [`headlamp`](charts/headlamp/) | 0.2.0 | 0.40.1 | Headlamp — Kubernetes Dashboard for cluster visualization and management |
| [`kafka-cluster`](charts/kafka-cluster/) | 1.0.11 | 4.3.1 | A Strimzi Kafka cluster in KRaft mode — node pools, topics, users, rebalancing, tiered storage, network policy and observability |
| [`kafka-common`](charts/kafka-common/) | 0.1.0 | | Library chart — the templates the Strimzi charts share (names and labels, rails, Kafka client authentication, the Connect worker spec, KafkaUser, secret sync, NetworkPolicy and monitoring fragments, the Grafana grid, the preflight probe) |
| [`kafka-ui`](charts/kafka-ui/) | 0.3.0 | v1.5.0 | A Helm chart for deploying Kafka UI (Kafbat) with Strimzi SCRAM-SHA-512 authentication |
| [`kates-chaos`](charts/kates-chaos/) | 2.2.1 | 3.28.0 | Kates Chaos Engineering — wraps the LitmusChaos execution plane (operator, exporter, CRDs) with Kafka-specific RBAC, experiment/engine templating, and monitoring |
| [`kates-platform`](charts/kates-platform/) | 0.8.2 | 1.0.0 | Umbrella chart for the full Kates platform — Kafka, Kates, and supporting infrastructure |
| [`kates`](charts/kates/) | 0.12.2 | 1.28.0 | Kates — Kafka Advanced Testing & Engineering Suite |
| [`legacy-kafka`](charts/legacy-kafka/) | 0.2.0 | 3.9.1 | A deliberately old Kafka (2.x on ZooKeeper, or 3.x on KRaft) to migrate FROM — the replication source that the pinned Strimzi release cannot deploy |
| [`mirror-maker2`](charts/mirror-maker2/) | 0.11.7 | 4.3.1 | Strimzi KafkaMirrorMaker2 — cross-cluster replication, DR, and cross-version migration (2.x/3.x → 4.x) |
| [`monitoring`](charts/monitoring/) | 1.6.0 | 82.4.3 | Kates Monitoring — wraps kube-prometheus-stack with Kates-specific dashboards and configuration |
| [`strimzi-operator`](charts/strimzi-operator/) | 0.3.7 | 1.2.0 | The Strimzi Kafka Operator — wraps the upstream chart with pinned kates defaults, an owned CRD-upgrade hook, and a strict values schema |
| [`velero`](charts/velero/) | 11.3.3 | 1.17.1 | A Helm chart for velero |
| [`apicurio-registry`](charts/apicurio-registry/) | 0.4.1 | 3.3.0 | Apicurio Registry, backed by the kafka-cluster chart (Strimzi) in this repository |
| [`connect-cluster`](charts/connect-cluster/) | 2.1.10 | 4.3.1 | A Helm chart for deploying Strimzi Kafka Connect clusters |
| [`headlamp`](charts/headlamp/) | 0.2.1 | 0.40.1 | Headlamp — Kubernetes Dashboard for cluster visualization and management |
| [`kafka-cluster`](charts/kafka-cluster/) | 1.0.12 | 4.3.1 | A Strimzi Kafka cluster in KRaft mode — node pools, topics, users, rebalancing, tiered storage, network policy and observability |
| [`kafka-common`](charts/kafka-common/) | 0.1.1 | | Library chart — the templates the Strimzi charts share (names and labels, rails, Kafka client authentication, the Connect worker spec, KafkaUser, secret sync, NetworkPolicy and monitoring fragments, the Grafana grid, the preflight probe) |
| [`kafka-ui`](charts/kafka-ui/) | 0.3.1 | v1.5.0 | A Helm chart for deploying Kafka UI (Kafbat) with Strimzi SCRAM-SHA-512 authentication |
| [`kates-chaos`](charts/kates-chaos/) | 2.3.0 | 3.28.0 | Kates Chaos Engineering — wraps the LitmusChaos execution plane (operator, exporter, CRDs) with Kafka-specific RBAC, experiment/engine templating, and monitoring |
| [`kates-platform`](charts/kates-platform/) | 0.8.3 | 1.0.0 | Umbrella chart for the full Kates platform — Kafka, Kates, and supporting infrastructure |
| [`kates`](charts/kates/) | 0.13.0 | 1.28.0 | Kates — Kafka Advanced Testing & Engineering Suite |
| [`legacy-kafka`](charts/legacy-kafka/) | 0.2.1 | 3.9.1 | A deliberately old Kafka (2.x on ZooKeeper, or 3.x on KRaft) to migrate FROM — the replication source that the pinned Strimzi release cannot deploy |
| [`mirror-maker2`](charts/mirror-maker2/) | 0.11.8 | 4.3.1 | Strimzi KafkaMirrorMaker2 — cross-cluster replication, DR, and cross-version migration (2.x/3.x → 4.x) |
| [`monitoring`](charts/monitoring/) | 1.7.0 | 82.4.3 | Kates Monitoring — wraps kube-prometheus-stack with Kates-specific dashboards and configuration |
| [`strimzi-operator`](charts/strimzi-operator/) | 0.4.0 | 1.2.0 | The Strimzi Kafka Operator — wraps the upstream chart with pinned kates defaults, an owned CRD-upgrade hook, and a strict values schema |
| [`velero`](charts/velero/) | 11.3.4 | 1.17.1 | A Helm chart for velero |
<!-- chart-table:end -->

## Building from source
Expand Down
Loading
Loading