Repository navigation
feat(chart,conformity): rbac.scope=namespace runs tests and conformity checks without cluster admin - #439
Merged
Conversation
…-scoped An account with only edit in the release namespace can install the chart: no ClusterRole or ClusterRoleBinding, one read-only Role and RoleBinding in networkPolicy.kafka.namespace for conformity checks (rbac.kafkaNamespaceRole, default true), chaos on noop unless chaos.provider is set, and startup orphan recovery off. The default, rbac.scope=cluster, renders what 0.11.6 rendered.
…it may not read A refused get of the Kafka CR names the missing grant instead of "Kubernetes API not available" (still a 503). A refused all-namespace PodMonitor list falls back to the Kafka namespace's: PASS when one there selects every broker pod, otherwise UNKNOWN, since one elsewhere can't be ruled out. A refused node list says nodes are cluster-scoped. The CLI's caveat refs into charts/kates/values.yaml follow the new rbac lines.
…space An account with edit in its own namespace may not list Services with -A, so kates ports printed "No Kates services found". When -A is refused it now lists --app-ns and --kafka-ns instead.
A Deployment Guide section: who does what, the team's install with rbac.scope=namespace, the Kafka namespace's Role and the Kafka ACLs Kates needs, reaching the API with kates ports --app-ns, and what the scope trades away. The CLI Reference's ports entry and the conformity chapter's limits point at it. The chart CI step now refuses any cluster-scoped kind.
- A missing rbac.scope, as after helm upgrade --reuse-values from 0.11.6, keeps scope cluster; a missing rbac.kafkaNamespaceRole renders the Role. - With scope namespace the chart sets KATES_TOPOLOGY_KAFKA_NAMESPACE from networkPolicy.kafka.namespace, so the check reads where its Role is. - Orphan recovery stays on: its Kubernetes calls already tolerate a 403, and switching it off also skipped marking interrupted reports. - The CI step requires exactly four rules, each get or list, and checks a missing scope still renders the ClusterRole. - kates ports tries other namespaces only when the listing is forbidden, not when the cluster is unreachable. - Docs: who may create the Role (only an account holding those reads), the team's own SASL username and Secret, and the ACLs for kates-dlq and conformity topic rules. OpenAPI names the 503's second cause.
…e listed A namespace-scoped role may not list nodes, which are cluster-scoped, so zones, skew and kafka.rackAwareness (source cr) were UNKNOWN under rbac.scope=namespace. Strimzi's headless Service, <cluster>-kafka-brokers, selects every Kafka pod and publishes not-ready addresses, and the EndpointSlice controller copies each node's topology.kubernetes.io/zone onto its endpoints. When the node list is refused, the check reads the zones there; the rule's detail says so. Another zoneLabel stays UNKNOWN, since endpoints carry only that one. The Kafka-namespace Role grants list on endpointslices.
Captured on panda with this branch's image, installed as an account with only edit in its namespace: the reference passes with brokers.zones read from the EndpointSlices of kafka/krafter-kafka-brokers.
govulncheck in the Dependency CVE scan finds GO-2026-6809 in crypto/x509 of go1.27.2, reachable from detect.RenderHTML; go1.27.3 fixes it. The advisory is new and not this branch's change, but the scan blocks it.
Conflicts: the chart version (0.12.0 stays, above #440's 0.11.7), the version tables, and the CLI caveat refs into charts/kates/values.yaml, re-pointed to 408-418 and 618-686. #440 renders networkPolicy.kafka.namespace through tpl, so kates-platform can pass {{ .Release.Namespace }}; the Kafka-namespace Role and KATES_TOPOLOGY_KAFKA_NAMESPACE now use the same tpl, and the chart CI step checks a templated namespace.
bmscomp
added a commit
that referenced
this pull request
Oct 21, 2026
… Kafka namespace and cluster name (#441) The backend reads the Kafka cluster it acts on from kates.chaos.kafka.namespace and .cluster (chaos guard, orchestrator, orphan recovery, lease, Prometheus capture) and kates.topology.kafka-namespace and -cluster (topology, cluster alerts, conformity, CDC's fallback). Nothing set them, so they stayed at kafka/krafter. With `kates deploy --kafka-ns X` or `--kafka-name Y`, or kates-platform in any namespace but kafka, chaos refused every plan with "No broker pods found", topology came back empty and every conformity check returned 409. - kates 0.12.1: the configmap sets KATES_CHAOS_KAFKA_NAMESPACE and KATES_TOPOLOGY_KAFKA_NAMESPACE from networkPolicy.kafka.namespace, through tpl, with the policy on or off. It sets KATES_CHAOS_KAFKA_CLUSTER and KATES_TOPOLOGY_KAFKA_CLUSTER from a new kafka.clusterName (default krafter). The defaults are the backend's own, so a default render sets the same values as before. An extraEnv entry still wins over the configmap. The rbac.scope=namespace block that set KATES_TOPOLOGY_KAFKA_NAMESPACE (#439) goes: it rendered the same value, and would now be a duplicate key. - kates deploy sets kafka.clusterName from --kafka-name. It already set networkPolicy.kafka.namespace from the Kafka namespace. - kates-platform 0.8.2: the kates floor moves to 0.12.1, and the umbrella sets kates.kafka.clusterName (krafter) next to the bootstrap address, which names the same cluster. CI's kates-platform render check now also asserts both namespace variables. - MCP caveats dry-run-other-namespace and topology-unread-looks-empty say which chart values set these settings, with anchored refs to the configmap. Four refs into charts/kates are re-pointed past the added lines.
bmscomp
added a commit
that referenced
this pull request
Oct 21, 2026
…ster's namespace, wherever it is (#442) * fix(chart): the Kates API's chaos, topology and conformity follow the Kafka namespace and cluster name The backend reads the Kafka cluster it acts on from kates.chaos.kafka.namespace and .cluster (chaos guard, orchestrator, orphan recovery, lease, Prometheus capture) and kates.topology.kafka-namespace and -cluster (topology, cluster alerts, conformity, CDC's fallback). Nothing set them, so they stayed at kafka/krafter. With `kates deploy --kafka-ns X` or `--kafka-name Y`, or kates-platform in any namespace but kafka, chaos refused every plan with "No broker pods found", topology came back empty and every conformity check returned 409. - kates 0.12.1: the configmap sets KATES_CHAOS_KAFKA_NAMESPACE and KATES_TOPOLOGY_KAFKA_NAMESPACE from networkPolicy.kafka.namespace, through tpl, with the policy on or off. It sets KATES_CHAOS_KAFKA_CLUSTER and KATES_TOPOLOGY_KAFKA_CLUSTER from a new kafka.clusterName (default krafter). The defaults are the backend's own, so a default render sets the same values as before. An extraEnv entry still wins over the configmap. The rbac.scope=namespace block that set KATES_TOPOLOGY_KAFKA_NAMESPACE (#439) goes: it rendered the same value, and would now be a duplicate key. - kates deploy sets kafka.clusterName from --kafka-name. It already set networkPolicy.kafka.namespace from the Kafka namespace. - kates-platform 0.8.2: the kates floor moves to 0.12.1, and the umbrella sets kates.kafka.clusterName (krafter) next to the bootstrap address, which names the same cluster. CI's kates-platform render check now also asserts both namespace variables. - MCP caveats dry-run-other-namespace and topology-unread-looks-empty say which chart values set these settings, with anchored refs to the configmap. Four refs into charts/kates are re-pointed past the added lines. * fix(chaos): a fault that names no targetNamespace is in the Kafka cluster's namespace, wherever it is FaultSpec.Builder defaulted targetNamespace to the literal "kafka". With kates.chaos.kafka.namespace set elsewhere, which charts/kates 0.11.8 does from networkPolicy.kafka.namespace, every step, playbook, template and resilience scenario that left the namespace out was aimed at kafka. The safety guard then refused it: kafka was neither the Kafka cluster's namespace nor the Kates API's own. The builder's default now reads kates.chaos.kafka.namespace (default kafka). JSON and plain callers both build specs through the builder, outside CDI, so the builder reads it from config itself. A spec that names a namespace keeps it. FaultSpecTest registers a config with namespace streaming and checks the builder, JSON without the field, and an explicit namespace. MCP preview_disruption, which assumed the literal: - A step that leaves targetNamespace out is in the namespace the dry run reads, so it never draws the dry-run-other-namespace caveat. - A playbook step's namespace is within the agent limits when it is the Kafka namespace the topology names, not only when it is kafka. A playbook comes back as the backend built it, so with Kafka in kafka-prod its steps name kafka-prod. - The caveat text says kates.chaos.kafka.namespace. Its FaultSpec refs are re-pointed and anchored. Book chapter 07 says the same.
This was referenced Oct 21, 2026
bmscomp
added a commit
that referenced
this pull request
Oct 21, 2026
…dminless plan with what shipped (#444) The book teaches the conformity language in its Conformity Checks chapter, but had no place that lists every field, value kind, rule id, report field and lint code. A new appendix does, after the version matrix; the chapter, the CLI Reference, the Reference part's intro and the README point to it. It is written against main as of #443: - a key set twice to the same value is a lint error that fmt fixes (#437); - with rbac.scope=namespace, zones, skew and rack awareness read the EndpointSlices of the brokers' headless Service when nodes can't be listed, and podMonitor looks in the Kafka namespace only (#439); - a refused get of the Kafka resource is a 503 naming the grant (#439), which the API Reference now says too; - the chart sets the checked namespace and cluster from networkPolicy.kafka.namespace and kafka.clusterName (#441). plans/adminless-kubernetes.md is the plan behind #439, with a status block naming what shipped in #439 and #441-#443, where the work departed from it (EndpointSlice zones; orphan recovery left on), and what is still open.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
On a shared cluster a team gets a namespace and the built-in
editrole, not cluster-admin, and today it can't install Kates: thekateschart's default RBAC is a ClusterRole and ClusterRoleBinding. Yet nothing in a performance or INTEGRITY run needs Kubernetes at all. A study of all 132 Kubernetes call sites inkates/src/main/javafound no Kubernetes API call from submission to report, on either backend; topics go through the Kafka Admin API. What did need Kubernetes rights was the install, the conformity check's reads of the Kafka namespace, andkates ports.What changes
Chart (0.12.0):
rbac.scopeandrbac.kafkaNamespaceRole.rbac.scope=namespacerenders nothing cluster-scoped. It adds one read-only Role and RoleBinding innetworkPolicy.kafka.namespacefor conformity checks:kafka.strimzi.iokafkaskafka.strimzi.iokafkanodepoolspods,persistentvolumeclaimsmonitoring.coreos.compodmonitorsdiscovery.k8s.ioendpointslicesIt also sets
KATES_TOPOLOGY_KAFKA_NAMESPACEto that namespace, so the check reads where its Role is, andKATES_CHAOS_PROVIDER=noopunlesschaos.provideris set. Withrbac.kafkaNamespaceRole=falsethe Role is left out, so anedit-only account can install. An account that holds those reads applies the Role fromhelm template … --show-only templates/rbac.yaml.The default,
rbac.scope=cluster, renders what 0.11.6 rendered: the diff of a default render is only the chart-version label and the checksums derived from it. A release with neither value set, as afterhelm upgrade --reuse-valuesfrom 0.11.6, keeps scopecluster.Conformity check (
ConformityCheck.java): a refused read says what it is.Kafkaresource is still a 503, but it now names the missing grant instead of "Kubernetes API not available" followed by fabric8's full message, which carried the API server's URL.zones,skewandkafka.rackAwareness(sourcecr) UNKNOWN. Each Kafka pod's zone comes from the EndpointSlices of Strimzi's headless Service,<cluster>-kafka-brokers, which selects every Kafka pod and publishes not-ready addresses. The EndpointSlice controller copies the node'stopology.kubernetes.io/zoneonto them. The rule's detail says where the zones came from. AnotherzoneLabelstays UNKNOWN, since endpoints carry only that label.CLI:
kates ports. When listing Services in every namespace is forbidden, it lists--app-nsand--kafka-nsinstead. It does that only on a refusal, so an unreachable cluster doesn't wait three times as long.Docs. A Deployment Guide section, "Running Without Cluster Admin", covers:
The chart README, the CLI Reference's
portsentry and the conformity chapter's Limits point to it.Evidence
Local mirrors of the jobs these paths trigger:
helm lint, the newci.ymlstep run locally, actionlint,gen-chart-table.sh --checkandgen-version-matrix.sh --check. The new step fails on a mutant Role that addssecretsandpods/execwith verb*.-Dquarkus.grpc.codegen.skip=truewith the cached generated sources (kates.protois unchanged).ConformityCheckTestis at 45 after the EndpointSlice commit. Spotless is clean.go test ./...,go vet ./..., and golangci-lint--new-from-revwith 0 issues.check-book-style.shand a scratch Quarto render, with no warnings.Live on
panda, the three-node Kind lab, with this branch's image (docker build -f kates/Dockerfile,kind load). It was installed by a user with onlyeditin a new namespace (helm --kube-as-user,--set rbac.scope=namespace --set rbac.kafkaNamespaceRole=false):kafka.rackAwarenessandmonitoring.podMonitor: 9 of 9 PASS. The zones came from the EndpointSlices ofkafka/krafter-kafka-brokers, and the PodMonitor found waskafka/krafter-kafka.brokers.zoneswas UNKNOWN with a one-line reason (exit 2).Everything created for the test was removed afterwards; the lab's own
katesrelease was untouched.Also in this PR
cli/go.modmoves the toolchain from go1.27.2 to go1.27.3. The Dependency CVE scan's govulncheck found GO-2026-6809 incrypto/x509of go1.27.2, reachable fromdetect.RenderHTML, and go1.27.3 fixes it. The advisory is new, not a regression from this branch. Locally, govulncheck finds nothing on 1.27.3 and the CLI suite passes. Thegodirective stays at 1.26.0, so the version matrix doesn't change.Deliberately not done
kates deploy: it installs Strimzi, cert-manager, monitoring and Litmus, which needs a cluster admin.*, because its group ids carry the run id, and CreateTopics on an existing topic without the Create ACL still fails submission. Both are documented.kates cluster topologyandalertsreads are not in the Role;alertsreports no rules under this scope, as documented.katesreleases in cluster scope still collide on the ClusterRole name; untouched.sourcefield still says "nodes' …" when the zones came from EndpointSlices; the detail says where they came from.kates-0.9.1inkates-platform(cluster-wide Secret reads) is fix(chart): kates-platform refuses stale subcharts, so a platform install no longer reads every Secret #438, separately.kates watchuses the default namespaces (kates,kafka), markedshortcut:in the code.kates portsitself, because it stops every runningkubectl port-forward. Its fallback is unit-tested, and the precondition was checked as the restricted user:get svc -Aforbidden,-n teamallowed.