Skip to content

Commit b6099d8

Browse files
committed
feat(helm): add support for user-managed SASL secrets and dynamic secret handling for Kafka, topic initialization, and MirrorMaker
1 parent 936c861 commit b6099d8

6 files changed

Lines changed: 209 additions & 41 deletions

File tree

kafka/README.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,77 @@ kafka:
4343
4444
With persistence disabled, the broker data path is still mounted, but it uses `emptyDir` and is lost when the pod is deleted.
4545

46+
## User-managed SASL secrets
47+
48+
For SASL/PLAIN, keep credentials in Kubernetes Secrets and point the chart at those secrets instead of putting JAAS strings in values files.
49+
50+
```yaml
51+
apiVersion: v1
52+
kind: Secret
53+
metadata:
54+
name: kafka-auth
55+
type: Opaque
56+
stringData:
57+
kafka-server-jaas.conf: |
58+
KafkaServer {
59+
org.apache.kafka.common.security.plain.PlainLoginModule required
60+
username="admin"
61+
password="admin-secret"
62+
user_admin="admin-secret"
63+
user_kafbat-ui="ui-secret"
64+
user_schema-registry="schema-secret"
65+
user_mm2="mm2-secret";
66+
};
67+
schema-registry-jaas.conf: |
68+
org.apache.kafka.common.security.plain.PlainLoginModule required username="schema-registry" password="schema-secret";
69+
kafbat-ui-jaas.conf: |
70+
org.apache.kafka.common.security.plain.PlainLoginModule required username="kafbat-ui" password="ui-secret";
71+
client-secret.properties: |
72+
sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule required username="admin" password="admin-secret";
73+
---
74+
apiVersion: v1
75+
kind: Secret
76+
metadata:
77+
name: kafka-mm2
78+
type: Opaque
79+
stringData:
80+
mm2-secret.properties: |
81+
primary.sasl.jaas.config = org.apache.kafka.common.security.plain.PlainLoginModule required username="mm2" password="mm2-secret";
82+
standby.sasl.jaas.config = org.apache.kafka.common.security.plain.PlainLoginModule required username="mm2" password="mm2-secret";
83+
```
84+
85+
Then reference them from values:
86+
87+
```yaml
88+
kafka:
89+
jaas:
90+
enabled: true
91+
existingSecret: kafka-auth
92+
existingSecretKey: kafka-server-jaas.conf
93+
94+
topicInit:
95+
commandConfig: |
96+
security.protocol=SASL_PLAINTEXT
97+
sasl.mechanism=PLAIN
98+
commandConfigSecretExistingSecret: kafka-auth
99+
commandConfigSecretExistingSecretKey: client-secret.properties
100+
101+
mirrorMaker:
102+
properties: |
103+
clusters = primary, standby
104+
primary.bootstrap.servers = kafka-kafka-primary-0.kafka-kafka-primary-headless.kafka.svc.cluster.local:9092,kafka-kafka-primary-1.kafka-kafka-primary-headless.kafka.svc.cluster.local:9092
105+
standby.bootstrap.servers = kafka-kafka-standby-0.kafka-kafka-standby-headless.kafka.svc.cluster.local:9092,kafka-kafka-standby-1.kafka-kafka-standby-headless.kafka.svc.cluster.local:9092
106+
primary.security.protocol = SASL_PLAINTEXT
107+
primary.sasl.mechanism = PLAIN
108+
standby.security.protocol = SASL_PLAINTEXT
109+
standby.sasl.mechanism = PLAIN
110+
primary->standby.enabled = true
111+
primary->standby.topics = .*
112+
replication.policy.class = org.apache.kafka.connect.mirror.IdentityReplicationPolicy
113+
secretPropertiesExistingSecret: kafka-mm2
114+
secretPropertiesExistingSecretKey: mm2-secret.properties
115+
```
116+
46117
## Multi-cluster example
47118

48119
```yaml
@@ -83,6 +154,7 @@ mirrorMaker:
83154
84155
primary->standby.enabled = true
85156
primary->standby.topics = .*
157+
replication.policy.class = org.apache.kafka.connect.mirror.IdentityReplicationPolicy
86158
replication.factor = 1
87159
checkpoints.topic.replication.factor = 1
88160
heartbeats.topic.replication.factor = 1

kafka/templates/kafka-statefulset.yaml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,11 +170,15 @@ spec:
170170
export KAFKA_OPTS="-Djava.security.krb5.conf={{ $root.Values.kerberos.krb5ConfigPath }} -Djava.security.auth.login.config={{ default $root.Values.kafka.kerberos.jaasPath (dig "kerberos" "jaasPath" nil $cluster) }} ${KAFKA_OPTS:-}"
171171
{{- end }}
172172
{{- if (default $root.Values.kafka.jaas.enabled (dig "jaas" "enabled" nil $cluster)) }}
173+
{{- if (default $root.Values.kafka.jaas.existingSecret (dig "jaas" "existingSecret" nil $cluster)) }}
174+
export KAFKA_OPTS="-Djava.security.auth.login.config={{ default $root.Values.kafka.jaas.path (dig "jaas" "path" nil $cluster) }} ${KAFKA_OPTS:-}"
175+
{{- else }}
173176
cat > {{ default $root.Values.kafka.jaas.path (dig "jaas" "path" nil $cluster) }} <<'EOF'
174177
{{- default $root.Values.kafka.jaas.config (dig "jaas" "config" nil $cluster) | nindent 14 }}
175178
EOF
176179
export KAFKA_OPTS="-Djava.security.auth.login.config={{ default $root.Values.kafka.jaas.path (dig "jaas" "path" nil $cluster) }} ${KAFKA_OPTS:-}"
177180
{{- end }}
181+
{{- end }}
178182
exec /etc/kafka/docker/run
179183
ports:
180184
- name: {{ $clientName }}
@@ -204,6 +208,12 @@ spec:
204208
mountPath: {{ $root.Values.kerberos.mountPath }}
205209
readOnly: true
206210
{{- end }}
211+
{{- if and (default $root.Values.kafka.jaas.enabled (dig "jaas" "enabled" nil $cluster)) (default $root.Values.kafka.jaas.existingSecret (dig "jaas" "existingSecret" nil $cluster)) }}
212+
- name: kafka-jaas
213+
mountPath: {{ default $root.Values.kafka.jaas.path (dig "jaas" "path" nil $cluster) }}
214+
subPath: {{ default $root.Values.kafka.jaas.existingSecretKey (dig "jaas" "existingSecretKey" nil $cluster) }}
215+
readOnly: true
216+
{{- end }}
207217
{{- with (concat (default list $root.Values.kafka.extraVolumeMounts) (default list $cluster.extraVolumeMounts)) }}
208218
{{- toYaml . | nindent 12 }}
209219
{{- end }}
@@ -233,6 +243,14 @@ spec:
233243
emptyDir:
234244
{{- toYaml (default $root.Values.kafka.persistence.emptyDir (dig "persistence" "emptyDir" nil $cluster)) | nindent 12 }}
235245
{{- end }}
246+
{{- if and (default $root.Values.kafka.jaas.enabled (dig "jaas" "enabled" nil $cluster)) (default $root.Values.kafka.jaas.existingSecret (dig "jaas" "existingSecret" nil $cluster)) }}
247+
- name: kafka-jaas
248+
secret:
249+
secretName: {{ default $root.Values.kafka.jaas.existingSecret (dig "jaas" "existingSecret" nil $cluster) }}
250+
items:
251+
- key: {{ default $root.Values.kafka.jaas.existingSecretKey (dig "jaas" "existingSecretKey" nil $cluster) }}
252+
path: {{ default $root.Values.kafka.jaas.existingSecretKey (dig "jaas" "existingSecretKey" nil $cluster) }}
253+
{{- end }}
236254
{{- if $root.Values.kerberos.enabled }}
237255
- name: kerberos
238256
{{- if and $root.Values.kerberos.kdc.enabled (not $root.Values.kerberos.existingSecret) }}

kafka/templates/mirror-maker.yaml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{{- if .Values.mirrorMaker.enabled }}
2+
{{- if not .Values.mirrorMaker.propertiesExistingSecret }}
23
apiVersion: v1
34
kind: ConfigMap
45
metadata:
@@ -10,6 +11,7 @@ data:
1011
mm2.properties: |
1112
{{- .Values.mirrorMaker.properties | nindent 4 }}
1213
---
14+
{{- end }}
1315
apiVersion: apps/v1
1416
kind: Deployment
1517
metadata:
@@ -42,12 +44,28 @@ spec:
4244
- -ec
4345
- |
4446
export KAFKA_OPTS="-Djava.security.krb5.conf={{ .Values.kerberos.krb5ConfigPath }} ${KAFKA_OPTS:-}"
47+
{{- if .Values.mirrorMaker.secretPropertiesExistingSecret }}
48+
cat /etc/kafka/mm2-common.properties /etc/kafka/mm2-secret.properties > /tmp/mm2.properties
49+
exec /opt/kafka/bin/connect-mirror-maker.sh /tmp/mm2.properties
50+
{{- else }}
4551
exec /opt/kafka/bin/connect-mirror-maker.sh /etc/kafka/mm2.properties
52+
{{- end }}
4653
volumeMounts:
4754
- name: mirror-maker-config
55+
{{- if .Values.mirrorMaker.secretPropertiesExistingSecret }}
56+
mountPath: /etc/kafka/mm2-common.properties
57+
subPath: mm2.properties
58+
{{- else }}
4859
mountPath: /etc/kafka/mm2.properties
4960
subPath: mm2.properties
61+
{{- end }}
62+
readOnly: true
63+
{{- if .Values.mirrorMaker.secretPropertiesExistingSecret }}
64+
- name: mirror-maker-secret-config
65+
mountPath: /etc/kafka/mm2-secret.properties
66+
subPath: mm2-secret.properties
5067
readOnly: true
68+
{{- end }}
5169
{{- if .Values.kerberos.enabled }}
5270
- name: kerberos
5371
mountPath: {{ .Values.kerberos.mountPath }}
@@ -59,8 +77,24 @@ spec:
5977
{{- end }}
6078
volumes:
6179
- name: mirror-maker-config
80+
{{- if .Values.mirrorMaker.propertiesExistingSecret }}
81+
secret:
82+
secretName: {{ .Values.mirrorMaker.propertiesExistingSecret }}
83+
items:
84+
- key: {{ .Values.mirrorMaker.propertiesExistingSecretKey }}
85+
path: mm2.properties
86+
{{- else }}
6287
configMap:
6388
name: {{ include "kafka.fullname" . }}-mirror-maker
89+
{{- end }}
90+
{{- if .Values.mirrorMaker.secretPropertiesExistingSecret }}
91+
- name: mirror-maker-secret-config
92+
secret:
93+
secretName: {{ .Values.mirrorMaker.secretPropertiesExistingSecret }}
94+
items:
95+
- key: {{ .Values.mirrorMaker.secretPropertiesExistingSecretKey }}
96+
path: mm2-secret.properties
97+
{{- end }}
6498
{{- if .Values.kerberos.enabled }}
6599
- name: kerberos
66100
{{- if and .Values.kerberos.kdc.enabled (not .Values.kerberos.existingSecret) }}

kafka/templates/topic-init.yaml

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
{{- end }}
99
{{- end }}
1010
{{- end }}
11+
{{- if not .Values.topicInit.commandConfigExistingSecret }}
1112
apiVersion: v1
1213
kind: ConfigMap
1314
metadata:
@@ -19,6 +20,7 @@ data:
1920
client.properties: |
2021
{{- .Values.topicInit.commandConfig | nindent 4 }}
2122
---
23+
{{- end }}
2224
apiVersion: batch/v1
2325
kind: Job
2426
metadata:
@@ -48,18 +50,35 @@ spec:
4850
- -ec
4951
- |
5052
export KAFKA_OPTS="-Djava.security.krb5.conf={{ .Values.kerberos.krb5ConfigPath }} ${KAFKA_OPTS:-}"
53+
{{- if .Values.topicInit.commandConfigSecretExistingSecret }}
54+
cat /etc/kafka/client-common.properties /etc/kafka/client-secret.properties > /tmp/client.properties
55+
COMMAND_CONFIG=/tmp/client.properties
56+
{{- else }}
57+
COMMAND_CONFIG=/etc/kafka/client.properties
58+
{{- end }}
5159
for i in $(seq 1 {{ int .Values.topicInit.waitAttempts }}); do
52-
/opt/kafka/bin/kafka-topics.sh --bootstrap-server {{ include "kafka.cluster.bootstrapServers" (dict "root" . "cluster" $targetCluster) }} --command-config /etc/kafka/client.properties --list >/dev/null && break
60+
/opt/kafka/bin/kafka-topics.sh --bootstrap-server {{ include "kafka.cluster.bootstrapServers" (dict "root" . "cluster" $targetCluster) }} --command-config "${COMMAND_CONFIG}" --list >/dev/null && break
5361
sleep {{ int .Values.topicInit.waitSeconds }}
5462
done
5563
{{- range .Values.topicInit.topics }}
56-
/opt/kafka/bin/kafka-topics.sh --bootstrap-server {{ include "kafka.cluster.bootstrapServers" (dict "root" $ "cluster" $targetCluster) }} --command-config /etc/kafka/client.properties --create --topic {{ .name | quote }} --partitions {{ .partitions }} --replication-factor {{ .replicationFactor }} --if-not-exists
64+
/opt/kafka/bin/kafka-topics.sh --bootstrap-server {{ include "kafka.cluster.bootstrapServers" (dict "root" $ "cluster" $targetCluster) }} --command-config "${COMMAND_CONFIG}" --create --topic {{ .name | quote }} --partitions {{ .partitions }} --replication-factor {{ .replicationFactor }} --if-not-exists
5765
{{- end }}
5866
volumeMounts:
5967
- name: topic-init-config
68+
{{- if .Values.topicInit.commandConfigSecretExistingSecret }}
69+
mountPath: /etc/kafka/client-common.properties
70+
subPath: client.properties
71+
{{- else }}
6072
mountPath: /etc/kafka/client.properties
6173
subPath: client.properties
74+
{{- end }}
6275
readOnly: true
76+
{{- if .Values.topicInit.commandConfigSecretExistingSecret }}
77+
- name: topic-init-secret-config
78+
mountPath: /etc/kafka/client-secret.properties
79+
subPath: client-secret.properties
80+
readOnly: true
81+
{{- end }}
6382
{{- if .Values.kerberos.enabled }}
6483
- name: kerberos
6584
mountPath: {{ .Values.kerberos.mountPath }}
@@ -71,8 +90,24 @@ spec:
7190
{{- end }}
7291
volumes:
7392
- name: topic-init-config
93+
{{- if .Values.topicInit.commandConfigExistingSecret }}
94+
secret:
95+
secretName: {{ .Values.topicInit.commandConfigExistingSecret }}
96+
items:
97+
- key: {{ .Values.topicInit.commandConfigExistingSecretKey }}
98+
path: client.properties
99+
{{- else }}
74100
configMap:
75101
name: {{ include "kafka.fullname" . }}-topic-init
102+
{{- end }}
103+
{{- if .Values.topicInit.commandConfigSecretExistingSecret }}
104+
- name: topic-init-secret-config
105+
secret:
106+
secretName: {{ .Values.topicInit.commandConfigSecretExistingSecret }}
107+
items:
108+
- key: {{ .Values.topicInit.commandConfigSecretExistingSecretKey }}
109+
path: client-secret.properties
110+
{{- end }}
76111
{{- if .Values.kerberos.enabled }}
77112
- name: kerberos
78113
{{- if and .Values.kerberos.kdc.enabled (not .Values.kerberos.existingSecret) }}

kafka/values-sample.yaml

Lines changed: 33 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -16,27 +16,10 @@ kafka:
1616
- User:schema-registry
1717
- User:mm2
1818

19-
config:
20-
KAFKA_LISTENER_NAME_SASL_PLAINTEXT_PLAIN_SASL_JAAS_CONFIG: >-
21-
org.apache.kafka.common.security.plain.PlainLoginModule required
22-
username="admin"
23-
password="admin-secret"
24-
user_admin="admin-secret"
25-
user_kafbat-ui="ui-secret"
26-
user_schema-registry="schema-secret"
27-
user_mm2="mm2-secret";
2819
jaas:
2920
enabled: true
30-
config: |
31-
KafkaServer {
32-
org.apache.kafka.common.security.plain.PlainLoginModule required
33-
username="admin"
34-
password="admin-secret"
35-
user_admin="admin-secret"
36-
user_kafbat-ui="ui-secret"
37-
user_schema-registry="schema-secret"
38-
user_mm2="mm2-secret";
39-
};
21+
existingSecret: kafka-auth
22+
existingSecretKey: kafka-server-jaas.conf
4023

4124
clusters:
4225
- name: primary
@@ -55,12 +38,18 @@ schemaRegistry:
5538
env:
5639
SCHEMA_REGISTRY_KAFKASTORE_SECURITY_PROTOCOL: SASL_PLAINTEXT
5740
SCHEMA_REGISTRY_KAFKASTORE_SASL_MECHANISM: PLAIN
58-
SCHEMA_REGISTRY_KAFKASTORE_SASL_JAAS_CONFIG: >-
59-
org.apache.kafka.common.security.plain.PlainLoginModule required
60-
username="schema-registry"
61-
password="schema-secret";
41+
extraEnv:
42+
- name: SCHEMA_REGISTRY_KAFKASTORE_SASL_JAAS_CONFIG
43+
valueFrom:
44+
secretKeyRef:
45+
name: kafka-auth
46+
key: schema-registry-jaas.conf
6247

6348
kafbatUi:
49+
image:
50+
repository: ghcr.io/openprojectx/kafka-ui
51+
tag: latest
52+
pullPolicy: Always
6453
enabled: true
6554
autoClusters: true
6655
clusters: []
@@ -69,43 +58,49 @@ kafbatUi:
6958
env:
7059
KAFKA_CLUSTERS_0_PROPERTIES_SECURITY_PROTOCOL: SASL_PLAINTEXT
7160
KAFKA_CLUSTERS_0_PROPERTIES_SASL_MECHANISM: PLAIN
72-
KAFKA_CLUSTERS_0_PROPERTIES_SASL_JAAS_CONFIG: >-
73-
org.apache.kafka.common.security.plain.PlainLoginModule required
74-
username="kafbat-ui"
75-
password="ui-secret";
7661
KAFKA_CLUSTERS_1_PROPERTIES_SECURITY_PROTOCOL: SASL_PLAINTEXT
7762
KAFKA_CLUSTERS_1_PROPERTIES_SASL_MECHANISM: PLAIN
78-
KAFKA_CLUSTERS_1_PROPERTIES_SASL_JAAS_CONFIG: >-
79-
org.apache.kafka.common.security.plain.PlainLoginModule required
80-
username="kafbat-ui"
81-
password="ui-secret";
63+
extraEnv:
64+
- name: KAFKA_CLUSTERS_0_PROPERTIES_SASL_JAAS_CONFIG
65+
valueFrom:
66+
secretKeyRef:
67+
name: kafka-auth
68+
key: kafbat-ui-jaas.conf
69+
- name: KAFKA_CLUSTERS_1_PROPERTIES_SASL_JAAS_CONFIG
70+
valueFrom:
71+
secretKeyRef:
72+
name: kafka-auth
73+
key: kafbat-ui-jaas.conf
8274

8375
topicInit:
8476
enabled: true
8577
kafkaCluster: primary
78+
commandConfigSecretExistingSecret: kafka-auth
79+
commandConfigSecretExistingSecretKey: client-secret.properties
8680
commandConfig: |
8781
security.protocol=SASL_PLAINTEXT
8882
sasl.mechanism=PLAIN
89-
sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule required username="admin" password="admin-secret";
9083
9184
mirrorMaker:
9285
enabled: true
86+
secretPropertiesExistingSecret: kafka-mm2
87+
secretPropertiesExistingSecretKey: mm2-secret.properties
9388
properties: |
9489
clusters = primary, standby
95-
90+
9691
primary.bootstrap.servers = kafka-kafka-primary-0.kafka-kafka-primary-headless.kafka.svc.cluster.local:9092,kafka-kafka-primary-1.kafka-kafka-primary-headless.kafka.svc.cluster.local:9092
9792
standby.bootstrap.servers = kafka-kafka-standby-0.kafka-kafka-standby-headless.kafka.svc.cluster.local:9092,kafka-kafka-standby-1.kafka-kafka-standby-headless.kafka.svc.cluster.local:9092
98-
93+
9994
primary.security.protocol = SASL_PLAINTEXT
10095
primary.sasl.mechanism = PLAIN
101-
primary.sasl.jaas.config = org.apache.kafka.common.security.plain.PlainLoginModule required username="mm2" password="mm2-secret";
102-
10396
standby.security.protocol = SASL_PLAINTEXT
10497
standby.sasl.mechanism = PLAIN
105-
standby.sasl.jaas.config = org.apache.kafka.common.security.plain.PlainLoginModule required username="mm2" password="mm2-secret";
106-
98+
10799
primary->standby.enabled = true
108100
primary->standby.topics = .*
101+
replication.policy.class = org.apache.kafka.connect.mirror.IdentityReplicationPolicy
102+
refresh.topics.interval.seconds = 10
103+
sync.topic.configs.interval.seconds = 10
109104
110105
standby->primary.enabled = false
111106
standby->primary.topics = $^

0 commit comments

Comments
 (0)