-
Notifications
You must be signed in to change notification settings - Fork 160
feat(kafka): add TLS support via Strimzi listener configuration #2681
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
ebd25b0
2b196c3
42a672f
bd49fe7
eef13ea
3050b7c
c806691
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| #!/usr/bin/env bats | ||
| # Unit test: kafka-rd cozyrds embedded openAPISchema must declare | ||
| # tls.enabled as nullable (["boolean","null"]) so the ApplicationDefinition | ||
| # CRD validation does not reject an unset (null) value. | ||
|
|
||
| REPO_ROOT="$(cd "$(dirname "${BATS_TEST_FILENAME:-$0}")/.." && pwd)" | ||
| COZYRDS="$REPO_ROOT/packages/system/kafka-rd/cozyrds/kafka.yaml" | ||
|
|
||
| @test "kafka-rd cozyrds embedded schema has tls.enabled type as [boolean, null]" { | ||
| # The openAPISchema value is a single-line JSON string after "openAPISchema: |-" | ||
| SCHEMA_JSON="$(grep -A1 'openAPISchema: |-' "$COZYRDS" | tail -n1 | sed 's/^[[:space:]]*//')" | ||
| [ -n "$SCHEMA_JSON" ] || { echo "Could not extract openAPISchema from $COZYRDS" >&2; exit 1; } | ||
| printf '%s' "$SCHEMA_JSON" | jq -e '.properties.tls.properties.enabled.type == ["boolean", "null"]' | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| #!/usr/bin/env bats | ||
| # Unit test: kafka-rd cozyrds must reference the Strimzi-generated | ||
| # clients-ca-cert secret (not the bare clients-ca name, which does not exist). | ||
|
|
||
| REPO_ROOT="$(cd "$(dirname "${BATS_TEST_FILENAME:-$0}")/.." && pwd)" | ||
| COZYRDS="$REPO_ROOT/packages/system/kafka-rd/cozyrds/kafka.yaml" | ||
|
|
||
| @test "kafka-rd cozyrds references clients-ca-cert (Strimzi actual name)" { | ||
| grep -q "clients-ca-cert" "$COZYRDS" | ||
| } | ||
|
|
||
| @test "kafka-rd cozyrds does not reference bare clients-ca (wrong name)" { | ||
| if grep -qP "clients-ca(?!-)" "$COZYRDS"; then | ||
| echo "Found bare 'clients-ca' reference (missing '-cert' suffix)" >&2 | ||
| exit 1 | ||
| fi | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,4 +3,10 @@ PRESET_ENUM := ["nano","micro","small","medium","large","xlarge","2xlarge"] | |
|
|
||
| generate: | ||
| cozyvalues-gen -m 'kafka' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/kafka/types.go | ||
| sed -i 's/Enabled bool `json:"enabled,omitempty"`/Enabled *bool `json:"enabled,omitempty"`/' ../../../api/apps/v1alpha1/kafka/types.go | ||
| jq '.properties.tls.properties.enabled.type = ["boolean", "null"]' values.schema.json > values.schema.json.tmp && mv values.schema.json.tmp values.schema.json | ||
| jq -e '.properties.tls.properties.enabled.type == ["boolean", "null"]' values.schema.json > /dev/null || (echo "ERROR: jq patch failed" && exit 1) | ||
|
Comment on lines
+6
to
+8
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Guard the Go type patch with a hard assertion. The Suggested fix generate:
cozyvalues-gen -m 'kafka' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/kafka/types.go
- sed -i 's/Enabled bool `json:"enabled,omitempty"`/Enabled *bool `json:"enabled,omitempty"`/' ../../../api/apps/v1alpha1/kafka/types.go
+ sed -i -E 's/Enabled[[:space:]]+bool[[:space:]]+`json:"enabled,omitempty"`/Enabled *bool `json:"enabled,omitempty"`/' ../../../api/apps/v1alpha1/kafka/types.go
+ grep -Eq 'Enabled[[:space:]]+\*bool[[:space:]]+`json:"enabled,omitempty"`' ../../../api/apps/v1alpha1/kafka/types.go || (echo "ERROR: failed to patch TLS.Enabled to *bool" && exit 1)
jq '.properties.tls.properties.enabled.type = ["boolean", "null"]' values.schema.json > values.schema.json.tmp && mv values.schema.json.tmp values.schema.json
jq -e '.properties.tls.properties.enabled.type == ["boolean", "null"]' values.schema.json > /dev/null || (echo "ERROR: jq patch failed" && exit 1)
../../../hack/update-crd.sh🤖 Prompt for AI Agents |
||
| ../../../hack/update-crd.sh | ||
|
|
||
| test: | ||
| helm unittest . | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,9 +4,11 @@ | |
|
|
||
| ### Common parameters | ||
|
|
||
| | Name | Description | Type | Value | | ||
| | ---------- | ------------------------------------------------ | ------ | ------- | | ||
| | `external` | Enable external access from outside the cluster. | `bool` | `false` | | ||
| | Name | Description | Type | Value | | ||
| | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------- | | ||
| | `external` | Enable external access from outside the cluster. | `bool` | `false` | | ||
| | `tls` | TLS configuration. Strimzi manages the cluster PKI automatically (no cert-manager is involved for this chart): the operator auto-creates `<release>-cluster-ca-cert` and `<release>-clients-ca-cert` secrets, both exposed for client trust setup. The internal TLS listener on 9093 is always on; this toggle only controls the external listener on 9094. | `object` | `{}` | | ||
| | `tls.enabled` | Enable TLS on the external listener. When unset, inherits the value of `external` (TLS is on when external access is enabled). Warning: setting this to false while external is true exposes Kafka over plaintext on a public IP via LoadBalancer. Strimzi does not provide authentication on this listener unless SCRAM, mTLS, or OAuth is separately configured. Use only in controlled networks. | `bool` | `false` | | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Document The row describes tri-state inheritance but lists default 🤖 Prompt for AI Agents |
||
|
|
||
|
|
||
| ### Application-specific parameters | ||
|
|
@@ -68,6 +70,10 @@ Presets follow a cloud-style `<series>.<size>` naming convention. Five series co | |
|
|
||
| See [`docs/operations/resource-presets.md`](../../../docs/operations/resource-presets.md) for the full size matrix and the legacy-to-instance-type mapping. | ||
|
|
||
| ### Authentication | ||
|
|
||
| This chart does not configure listener authentication. When TLS is enabled on the external listener, clients can connect without credentials. To require authentication, use Strimzi's `KafkaUser` resource with an appropriate `authentication` type (`tls`, `scram-sha-512`, or `oauth`) outside this chart. See the [Strimzi documentation on KafkaUser](https://strimzi.io/docs/operators/latest/overview.html#security-options_str) for details. | ||
|
|
||
| ### topics | ||
|
|
||
| ```yaml | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,12 @@ | ||
| {{- $tlsMap := .Values.tls | default dict -}} | ||
| {{- $tlsEnabledExplicit := hasKey $tlsMap "enabled" -}} | ||
| {{- $tlsEnabled := false -}} | ||
| {{- if $tlsEnabledExplicit -}} | ||
| {{- $tlsEnabled = index $tlsMap "enabled" -}} | ||
| {{- else -}} | ||
| {{- $tlsEnabled = .Values.external | default false -}} | ||
| {{- end -}} | ||
| {{- $showExternal := or .Values.external (and $tlsEnabledExplicit $tlsEnabled) -}} | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Gate external-bootstrap RBAC only on Line 9 still grants external-bootstrap access when Proposed fix-{{- $tlsMap := .Values.tls | default dict -}}
-{{- $tlsEnabledExplicit := hasKey $tlsMap "enabled" -}}
-{{- $tlsEnabled := false -}}
-{{- if $tlsEnabledExplicit -}}
- {{- $tlsEnabled = index $tlsMap "enabled" -}}
-{{- else -}}
- {{- $tlsEnabled = .Values.external | default false -}}
-{{- end -}}
-{{- $showExternal := or .Values.external (and $tlsEnabledExplicit $tlsEnabled) -}}
+{{- $showExternal := .Values.external | default false -}}Also applies to: 21-23 🤖 Prompt for AI Agents |
||
| apiVersion: rbac.authorization.k8s.io/v1 | ||
| kind: Role | ||
| metadata: | ||
|
|
@@ -9,7 +18,7 @@ rules: | |
| - services | ||
| resourceNames: | ||
| - {{ .Release.Name }}-kafka-bootstrap | ||
| {{- if .Values.external }} | ||
| {{- if $showExternal }} | ||
| - {{ .Release.Name }}-kafka-external-bootstrap | ||
| {{- end }} | ||
| verbs: ["get", "list", "watch"] | ||
|
|
@@ -18,7 +27,8 @@ rules: | |
| resources: | ||
| - secrets | ||
| resourceNames: | ||
| - {{ .Release.Name }}-clients-ca | ||
| - {{ .Release.Name }}-clients-ca-cert | ||
| - {{ .Release.Name }}-cluster-ca-cert | ||
| verbs: ["get", "list", "watch"] | ||
| - apiGroups: | ||
| - cozystack.io | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,25 @@ | ||
| {{- /* | ||
| Tri-state TLS logic for the external listener (port 9094): | ||
| - .Values.external is the sole gate for the external LoadBalancer listener. | ||
| The listener is rendered if and only if external is true. | ||
| - tls.enabled controls TLS *on the external listener* (independent of whether | ||
| the listener exists): | ||
| - If tls.enabled is explicitly set (true or false), that value wins. | ||
| - If tls.enabled is unset (nil), TLS inherits from .Values.external | ||
| (auto-on when external is true, off otherwise). | ||
| - tls.enabled does NOT control whether the external listener is created. | ||
| Setting tls.enabled=true with external=false has no effect on listeners. | ||
| Internal TLS listener (port 9093) is always on; Strimzi manages the PKI. | ||
| */ -}} | ||
| {{- $tlsMap := .Values.tls | default dict -}} | ||
| {{- $tlsEnabledExplicit := hasKey $tlsMap "enabled" -}} | ||
| {{- $tlsEnabled := false -}} | ||
| {{- if $tlsEnabledExplicit -}} | ||
| {{- $tlsEnabled = index $tlsMap "enabled" -}} | ||
| {{- else -}} | ||
| {{- $tlsEnabled = .Values.external | default false -}} | ||
| {{- end -}} | ||
|
Comment on lines
+15
to
+21
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "Confirm schema allows null for tls.enabled:"
rg -n '"enabled".*"type":\["boolean","null"\]' packages/system/kafka-rd/cozyrds/kafka.yaml
echo
echo "Confirm template uses key-presence explicitness and renders tls from that value:"
rg -n 'hasKey \$tlsMap "enabled"|index \$tlsMap "enabled"|tls: \{\{ \$tlsEnabled \}\}' packages/apps/kafka/templates/kafka.yamlRepository: cozystack/cozystack Length of output: 5898 Handle The schema allows The fix distinguishes between "key exists with a boolean" and "key exists but is null" (which should behave as unset). Capture the raw value, update the explicit check to Proposed fix {{- $tlsMap := .Values.tls | default dict -}}
-{{- $tlsEnabledExplicit := hasKey $tlsMap "enabled" -}}
+{{- $tlsEnabledRaw := index $tlsMap "enabled" -}}
+{{- $tlsEnabledExplicit := and (hasKey $tlsMap "enabled") (ne $tlsEnabledRaw nil) -}}
{{- $tlsEnabled := false -}}
{{- if $tlsEnabledExplicit -}}
- {{- $tlsEnabled = index $tlsMap "enabled" -}}
+ {{- $tlsEnabled = $tlsEnabledRaw -}}
{{- else -}}
{{- $tlsEnabled = .Values.external | default false -}}
{{- end -}}Also applies to: 47-47 🤖 Prompt for AI Agents |
||
| {{- $showExternal := .Values.external -}} | ||
| apiVersion: kafka.strimzi.io/v1beta2 | ||
| kind: Kafka | ||
| metadata: | ||
|
|
@@ -18,11 +40,11 @@ spec: | |
| port: 9093 | ||
| type: internal | ||
| tls: true | ||
| {{- if .Values.external }} | ||
| {{- if $showExternal }} | ||
| - name: external | ||
| port: 9094 | ||
| type: loadbalancer | ||
| tls: false | ||
| tls: {{ $tlsEnabled }} | ||
| {{- end }} | ||
| config: | ||
| {{- if eq (int .Values.kafka.replicas) 1 }} | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -78,17 +78,31 @@ tests: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content: test-kafka-kafka-external-bootstrap | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| documentIndex: 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Role grants access to CA secret | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - it: grants access to clients CA secret | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Role grants access to CA secrets | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - it: grants access to clients CA cert secret | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| release: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: test-kafka | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| namespace: tenant-test | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| asserts: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - contains: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| path: rules[1].resourceNames | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content: test-kafka-clients-ca-cert | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| documentIndex: 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - notContains: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| path: rules[1].resourceNames | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content: test-kafka-clients-ca | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| documentIndex: 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - it: grants access to cluster CA cert secret | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| release: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: test-kafka | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| namespace: tenant-test | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| asserts: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - contains: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| path: rules[1].resourceNames | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content: test-kafka-cluster-ca-cert | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| documentIndex: 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Role grants access to workloadmonitors | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - it: grants access to WorkloadMonitor | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| release: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -104,6 +118,36 @@ tests: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| value: cozystack.io | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| documentIndex: 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # External bootstrap service present when tls.enabled=true and external=false ($showExternal is true) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - it: grants access to external bootstrap service when tls.enabled=true and external=false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| release: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: test-kafka | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| namespace: tenant-test | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| external: false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tls: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| enabled: true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| asserts: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - contains: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| path: rules[0].resourceNames | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content: test-kafka-kafka-external-bootstrap | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| documentIndex: 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+121
to
+134
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. External bootstrap RBAC should not be granted when This test enforces over-permissive behavior ( Suggested test fix- # External bootstrap service present when tls.enabled=true and external=false ($showExternal is true)
- - it: grants access to external bootstrap service when tls.enabled=true and external=false
+ # External bootstrap service absent when external=false, regardless of tls.enabled
+ - it: does not grant access to external bootstrap service when tls.enabled=true and external=false
@@
- asserts:
- - contains:
+ asserts:
+ - notContains:
path: rules[0].resourceNames
content: test-kafka-kafka-external-bootstrap
documentIndex: 0📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # External bootstrap service absent when both external=false and tls.enabled=false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - it: does not grant access to external bootstrap when tls.enabled is explicitly false and external is false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| release: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: test-kafka | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| namespace: tenant-test | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| external: false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tls: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| enabled: false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| asserts: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - notContains: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| path: rules[0].resourceNames | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content: test-kafka-kafka-external-bootstrap | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| documentIndex: 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # RoleBinding references correct Role | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - it: RoleBinding references correct Role | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| release: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add cluster CA naming checks to match the same contract.
This file only guards
clients-ca-cert; it should also assertcluster-ca-certand reject barecluster-cato prevent partial regressions.Suggested test additions
`@test` "kafka-rd cozyrds references clients-ca-cert (Strimzi actual name)" { grep -q "clients-ca-cert" "$COZYRDS" } +@test "kafka-rd cozyrds references cluster-ca-cert (Strimzi actual name)" { + grep -q "cluster-ca-cert" "$COZYRDS" +} + `@test` "kafka-rd cozyrds does not reference bare clients-ca (wrong name)" { if grep -qP "clients-ca(?!-)" "$COZYRDS"; then echo "Found bare 'clients-ca' reference (missing '-cert' suffix)" >&2 exit 1 fi } + +@test "kafka-rd cozyrds does not reference bare cluster-ca (wrong name)" { + if grep -qP "cluster-ca(?!-)" "$COZYRDS"; then + echo "Found bare 'cluster-ca' reference (missing '-cert' suffix)" >&2 + exit 1 + fi +}📝 Committable suggestion
🤖 Prompt for AI Agents