This is an automated email from the ASF dual-hosted git repository.

lhotari pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-helm-chart.git


The following commit(s) were added to refs/heads/master by this push:
     new e8ab0c6  Feat/cacerts (#619)
e8ab0c6 is described below

commit e8ab0c6ded2cb61f9b65e38e9615c80dc5bff8c8
Author: gulecroc <[email protected]>
AuthorDate: Sat Jun 21 22:13:35 2025 +0200

    Feat/cacerts (#619)
---
 .ci/clusters/values-cacerts.yaml                   | 105 +++++++++++++++++++++
 .github/workflows/pulsar-helm-chart-ci.yaml        |   3 +
 charts/pulsar/templates/_autorecovery.tpl          |  35 ++++++-
 charts/pulsar/templates/_bookkeeper.tpl            |  45 ++++++++-
 charts/pulsar/templates/_broker.tpl                |  43 ++++++++-
 charts/pulsar/templates/_certs.tpl                 |  18 +++-
 charts/pulsar/templates/_proxy.tpl                 |  95 +++++++++++++++++++
 charts/pulsar/templates/_toolset.tpl               |  43 ++++++++-
 .../{_values_validation.tpl => _tplvalues.tpl}     |  62 +++++++-----
 charts/pulsar/templates/_values_validation.tpl     |  50 +++++-----
 charts/pulsar/templates/_zookeeper.tpl             |  74 ++++++++++++++-
 .../pulsar/templates/autorecovery-statefulset.yaml |  17 ++++
 .../templates/bookkeeper-cluster-initialize.yaml   |  12 +++
 .../pulsar/templates/bookkeeper-statefulset.yaml   |  17 ++++
 charts/pulsar/templates/broker-configmap.yaml      |   6 +-
 charts/pulsar/templates/broker-statefulset.yaml    |  17 ++++
 .../pulsar/templates/certs-scripts-configmap.yaml  |  82 ++++++++++++++++
 charts/pulsar/templates/extra-list.yaml            |  23 +++++
 charts/pulsar/templates/proxy-configmap.yaml       |   4 +-
 charts/pulsar/templates/proxy-statefulset.yaml     |  49 ++++------
 .../templates/pulsar-cluster-initialize.yaml       |  12 +++
 charts/pulsar/templates/toolset-configmap.yaml     |   4 +-
 charts/pulsar/templates/toolset-statefulset.yaml   |  32 ++++---
 charts/pulsar/templates/zookeeper-statefulset.yaml |  47 ++++-----
 charts/pulsar/values.yaml                          |  54 +++++++++++
 25 files changed, 807 insertions(+), 142 deletions(-)

diff --git a/.ci/clusters/values-cacerts.yaml b/.ci/clusters/values-cacerts.yaml
new file mode 100644
index 0000000..72b41ea
--- /dev/null
+++ b/.ci/clusters/values-cacerts.yaml
@@ -0,0 +1,105 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+
+# enable TLS with cacerts
+tls:
+  enabled: true
+  proxy:
+    enabled: true
+    cacerts:
+      enabled: true
+      certs:
+        - name: common-cacert
+          existingSecret: "pulsar-ci-common-cacert"
+          secretKeys:
+            - ca.crt
+  broker:
+    enabled: true
+    cacerts:
+      enabled: true
+      certs:
+        - name: common-cacert
+          existingSecret: "pulsar-ci-common-cacert"
+          secretKeys:
+            - ca.crt
+  bookie:
+    enabled: true
+    cacerts:
+      enabled: true
+      certs:
+        - name: common-cacert
+          existingSecret: "pulsar-ci-common-cacert"
+          secretKeys:
+            - ca.crt
+  zookeeper:
+    enabled: true
+    cacerts:
+      enabled: true
+      certs:
+        - name: common-cacert
+          existingSecret: "pulsar-ci-common-cacert"
+          secretKeys:
+            - ca.crt
+  toolset:
+    cacerts:
+      enabled: true
+      certs:
+        - name: common-cacert
+          existingSecret: "pulsar-ci-common-cacert"
+          secretKeys:
+            - ca.crt
+  autorecovery:
+    cacerts:
+      enabled: true
+      certs:
+        - name: common-cacert
+          existingSecret: "pulsar-ci-common-cacert"
+          secretKeys:
+            - ca.crt
+
+# enable cert-manager
+certs:
+  internal_issuer:
+    enabled: true
+    type: selfsigning
+
+# deploy cacerts
+extraDeploy:
+  - |
+    apiVersion: "{{ .Values.certs.internal_issuer.apiVersion }}"
+    kind: Certificate
+    metadata:
+      name: "{{ template "pulsar.fullname" . }}-common-cacert"
+      namespace: {{ template "pulsar.namespace" . }}
+      labels:
+        {{- include "pulsar.standardLabels" . | nindent 4 }}
+    spec:
+      secretName: "{{ template "pulsar.fullname" . }}-common-cacert"
+      commonName: "common-cacert"
+      duration: "{{ .Values.certs.internal_issuer.duration }}"
+      renewBefore: "{{ .Values.certs.internal_issuer.renewBefore }}"
+      usages:
+        - server auth
+        - client auth
+      isCA: true
+      issuerRef:
+        name: "{{ template "pulsar.fullname" . }}-{{ 
.Values.certs.internal_issuer.component }}"
+        kind: Issuer
+        group: cert-manager.io
diff --git a/.github/workflows/pulsar-helm-chart-ci.yaml 
b/.github/workflows/pulsar-helm-chart-ci.yaml
index 1244020..5ec29f6 100644
--- a/.github/workflows/pulsar-helm-chart-ci.yaml
+++ b/.github/workflows/pulsar-helm-chart-ci.yaml
@@ -233,6 +233,9 @@ jobs:
           - name: OpenID
             values_file: .ci/clusters/values-openid.yaml
             shortname: openid
+          - name: CA certificates
+            values_file: .ci/clusters/values-cacerts.yaml
+            shortname: cacerts
         include:
           - k8sVersion:
               version: "1.25.16"
diff --git a/charts/pulsar/templates/_autorecovery.tpl 
b/charts/pulsar/templates/_autorecovery.tpl
index f5b4185..845c66c 100644
--- a/charts/pulsar/templates/_autorecovery.tpl
+++ b/charts/pulsar/templates/_autorecovery.tpl
@@ -36,7 +36,7 @@ Define autorecovery zookeeper client tls settings
 */}}
 {{- define "pulsar.autorecovery.zookeeper.tls.settings" -}}
 {{- if and .Values.tls.enabled .Values.tls.zookeeper.enabled }}
-{{- include "pulsar.component.zookeeper.tls.settings" (dict "component" 
"autorecovery" "isClient" true) -}}
+{{- include "pulsar.component.zookeeper.tls.settings" (dict "component" 
"autorecovery" "isClient" true "isCacerts" 
.Values.tls.autorecovery.cacerts.enabled) -}}
 {{- end }}
 {{- end }}
 
@@ -52,6 +52,21 @@ Define autorecovery tls certs mounts
   mountPath: "/pulsar/certs/ca"
   readOnly: true
 {{- end }}
+{{- if .Values.tls.autorecovery.cacerts.enabled }}
+- mountPath: "/pulsar/certs/cacerts"
+  name: autorecovery-cacerts
+{{- range $cert := .Values.tls.autorecovery.cacerts.certs }}
+- name: {{ $cert.name }}
+  mountPath: "/pulsar/certs/{{ $cert.name }}"
+  readOnly: true
+{{- end }}
+- name: certs-scripts
+  mountPath: "/pulsar/bin/certs-combine-pem.sh"
+  subPath: certs-combine-pem.sh
+- name: certs-scripts
+  mountPath: "/pulsar/bin/certs-combine-pem-infinity.sh"
+  subPath: certs-combine-pem-infinity.sh
+{{- end }}
 {{- end }}
 
 {{/*
@@ -76,6 +91,24 @@ Define autorecovery tls certs volumes
     - key: ca.crt
       path: ca.crt
 {{- end }}
+{{- if .Values.tls.autorecovery.cacerts.enabled }}
+- name: autorecovery-cacerts
+  emptyDir: {}
+{{- range $cert := .Values.tls.autorecovery.cacerts.certs }}
+- name: {{ $cert.name }}
+  secret:
+    secretName: "{{ $cert.existingSecret }}"
+    items:
+    {{- range $key := $cert.secretKeys }}
+      - key: {{ $key }}
+        path: {{ $key }}
+    {{- end }}
+{{- end }}
+- name: certs-scripts
+  configMap:
+    name: "{{ template "pulsar.fullname" . }}-certs-scripts"
+    defaultMode: 0755
+{{- end }}
 {{- end }}
 
 {{/*
diff --git a/charts/pulsar/templates/_bookkeeper.tpl 
b/charts/pulsar/templates/_bookkeeper.tpl
index a279737..c8c97d0 100644
--- a/charts/pulsar/templates/_bookkeeper.tpl
+++ b/charts/pulsar/templates/_bookkeeper.tpl
@@ -37,7 +37,7 @@ Define bookie zookeeper client tls settings
 */}}
 {{- define "pulsar.bookkeeper.zookeeper.tls.settings" -}}
 {{- if and .Values.tls.enabled .Values.tls.zookeeper.enabled }}
-{{- include "pulsar.component.zookeeper.tls.settings" (dict "component" 
"bookie" "isClient" true) -}}
+{{- include "pulsar.component.zookeeper.tls.settings" (dict "component" 
"bookie" "isClient" true "isCacerts" .Values.tls.bookie.cacerts.enabled) -}}
 {{- end }}
 {{- end }}
 
@@ -45,21 +45,39 @@ Define bookie zookeeper client tls settings
 Define bookie tls certs mounts
 */}}
 {{- define "pulsar.bookkeeper.certs.volumeMounts" -}}
-{{- if and .Values.tls.enabled (or .Values.tls.bookie.enabled 
.Values.tls.zookeeper.enabled) }}
+{{- if .Values.tls.enabled }}
+{{- if or .Values.tls.bookie.enabled .Values.tls.zookeeper.enabled }}
 - name: bookie-certs
   mountPath: "/pulsar/certs/bookie"
   readOnly: true
+{{- end }}
 - name: ca
   mountPath: "/pulsar/certs/ca"
   readOnly: true
 {{- end }}
+{{- if .Values.tls.bookie.cacerts.enabled }}
+- mountPath: "/pulsar/certs/cacerts"
+  name: bookie-cacerts
+{{- range $cert := .Values.tls.bookie.cacerts.certs }}
+- name: {{ $cert.name }}
+  mountPath: "/pulsar/certs/{{ $cert.name }}"
+  readOnly: true
+{{- end }}
+- name: certs-scripts
+  mountPath: "/pulsar/bin/certs-combine-pem.sh"
+  subPath: certs-combine-pem.sh
+- name: certs-scripts
+  mountPath: "/pulsar/bin/certs-combine-pem-infinity.sh"
+  subPath: certs-combine-pem-infinity.sh
+{{- end }}
 {{- end }}
 
 {{/*
 Define bookie tls certs volumes
 */}}
 {{- define "pulsar.bookkeeper.certs.volumes" -}}
-{{- if and .Values.tls.enabled (or .Values.tls.bookie.enabled 
.Values.tls.zookeeper.enabled) }}
+{{- if .Values.tls.enabled }}
+{{- if or .Values.tls.bookie.enabled .Values.tls.zookeeper.enabled }}
 - name: bookie-certs
   secret:
     secretName: "{{ .Release.Name }}-{{ .Values.tls.bookie.cert_name }}"
@@ -72,6 +90,7 @@ Define bookie tls certs volumes
     - key: tls-combined.pem
       path: tls-combined.pem
 {{- end }}
+{{- end }}
 - name: ca
   secret:
     secretName: "{{ template "pulsar.certs.issuers.ca.secretName" . }}"
@@ -79,6 +98,24 @@ Define bookie tls certs volumes
     - key: ca.crt
       path: ca.crt
 {{- end }}
+{{- if .Values.tls.bookie.cacerts.enabled }}
+- name: bookie-cacerts
+  emptyDir: {}
+{{- range $cert := .Values.tls.bookie.cacerts.certs }}
+- name: {{ $cert.name }}
+  secret:
+    secretName: "{{ $cert.existingSecret }}"
+    items:
+    {{- range $key := $cert.secretKeys }}
+      - key: {{ $key }}
+        path: {{ $key }}
+    {{- end }}
+{{- end }}
+- name: certs-scripts
+  configMap:
+    name: "{{ template "pulsar.fullname" . }}-certs-scripts"
+    defaultMode: 0755
+{{- end }}
 {{- end }}
 
 {{/*
@@ -129,7 +166,7 @@ PULSAR_PREFIX_tlsCertificatePath: 
/pulsar/certs/bookie/tls.crt
 PULSAR_PREFIX_tlsKeyStoreType: PEM
 PULSAR_PREFIX_tlsKeyStore: /pulsar/certs/bookie/tls.key
 PULSAR_PREFIX_tlsTrustStoreType: PEM
-PULSAR_PREFIX_tlsTrustStore: /pulsar/certs/ca/ca.crt 
+PULSAR_PREFIX_tlsTrustStore: {{ ternary 
"/pulsar/certs/cacerts/ca-combined.pem" "/pulsar/certs/ca/ca.crt" 
.Values.tls.bookie.cacerts.enabled | quote }}
 {{- end }}
 {{- end }}
 
diff --git a/charts/pulsar/templates/_broker.tpl 
b/charts/pulsar/templates/_broker.tpl
index 773ae15..814d630 100644
--- a/charts/pulsar/templates/_broker.tpl
+++ b/charts/pulsar/templates/_broker.tpl
@@ -43,7 +43,7 @@ Define broker zookeeper client tls settings
 */}}
 {{- define "pulsar.broker.zookeeper.tls.settings" -}}
 {{- if and .Values.tls.enabled .Values.tls.zookeeper.enabled }}
-{{- include "pulsar.component.zookeeper.tls.settings" (dict "component" 
"broker" "isClient" true) -}}
+{{- include "pulsar.component.zookeeper.tls.settings" (dict "component" 
"broker" "isClient" true "isCacerts" .Values.tls.broker.cacerts.enabled) -}}
 {{- end }}
 {{- end }}
 
@@ -51,21 +51,39 @@ Define broker zookeeper client tls settings
 Define broker tls certs mounts
 */}}
 {{- define "pulsar.broker.certs.volumeMounts" -}}
-{{- if and .Values.tls.enabled (or .Values.tls.broker.enabled (or 
.Values.tls.bookie.enabled .Values.tls.zookeeper.enabled)) }}
+{{- if .Values.tls.enabled }}
+{{- if or .Values.tls.broker.enabled (or .Values.tls.bookie.enabled 
.Values.tls.zookeeper.enabled) }}
 - name: broker-certs
   mountPath: "/pulsar/certs/broker"
   readOnly: true
+{{- end }}
 - name: ca
   mountPath: "/pulsar/certs/ca"
   readOnly: true
 {{- end }}
+{{- if .Values.tls.broker.cacerts.enabled }}
+- mountPath: "/pulsar/certs/cacerts"
+  name: broker-cacerts
+{{- range $cert := .Values.tls.broker.cacerts.certs }}
+- name: {{ $cert.name }}
+  mountPath: "/pulsar/certs/{{ $cert.name }}"
+  readOnly: true
+{{- end }}
+- name: certs-scripts
+  mountPath: "/pulsar/bin/certs-combine-pem.sh"
+  subPath: certs-combine-pem.sh
+- name: certs-scripts
+  mountPath: "/pulsar/bin/certs-combine-pem-infinity.sh"
+  subPath: certs-combine-pem-infinity.sh
+{{- end }}
 {{- end }}
 
 {{/*
 Define broker tls certs volumes
 */}}
 {{- define "pulsar.broker.certs.volumes" -}}
-{{- if and .Values.tls.enabled (or .Values.tls.broker.enabled (or 
.Values.tls.bookie.enabled .Values.tls.zookeeper.enabled)) }}
+{{- if .Values.tls.enabled }}
+{{- if or .Values.tls.broker.enabled (or .Values.tls.bookie.enabled 
.Values.tls.zookeeper.enabled) }}
 - name: broker-certs
   secret:
     secretName: "{{ .Release.Name }}-{{ .Values.tls.broker.cert_name }}"
@@ -78,6 +96,7 @@ Define broker tls certs volumes
     - key: tls-combined.pem
       path: tls-combined.pem
 {{- end }}
+{{- end }}
 - name: ca
   secret:
     secretName: "{{ template "pulsar.certs.issuers.ca.secretName" . }}"
@@ -85,4 +104,22 @@ Define broker tls certs volumes
     - key: ca.crt
       path: ca.crt
 {{- end }}
+{{- if .Values.tls.broker.cacerts.enabled }}
+- name: broker-cacerts
+  emptyDir: {}
+{{- range $cert := .Values.tls.broker.cacerts.certs }}
+- name: {{ $cert.name }}
+  secret:
+    secretName: "{{ $cert.existingSecret }}"
+    items:
+    {{- range $key := $cert.secretKeys }}
+      - key: {{ $key }}
+        path: {{ $key }}
+    {{- end }}
+{{- end }}
+- name: certs-scripts
+  configMap:
+    name: "{{ template "pulsar.fullname" . }}-certs-scripts"
+    defaultMode: 0755
+{{- end }}
 {{- end }}
diff --git a/charts/pulsar/templates/_certs.tpl 
b/charts/pulsar/templates/_certs.tpl
index 215792f..5aad491 100644
--- a/charts/pulsar/templates/_certs.tpl
+++ b/charts/pulsar/templates/_certs.tpl
@@ -113,4 +113,20 @@ spec:
     # This is optional since cert-manager will default to this value however
     # if you are using an external issuer, change this to that issuer group.
     group: cert-manager.io
-{{- end -}}
\ No newline at end of file
+{{- end -}}
+
+{{/*
+CA certificates template
+Usage: {{ include "pulsar.certs.cacerts" (dict "certs" 
.Values.tls.<component>.cacerts.certs) }}
+*/}}
+{{- define "pulsar.certs.cacerts" -}}
+{{- $certs := .certs -}}
+{{- $cacerts := list -}}
+{{- $cacerts = print "/pulsar/certs/ca/ca.crt" | append $cacerts -}}
+{{- range $cert := $certs -}}
+{{- range $key := $cert.secretKeys -}}
+{{- $cacerts = print "/pulsar/certs/" $cert.name "/" $key | append $cacerts -}}
+{{- end -}}
+{{- end -}}
+{{ join " " $cacerts }}
+{{- end -}}
diff --git a/charts/pulsar/templates/_proxy.tpl 
b/charts/pulsar/templates/_proxy.tpl
new file mode 100644
index 0000000..958dc7c
--- /dev/null
+++ b/charts/pulsar/templates/_proxy.tpl
@@ -0,0 +1,95 @@
+{{/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/}}
+
+{{/*
+Define proxy tls certs mounts
+*/}}
+{{- define "pulsar.proxy.certs.volumeMounts" -}}
+{{- if .Values.tls.enabled }}
+{{- if .Values.tls.proxy.enabled }}
+- mountPath: "/pulsar/certs/proxy"
+  name: proxy-certs
+  readOnly: true
+{{- end }}
+- mountPath: "/pulsar/certs/ca"
+  name: ca
+  readOnly: true
+{{- end }}
+{{- if .Values.tls.proxy.cacerts.enabled }}
+- mountPath: "/pulsar/certs/cacerts"
+  name: proxy-cacerts
+{{- range $cert := .Values.tls.proxy.cacerts.certs }}
+- name: {{ $cert.name }}
+  mountPath: "/pulsar/certs/{{ $cert.name }}"
+  readOnly: true
+{{- end }}
+- name: certs-scripts
+  mountPath: "/pulsar/bin/certs-combine-pem.sh"
+  subPath: certs-combine-pem.sh
+- name: certs-scripts
+  mountPath: "/pulsar/bin/certs-combine-pem-infinity.sh"
+  subPath: certs-combine-pem-infinity.sh
+{{- end }}
+{{- end }}
+
+{{/*
+Define proxy tls certs volumes
+*/}}
+{{- define "pulsar.proxy.certs.volumes" -}}
+{{- if .Values.tls.enabled }}
+{{- if .Values.tls.proxy.enabled }}
+- name: proxy-certs
+  secret:
+    secretName: "{{ .Release.Name }}-{{ .Values.tls.proxy.cert_name }}"
+    items:
+      - key: tls.crt
+        path: tls.crt
+      - key: tls.key
+        path: tls.key
+      {{- if .Values.tls.zookeeper.enabled }}
+      - key: tls-combined.pem
+        path: tls-combined.pem
+      {{- end }}
+{{- end }}
+- name: ca
+  secret:
+    secretName: "{{ template "pulsar.certs.issuers.ca.secretName" . }}"
+    items:
+      - key: ca.crt
+        path: ca.crt
+{{- end }}
+{{- if .Values.tls.proxy.cacerts.enabled }}
+- name: proxy-cacerts
+  emptyDir: {}
+{{- range $cert := .Values.tls.proxy.cacerts.certs }}
+- name: {{ $cert.name }}
+  secret:
+    secretName: "{{ $cert.existingSecret }}"
+    items:
+    {{- range $key := $cert.secretKeys }}
+      - key: {{ $key }}
+        path: {{ $key }}
+    {{- end }}
+{{- end }}
+- name: certs-scripts
+  configMap:
+    name: "{{ template "pulsar.fullname" . }}-certs-scripts"
+    defaultMode: 0755
+{{- end }}
+{{- end }}
diff --git a/charts/pulsar/templates/_toolset.tpl 
b/charts/pulsar/templates/_toolset.tpl
index 0865c67..9c536bc 100644
--- a/charts/pulsar/templates/_toolset.tpl
+++ b/charts/pulsar/templates/_toolset.tpl
@@ -36,7 +36,7 @@ Define toolset zookeeper client tls settings
 */}}
 {{- define "pulsar.toolset.zookeeper.tls.settings" -}}
 {{- if and .Values.tls.enabled .Values.tls.zookeeper.enabled -}}
-{{- include "pulsar.component.zookeeper.tls.settings" (dict "component" 
"toolset" "isClient" true) -}}
+{{- include "pulsar.component.zookeeper.tls.settings" (dict "component" 
"toolset" "isClient" true "isCacerts" .Values.tls.toolset.cacerts.enabled) -}}
 {{- end -}}
 {{- end }}
 
@@ -44,21 +44,39 @@ Define toolset zookeeper client tls settings
 Define toolset tls certs mounts
 */}}
 {{- define "pulsar.toolset.certs.volumeMounts" -}}
-{{- if and .Values.tls.enabled .Values.tls.zookeeper.enabled }}
+{{- if .Values.tls.enabled }}
+{{- if .Values.tls.zookeeper.enabled }}
 - name: toolset-certs
   mountPath: "/pulsar/certs/toolset"
   readOnly: true
+{{- end }}
 - name: ca
   mountPath: "/pulsar/certs/ca"
   readOnly: true
 {{- end }}
+{{- if .Values.tls.toolset.cacerts.enabled }}
+- mountPath: "/pulsar/certs/cacerts"
+  name: toolset-cacerts
+{{- range $cert := .Values.tls.toolset.cacerts.certs }}
+- name: {{ $cert.name }}
+  mountPath: "/pulsar/certs/{{ $cert.name }}"
+  readOnly: true
+{{- end }}
+- name: certs-scripts
+  mountPath: "/pulsar/bin/certs-combine-pem.sh"
+  subPath: certs-combine-pem.sh
+- name: certs-scripts
+  mountPath: "/pulsar/bin/certs-combine-pem-infinity.sh"
+  subPath: certs-combine-pem-infinity.sh
+{{- end }}
 {{- end }}
 
 {{/*
 Define toolset tls certs volumes
 */}}
 {{- define "pulsar.toolset.certs.volumes" -}}
-{{- if and .Values.tls.enabled .Values.tls.zookeeper.enabled }}
+{{- if .Values.tls.enabled  }}
+{{- if .Values.tls.zookeeper.enabled }}
 - name: toolset-certs
   secret:
     secretName: "{{ .Release.Name }}-{{ .Values.tls.toolset.cert_name }}"
@@ -69,6 +87,7 @@ Define toolset tls certs volumes
       path: tls.key
     - key: tls-combined.pem
       path: tls-combined.pem
+{{- end }}
 - name: ca
   secret:
     secretName: "{{ template "pulsar.certs.issuers.ca.secretName" . }}"
@@ -76,4 +95,22 @@ Define toolset tls certs volumes
     - key: ca.crt
       path: ca.crt
 {{- end }}
+{{- if .Values.tls.toolset.cacerts.enabled }}
+- name: toolset-cacerts
+  emptyDir: {}
+{{- range $cert := .Values.tls.toolset.cacerts.certs }}
+- name: {{ $cert.name }}
+  secret:
+    secretName: "{{ $cert.existingSecret }}"
+    items:
+    {{- range $key := $cert.secretKeys }}
+      - key: {{ $key }}
+        path: {{ $key }}
+    {{- end }}
+{{- end }}
+- name: certs-scripts
+  configMap:
+    name: "{{ template "pulsar.fullname" . }}-certs-scripts"
+    defaultMode: 0755
+{{- end }}
 {{- end }}
diff --git a/charts/pulsar/templates/_values_validation.tpl 
b/charts/pulsar/templates/_tplvalues.tpl
similarity index 53%
copy from charts/pulsar/templates/_values_validation.tpl
copy to charts/pulsar/templates/_tplvalues.tpl
index fface25..945c6be 100644
--- a/charts/pulsar/templates/_values_validation.tpl
+++ b/charts/pulsar/templates/_tplvalues.tpl
@@ -1,25 +1,37 @@
-{{/*
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
-*/}}
-
-{{/*
-Check deprecated setting auth.authentication.provider since 4.1.0
-*/}}
-{{- if (and .Values.auth.authentication.enabled (not (empty 
.Values.auth.authentication.provider))) }}
-  {{- fail "ERROR: Setting auth.authentication.provider is no longer 
supported. For details, see the migration guide in README.md." }}
-{{- end }}
+{{/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/}}
+
+{{/*
+Renders a value that contains template perhaps with scope if the scope is 
present.
+Usage:
+{{ include "common.tplvalues.render" ( dict "value" .Values.path.to.the.Value 
"context" $ ) }}
+{{ include "common.tplvalues.render" ( dict "value" .Values.path.to.the.Value 
"context" $ "scope" $app ) }}
+*/}}
+{{- define "common.tplvalues.render" -}}
+{{- $value := typeIs "string" .value | ternary .value (.value | toYaml) }}
+{{- if contains "{{" (toJson .value) }}
+  {{- if .scope }}
+      {{- tpl (cat "{{- with $.RelativeScope -}}" $value "{{- end }}") (merge 
(dict "RelativeScope" .scope) .context) }}
+  {{- else }}
+    {{- tpl $value .context }}
+  {{- end }}
+{{- else }}
+    {{- $value }}
+{{- end }}
+{{- end -}}
diff --git a/charts/pulsar/templates/_values_validation.tpl 
b/charts/pulsar/templates/_values_validation.tpl
index fface25..807b469 100644
--- a/charts/pulsar/templates/_values_validation.tpl
+++ b/charts/pulsar/templates/_values_validation.tpl
@@ -1,25 +1,25 @@
-{{/*
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
-*/}}
-
-{{/*
-Check deprecated setting auth.authentication.provider since 4.1.0
-*/}}
-{{- if (and .Values.auth.authentication.enabled (not (empty 
.Values.auth.authentication.provider))) }}
-  {{- fail "ERROR: Setting auth.authentication.provider is no longer 
supported. For details, see the migration guide in README.md." }}
-{{- end }}
+{{/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/}}
+
+{{/*
+Check deprecated setting auth.authentication.provider since 4.1.0
+*/}}
+{{- if (and .Values.auth.authentication.enabled (not (empty 
.Values.auth.authentication.provider))) }}
+  {{- fail "ERROR: Setting auth.authentication.provider is no longer 
supported. For details, see the migration guide in README.md." }}
+{{- end }}
diff --git a/charts/pulsar/templates/_zookeeper.tpl 
b/charts/pulsar/templates/_zookeeper.tpl
index e546cde..dc86d40 100644
--- a/charts/pulsar/templates/_zookeeper.tpl
+++ b/charts/pulsar/templates/_zookeeper.tpl
@@ -53,7 +53,7 @@ Define zookeeper tls settings
 */}}
 {{- define "pulsar.zookeeper.tls.settings" -}}
 {{- if and .Values.tls.enabled .Values.tls.zookeeper.enabled }}
-{{- include "pulsar.component.zookeeper.tls.settings" (dict "component" 
"zookeeper" "isClient" false) -}}
+{{- include "pulsar.component.zookeeper.tls.settings" (dict "component" 
"zookeeper" "isClient" false "isCacerts" .Values.tls.zookeeper.cacerts.enabled) 
-}}
 {{- end }}
 {{- end }}
 
@@ -61,7 +61,7 @@ Define zookeeper tls settings
 {{- $component := .component -}}
 {{- $isClient := .isClient -}}
 {{- $keyFile := printf "/pulsar/certs/%s/tls-combined.pem" $component -}}
-{{- $caFile := "/pulsar/certs/ca/ca.crt" -}}
+{{- $caFile := ternary "/pulsar/certs/cacerts/ca-combined.pem" 
"/pulsar/certs/ca/ca.crt" .isCacerts -}}
 {{- if $isClient }}
 echo $'\n' >> conf/pulsar_env.sh
 echo "PULSAR_EXTRA_OPTS=\"\${PULSAR_EXTRA_OPTS} 
-Dzookeeper.clientCnxnSocket=org.apache.zookeeper.ClientCnxnSocketNetty 
-Dzookeeper.client.secure=true -Dzookeeper.client.certReload=true 
-Dzookeeper.ssl.keyStore.location={{- $keyFile }} 
-Dzookeeper.ssl.keyStore.type=PEM -Dzookeeper.ssl.trustStore.location={{- 
$caFile }} -Dzookeeper.ssl.trustStore.type=PEM\"" >> conf/pulsar_env.sh
@@ -73,3 +73,73 @@ echo "PULSAR_EXTRA_OPTS=\"\${PULSAR_EXTRA_OPTS} 
-Dzookeeper.ssl.keyStore.locatio
 {{- end }}
 {{- end }}
 
+{{/*
+Define zookeeper tls certs mounts
+*/}}
+{{- define "pulsar.zookeeper.certs.volumeMounts" -}}
+{{- if and .Values.tls.enabled .Values.tls.zookeeper.enabled }}
+- mountPath: "/pulsar/certs/zookeeper"
+  name: zookeeper-certs
+  readOnly: true
+- mountPath: "/pulsar/certs/ca"
+  name: ca
+  readOnly: true
+{{- end }}
+{{- if .Values.tls.zookeeper.cacerts.enabled }}
+- mountPath: "/pulsar/certs/cacerts"
+  name: zookeeper-cacerts
+{{- range $cert := .Values.tls.zookeeper.cacerts.certs }}
+- name: {{ $cert.name }}
+  mountPath: "/pulsar/certs/{{ $cert.name }}"
+  readOnly: true
+{{- end }}
+- name: certs-scripts
+  mountPath: "/pulsar/bin/certs-combine-pem.sh"
+  subPath: certs-combine-pem.sh
+- name: certs-scripts
+  mountPath: "/pulsar/bin/certs-combine-pem-infinity.sh"
+  subPath: certs-combine-pem-infinity.sh
+{{- end }}
+{{- end }}
+
+{{/*
+Define zookeeper tls certs volumes
+*/}}
+{{- define "pulsar.zookeeper.certs.volumes" -}}
+{{- if and .Values.tls.enabled .Values.tls.zookeeper.enabled }}
+- name: zookeeper-certs
+  secret:
+    secretName: "{{ .Release.Name }}-{{ .Values.tls.zookeeper.cert_name }}"
+    items:
+      - key: tls.crt
+        path: tls.crt
+      - key: tls.key
+        path: tls.key
+      - key: tls-combined.pem
+        path: tls-combined.pem
+- name: ca
+  secret:
+    secretName: "{{ template "pulsar.certs.issuers.ca.secretName" . }}"
+    items:
+      - key: ca.crt
+        path: ca.crt
+{{- end }}
+{{- if .Values.tls.zookeeper.cacerts.enabled }}
+- name: zookeeper-cacerts
+  emptyDir: {}
+{{- range $cert := .Values.tls.zookeeper.cacerts.certs }}
+- name: {{ $cert.name }}
+  secret:
+    secretName: "{{ $cert.existingSecret }}"
+    items:
+    {{- range $key := $cert.secretKeys }}
+      - key: {{ $key }}
+        path: {{ $key }}
+    {{- end }}
+{{- end }}
+- name: certs-scripts
+  configMap:
+    name: "{{ template "pulsar.fullname" . }}-certs-scripts"
+    defaultMode: 0755
+{{- end }}
+{{- end }}
diff --git a/charts/pulsar/templates/autorecovery-statefulset.yaml 
b/charts/pulsar/templates/autorecovery-statefulset.yaml
index fb58752..af7fb71 100644
--- a/charts/pulsar/templates/autorecovery-statefulset.yaml
+++ b/charts/pulsar/templates/autorecovery-statefulset.yaml
@@ -113,6 +113,18 @@ spec:
       terminationGracePeriodSeconds: {{ .Values.autorecovery.gracePeriod }}
       serviceAccountName: "{{ template "pulsar.fullname" . }}-{{ 
.Values.autorecovery.component }}"
       initContainers:
+      {{- if .Values.tls.autorecovery.cacerts.enabled }}
+      - name: cacerts
+        image: "{{ template "pulsar.imageFullName" (dict "image" 
.Values.images.autorecovery "root" .) }}"
+        imagePullPolicy: "{{ template "pulsar.imagePullPolicy" (dict "image" 
.Values.images.autorecovery "root" .) }}"
+        resources: {{ toYaml .Values.initContainer.resources | nindent 10 }}
+        command: ["sh", "-c"]
+        args:
+        - |
+          bin/certs-combine-pem.sh /pulsar/certs/cacerts/ca-combined.pem {{ 
template "pulsar.certs.cacerts" (dict "certs" 
.Values.tls.autorecovery.cacerts.certs) }}
+        volumeMounts:
+        {{- include "pulsar.autorecovery.certs.volumeMounts" . | nindent 8 }}
+      {{- end }}
       {{- if and .Values.autorecovery.waitBookkeeperTimeout (gt 
(.Values.autorecovery.waitBookkeeperTimeout | int) 0) }}
       # This initContainer will wait for bookkeeper initnewcluster to complete
       # before deploying the bookies
@@ -147,6 +159,11 @@ spec:
         command: ["sh", "-c"]
         args:
         - |
+          {{- if .Values.tls.autorecovery.cacerts.enabled }}
+          cd /pulsar/certs/cacerts;
+          nohup /pulsar/bin/certs-combine-pem-infinity.sh 
/pulsar/certs/cacerts/ca-combined.pem {{ template "pulsar.certs.cacerts" (dict 
"certs" .Values.tls.autorecovery.cacerts.certs) }} > 
/pulsar/certs/cacerts/certs-combine-pem-infinity.log 2>&1 &
+          cd /pulsar;
+          {{- end }}
           bin/apply-config-from-env.py conf/bookkeeper.conf;
           {{- include "pulsar.autorecovery.zookeeper.tls.settings" . | nindent 
10 }}
           OPTS="${OPTS} -Dlog4j2.formatMsgNoLookups=true" exec bin/bookkeeper 
autorecovery
diff --git a/charts/pulsar/templates/bookkeeper-cluster-initialize.yaml 
b/charts/pulsar/templates/bookkeeper-cluster-initialize.yaml
index fab46ab..e2bdd72 100755
--- a/charts/pulsar/templates/bookkeeper-cluster-initialize.yaml
+++ b/charts/pulsar/templates/bookkeeper-cluster-initialize.yaml
@@ -49,6 +49,18 @@ spec:
 {{ toYaml .Values.pulsar_metadata.tolerations | indent 8 }}
       {{- end }}
       initContainers:
+      {{- if .Values.tls.bookie.cacerts.enabled }}
+      - name: cacerts
+        image: "{{ template "pulsar.imageFullName" (dict "image" 
.Values.images.bookie "root" .) }}"
+        imagePullPolicy: "{{ template "pulsar.imagePullPolicy" (dict "image" 
.Values.images.bookie "root" .) }}"
+        resources: {{ toYaml .Values.initContainer.resources | nindent 10 }}
+        command: ["sh", "-c"]
+        args:
+          - |
+            bin/certs-combine-pem.sh /pulsar/certs/cacerts/ca-combined.pem {{ 
template "pulsar.certs.cacerts" (dict "certs" .Values.tls.bookie.cacerts.certs) 
}}
+        volumeMounts:
+        {{- include "pulsar.toolset.certs.volumeMounts" . | nindent 8 }}
+      {{- end }}
       {{- if and .Values.components.zookeeper 
.Values.bookkeeper.metadata.waitZookeeperTimeout (gt 
(.Values.bookkeeper.metadata.waitZookeeperTimeout | int) 0) }}
       - name: wait-zookeeper-ready
         image: "{{ template "pulsar.imageFullName" (dict "image" 
.Values.images.bookie "root" .) }}"
diff --git a/charts/pulsar/templates/bookkeeper-statefulset.yaml 
b/charts/pulsar/templates/bookkeeper-statefulset.yaml
index 4f8e346..5bd5fa4 100644
--- a/charts/pulsar/templates/bookkeeper-statefulset.yaml
+++ b/charts/pulsar/templates/bookkeeper-statefulset.yaml
@@ -115,6 +115,18 @@ spec:
       {{- end }}
       {{- if and .Values.bookkeeper.waitMetadataTimeout (gt 
(.Values.bookkeeper.waitMetadataTimeout | int) 0) }}
       initContainers:
+      {{- if .Values.tls.bookie.cacerts.enabled }}
+      - name: cacerts
+        image: "{{ template "pulsar.imageFullName" (dict "image" 
.Values.images.bookie "root" .) }}"
+        imagePullPolicy: "{{ template "pulsar.imagePullPolicy" (dict "image" 
.Values.images.bookie "root" .) }}"
+        resources: {{ toYaml .Values.initContainer.resources | nindent 10 }}
+        command: ["sh", "-c"]
+        args:
+        - |
+          bin/certs-combine-pem.sh /pulsar/certs/cacerts/ca-combined.pem {{ 
template "pulsar.certs.cacerts" (dict "certs" .Values.tls.bookie.cacerts.certs) 
}}
+        volumeMounts:
+        {{- include "pulsar.bookkeeper.certs.volumeMounts" . | nindent 8 }}
+      {{- end }}
       # This initContainer will wait for bookkeeper initnewcluster to complete
       # before deploying the bookies
       - name: pulsar-bookkeeper-verify-clusterid
@@ -195,6 +207,11 @@ spec:
           {{- if .Values.bookkeeper.additionalCommand }}
           {{ .Values.bookkeeper.additionalCommand }}
           {{- end }}
+          {{- if .Values.tls.bookie.cacerts.enabled }}
+          cd /pulsar/certs/cacerts;
+          nohup /pulsar/bin/certs-combine-pem-infinity.sh 
/pulsar/certs/cacerts/ca-combined.pem {{ template "pulsar.certs.cacerts" (dict 
"certs" .Values.tls.bookie.cacerts.certs) }} > 
/pulsar/certs/cacerts/certs-combine-pem-infinity.log 2>&1 &
+          cd /pulsar;
+          {{- end }}
           bin/apply-config-from-env.py conf/bookkeeper.conf;
           {{- include "pulsar.bookkeeper.zookeeper.tls.settings" . | nindent 
10 }}
           OPTS="${OPTS} -Dlog4j2.formatMsgNoLookups=true" exec bin/pulsar 
bookie;
diff --git a/charts/pulsar/templates/broker-configmap.yaml 
b/charts/pulsar/templates/broker-configmap.yaml
index 59e7ac4..29f8970 100644
--- a/charts/pulsar/templates/broker-configmap.yaml
+++ b/charts/pulsar/templates/broker-configmap.yaml
@@ -204,7 +204,7 @@ data:
   # TLS Settings
   tlsCertificateFilePath: "/pulsar/certs/broker/tls.crt"
   tlsKeyFilePath: "/pulsar/certs/broker/tls.key"
-  tlsTrustCertsFilePath: "/pulsar/certs/ca/ca.crt"
+  tlsTrustCertsFilePath: {{ ternary "/pulsar/certs/cacerts/ca-combined.pem" 
"/pulsar/certs/ca/ca.crt" .Values.tls.broker.cacerts.enabled | quote }}
   {{- end }}
 
   # Authentication Settings
@@ -260,13 +260,13 @@ data:
   bookkeeperTLSKeyFileType: "PEM"
   bookkeeperTLSKeyFilePath: "/pulsar/certs/broker/tls.key"
   bookkeeperTLSCertificateFilePath: "/pulsar/certs/broker/tls.crt"
-  bookkeeperTLSTrustCertsFilePath: "/pulsar/certs/ca/ca.crt"
+  bookkeeperTLSTrustCertsFilePath: {{ ternary 
"/pulsar/certs/cacerts/ca-combined.pem" "/pulsar/certs/ca/ca.crt" 
.Values.tls.broker.cacerts.enabled | quote }}
   bookkeeperTLSTrustCertTypes: "PEM"
   PULSAR_PREFIX_bookkeeperTLSClientAuthentication: "true"
   PULSAR_PREFIX_bookkeeperTLSKeyFileType: "PEM"
   PULSAR_PREFIX_bookkeeperTLSKeyFilePath: "/pulsar/certs/broker/tls.key"
   PULSAR_PREFIX_bookkeeperTLSCertificateFilePath: 
"/pulsar/certs/broker/tls.crt"
-  PULSAR_PREFIX_bookkeeperTLSTrustCertsFilePath: "/pulsar/certs/ca/ca.crt"
+  PULSAR_PREFIX_bookkeeperTLSTrustCertsFilePath: {{ ternary 
"/pulsar/certs/cacerts/ca-combined.pem" "/pulsar/certs/ca/ca.crt" 
.Values.tls.broker.cacerts.enabled | quote }}
   PULSAR_PREFIX_bookkeeperTLSTrustCertTypes: "PEM"
   # https://github.com/apache/bookkeeper/pull/2300
   bookkeeperUseV2WireProtocol: "false"
diff --git a/charts/pulsar/templates/broker-statefulset.yaml 
b/charts/pulsar/templates/broker-statefulset.yaml
index dee80a3..0c8f7ee 100644
--- a/charts/pulsar/templates/broker-statefulset.yaml
+++ b/charts/pulsar/templates/broker-statefulset.yaml
@@ -130,6 +130,18 @@ spec:
         {{- end }}
       terminationGracePeriodSeconds: {{ .Values.broker.gracePeriod }}
       initContainers:
+      {{- if .Values.tls.broker.cacerts.enabled }}
+      - name: cacerts
+        image: "{{ template "pulsar.imageFullName" (dict "image" 
.Values.images.broker "root" .) }}"
+        imagePullPolicy: "{{ template "pulsar.imagePullPolicy" (dict "image" 
.Values.images.broker "root" .) }}"
+        resources: {{ toYaml .Values.initContainer.resources | nindent 10 }}
+        command: ["sh", "-c"]
+        args:
+          - |
+            bin/certs-combine-pem.sh /pulsar/certs/cacerts/ca-combined.pem {{ 
template "pulsar.certs.cacerts" (dict "certs" .Values.tls.broker.cacerts.certs) 
}}
+        volumeMounts:
+        {{- include "pulsar.broker.certs.volumeMounts" . | nindent 8 }}
+      {{- end }}
       {{- if and .Values.components.zookeeper 
.Values.broker.waitZookeeperTimeout (gt (.Values.broker.waitZookeeperTimeout | 
int) 0) }}
       # This init container will wait for zookeeper to be ready before
       # deploying the bookies
@@ -243,6 +255,11 @@ spec:
         {{- if .Values.broker.additionalCommand }}
           {{ .Values.broker.additionalCommand }}
         {{- end }}
+          {{- if .Values.tls.broker.cacerts.enabled }}
+          cd /pulsar/certs/cacerts;
+          nohup /pulsar/bin/certs-combine-pem-infinity.sh 
/pulsar/certs/cacerts/ca-combined.pem {{ template "pulsar.certs.cacerts" (dict 
"certs" .Values.tls.broker.cacerts.certs) }} > 
/pulsar/certs/cacerts/certs-combine-pem-infinity.log 2>&1 &
+          cd /pulsar;
+          {{- end }}
           bin/apply-config-from-env.py conf/broker.conf;
           bin/gen-yml-from-env.py conf/functions_worker.yml;
           echo "OK" > "${statusFilePath:-status}";
diff --git a/charts/pulsar/templates/certs-scripts-configmap.yaml 
b/charts/pulsar/templates/certs-scripts-configmap.yaml
new file mode 100644
index 0000000..231b311
--- /dev/null
+++ b/charts/pulsar/templates/certs-scripts-configmap.yaml
@@ -0,0 +1,82 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: "{{ template "pulsar.fullname" . }}-certs-scripts"
+  namespace: {{ template "pulsar.namespace" . }}
+  labels:
+    {{- include "pulsar.standardLabels" . | nindent 4 }}
+    component: certs-scripts 
+data:
+    certs-combine-pem.sh: |
+      #!/bin/bash
+      # This script combines all certificates into a single file.
+      # Usage: certs-combine-pem.sh <output_file> <cert1> <cert2> ...
+      set -eu -o pipefail
+
+      if [ "$#" -lt 2 ]; then
+        echo "Usage: $0 <output_file> <cert1> <cert2> ..."
+        exit 1
+      fi
+
+      OUTPUT_FILE="$1"
+      shift
+
+      OUTPUT_FILE_TMP="${OUTPUT_FILE}.tmp"
+      rm -f "$OUTPUT_FILE_TMP"
+
+      for CERT in "$@"; do
+        if [ -f "$CERT" ]; then
+          echo "# $CERT" >> "$OUTPUT_FILE_TMP"
+          cat "$CERT" >> "$OUTPUT_FILE_TMP"
+        else
+          echo "Certificate file '$CERT' does not exist, skipping"
+        fi
+      done
+
+      if [ ! -f "$OUTPUT_FILE" ]; then
+        touch "$OUTPUT_FILE"
+      fi
+
+      if diff -q "$OUTPUT_FILE" "$OUTPUT_FILE_TMP" > /dev/null; then
+        # No changes detected, skipping update
+        rm -f "$OUTPUT_FILE_TMP"
+      else
+        # Update $OUTPUT_FILE with new certificates
+        mv "$OUTPUT_FILE_TMP" "$OUTPUT_FILE"
+      fi
+
+    certs-combine-pem-infinity.sh: |
+      #!/bin/bash
+      # This script combines all certificates into a single file, every 
minutes.
+      # Usage: certs-combine-pem-infinity.sh <output_file> <cert1> <cert2> ...
+      set -eu -o pipefail
+
+      if [ "$#" -lt 2 ]; then
+        echo "Usage: $0 <output_file> <cert1> <cert2> ..."
+        exit 1
+      fi
+
+      while true; do
+        /pulsar/bin/certs-combine-pem.sh "$@"
+        sleep 60
+      done
+    
\ No newline at end of file
diff --git a/charts/pulsar/templates/extra-list.yaml 
b/charts/pulsar/templates/extra-list.yaml
new file mode 100644
index 0000000..a557f63
--- /dev/null
+++ b/charts/pulsar/templates/extra-list.yaml
@@ -0,0 +1,23 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+{{- range .Values.extraDeploy }}
+---
+{{ include "common.tplvalues.render" (dict "value" . "context" $) }}
+{{- end }}
diff --git a/charts/pulsar/templates/proxy-configmap.yaml 
b/charts/pulsar/templates/proxy-configmap.yaml
index 01105fe..0e85271 100644
--- a/charts/pulsar/templates/proxy-configmap.yaml
+++ b/charts/pulsar/templates/proxy-configmap.yaml
@@ -42,14 +42,14 @@ data:
   webServicePortTls: "{{ .Values.proxy.ports.containerPorts.https }}"
   tlsCertificateFilePath: "/pulsar/certs/proxy/tls.crt"
   tlsKeyFilePath: "/pulsar/certs/proxy/tls.key"
-  tlsTrustCertsFilePath: "/pulsar/certs/ca/ca.crt"
+  tlsTrustCertsFilePath: {{ ternary "/pulsar/certs/cacerts/ca-combined.pem" 
"/pulsar/certs/ca/ca.crt" .Values.tls.proxy.cacerts.enabled | quote }}
   {{- if and .Values.tls.enabled .Values.tls.broker.enabled }}
   # if broker enables TLS, configure proxy to talk to broker using TLS
   brokerServiceURLTLS: pulsar+ssl://{{ template "pulsar.fullname" . }}-{{ 
.Values.broker.component }}:{{ .Values.broker.ports.pulsarssl }}
   brokerWebServiceURLTLS: https://{{ template "pulsar.fullname" . }}-{{ 
.Values.broker.component }}:{{ .Values.broker.ports.https }}
   tlsEnabledWithBroker: "true"
   tlsCertRefreshCheckDurationSec: "300"
-  brokerClientTrustCertsFilePath: "/pulsar/certs/ca/ca.crt"
+  brokerClientTrustCertsFilePath: {{ ternary 
"/pulsar/certs/cacerts/ca-combined.pem" "/pulsar/certs/ca/ca.crt" 
.Values.tls.proxy.cacerts.enabled | quote }}
   {{- end }}
   {{- if not (and .Values.tls.enabled .Values.tls.broker.enabled) }}
   brokerServiceURL: pulsar://{{ template "pulsar.fullname" . }}-{{ 
.Values.broker.component }}:{{ .Values.broker.ports.pulsar }}
diff --git a/charts/pulsar/templates/proxy-statefulset.yaml 
b/charts/pulsar/templates/proxy-statefulset.yaml
index 9324a69..0d2a7ec 100644
--- a/charts/pulsar/templates/proxy-statefulset.yaml
+++ b/charts/pulsar/templates/proxy-statefulset.yaml
@@ -112,6 +112,18 @@ spec:
       terminationGracePeriodSeconds: {{ .Values.proxy.gracePeriod }}
       serviceAccountName: "{{ template "pulsar.fullname" . }}-{{ 
.Values.proxy.component }}"
       initContainers:
+      {{- if .Values.tls.proxy.cacerts.enabled }}
+      - name: combine-certs
+        image: "{{ template "pulsar.imageFullName" (dict "image" 
.Values.images.proxy "root" .) }}"
+        imagePullPolicy: "{{ template "pulsar.imagePullPolicy" (dict "image" 
.Values.images.proxy "root" .) }}"
+        resources: {{ toYaml .Values.initContainer.resources | nindent 10 }}
+        command: ["sh", "-c"]
+        args:
+          - |
+            bin/certs-combine-pem.sh /pulsar/certs/cacerts/ca-combined.pem {{ 
template "pulsar.certs.cacerts" (dict "certs" .Values.tls.proxy.cacerts.certs) 
}}
+        volumeMounts:
+        {{- include "pulsar.proxy.certs.volumeMounts" . | nindent 8 }}
+      {{- end }}
       {{- if and .Values.components.zookeeper 
.Values.proxy.waitZookeeperTimeout (gt (.Values.proxy.waitZookeeperTimeout | 
int) 0) }}
       # This init container will wait for zookeeper to be ready before
       # deploying the bookies
@@ -214,6 +226,11 @@ spec:
         {{- if .Values.proxy.additionalCommand }}
           {{ .Values.proxy.additionalCommand }}
         {{- end }}
+          {{- if .Values.tls.proxy.cacerts.enabled }}
+          cd /pulsar/certs/cacerts;
+          nohup /pulsar/bin/certs-combine-pem-infinity.sh 
/pulsar/certs/cacerts/ca-combined.pem {{ template "pulsar.certs.cacerts" (dict 
"certs" .Values.tls.proxy.cacerts.certs) }} > 
/pulsar/certs/cacerts/certs-combine-pem-infinity.log 2>&1 &
+          cd /pulsar;
+          {{- end }}
           bin/apply-config-from-env.py conf/proxy.conf &&
           echo "OK" > "${statusFilePath:-status}" &&
           OPTS="${OPTS} -Dlog4j2.formatMsgNoLookups=true" exec bin/pulsar proxy
@@ -250,16 +267,7 @@ spec:
             readOnly: true
           {{- end }}
           {{- end }}
-          {{- if .Values.tls.proxy.enabled }}
-          - mountPath: "/pulsar/certs/proxy"
-            name: proxy-certs
-            readOnly: true
-          {{- end}}
-          {{- if .Values.tls.enabled }}
-          - mountPath: "/pulsar/certs/ca"
-            name: ca
-            readOnly: true
-          {{- end}}
+          {{- include "pulsar.proxy.certs.volumeMounts" . | nindent 10 }}
           {{- if .Values.proxy.extraVolumeMounts }}
 {{ toYaml .Values.proxy.extraVolumeMounts | indent 10 }}
           {{- end }}
@@ -296,25 +304,6 @@ spec:
                 path: proxy/token
         {{- end}}
         {{- end}}
-        {{- if .Values.tls.proxy.enabled }}
-        - name: ca
-          secret:
-            secretName: "{{ template "pulsar.certs.issuers.ca.secretName" . }}"
-            items:
-              - key: ca.crt
-                path: ca.crt
-        - name: proxy-certs
-          secret:
-            secretName: "{{ .Release.Name }}-{{ .Values.tls.proxy.cert_name }}"
-            items:
-              - key: tls.crt
-                path: tls.crt
-              - key: tls.key
-                path: tls.key
-{{- if .Values.tls.zookeeper.enabled }}
-              - key: tls-combined.pem
-                path: tls-combined.pem
-{{- end }}
-        {{- end}}
+        {{- include "pulsar.proxy.certs.volumes" . | nindent 8 }}
       {{- end}}
 {{- end }}
diff --git a/charts/pulsar/templates/pulsar-cluster-initialize.yaml 
b/charts/pulsar/templates/pulsar-cluster-initialize.yaml
index 1279486..158a22d 100755
--- a/charts/pulsar/templates/pulsar-cluster-initialize.yaml
+++ b/charts/pulsar/templates/pulsar-cluster-initialize.yaml
@@ -45,6 +45,18 @@ spec:
 {{ toYaml .Values.pulsar_metadata.nodeSelector | indent 8 }}
     {{- end }}
       initContainers:
+      {{- if .Values.tls.toolset.cacerts.enabled }}
+      - name: cacerts
+        image: "{{ template "pulsar.imageFullName" (dict "image" 
.Values.pulsar_metadata.image "root" .) }}"
+        imagePullPolicy: "{{ template "pulsar.imagePullPolicy" (dict "image" 
.Values.pulsar_metadata.image "root" .) }}"
+        resources: {{ toYaml .Values.initContainer.resources | nindent 10 }}
+        command: ["sh", "-c"]
+        args:
+          - |
+            bin/certs-combine-pem.sh /pulsar/certs/cacerts/ca-combined.pem {{ 
template "pulsar.certs.cacerts" (dict "certs" 
.Values.tls.toolset.cacerts.certs) }}
+        volumeMounts:
+        {{- include "pulsar.toolset.certs.volumeMounts" . | nindent 8 }}
+      {{- end }}
       {{- if and .Values.components.zookeeper 
.Values.pulsar_metadata.waitZookeeperTimeout (gt 
(.Values.pulsar_metadata.waitZookeeperTimeout | int) 0) }}
       {{- if .Values.pulsar_metadata.configurationStore }}
       - name: wait-zk-cs-ready
diff --git a/charts/pulsar/templates/toolset-configmap.yaml 
b/charts/pulsar/templates/toolset-configmap.yaml
index 9ecdec7..16f12c6 100644
--- a/charts/pulsar/templates/toolset-configmap.yaml
+++ b/charts/pulsar/templates/toolset-configmap.yaml
@@ -36,7 +36,7 @@ data:
   brokerServiceUrl: "pulsar+ssl://{{ template "pulsar.fullname" . }}-{{ 
.Values.broker.component }}:{{ .Values.broker.ports.pulsarssl }}/"
   useTls: "true"
   tlsAllowInsecureConnection: "false"
-  tlsTrustCertsFilePath: "/pulsar/certs/proxy-ca/ca.crt"
+  tlsTrustCertsFilePath: {{ ternary "/pulsar/certs/cacerts/ca-combined.pem" 
"/pulsar/certs/ca/ca.crt" .Values.tls.toolset.cacerts.enabled | quote }}
   tlsEnableHostnameVerification: "false"
   {{- end }}
   {{- if not (and .Values.tls.enabled .Values.tls.broker.enabled) }}
@@ -51,7 +51,7 @@ data:
   brokerServiceUrl: "pulsar+ssl://{{ template "pulsar.fullname" . }}-{{ 
.Values.proxy.component }}:{{ .Values.proxy.ports.pulsarssl }}/"
   useTls: "true"
   tlsAllowInsecureConnection: "false"
-  tlsTrustCertsFilePath: "/pulsar/certs/proxy-ca/ca.crt"
+  tlsTrustCertsFilePath: {{ ternary "/pulsar/certs/cacerts/ca-combined.pem" 
"/pulsar/certs/ca/ca.crt" .Values.tls.toolset.cacerts.enabled | quote }}
   tlsEnableHostnameVerification: "false"
   {{- end }}
   {{- if not (and .Values.tls.enabled .Values.tls.proxy.enabled) }}
diff --git a/charts/pulsar/templates/toolset-statefulset.yaml 
b/charts/pulsar/templates/toolset-statefulset.yaml
index 922f8ac..688777a 100644
--- a/charts/pulsar/templates/toolset-statefulset.yaml
+++ b/charts/pulsar/templates/toolset-statefulset.yaml
@@ -64,8 +64,20 @@ spec:
     {{- end }}
       terminationGracePeriodSeconds: {{ .Values.toolset.gracePeriod }}
       serviceAccountName: "{{ template "pulsar.fullname" . }}-{{ 
.Values.toolset.component }}"
-      {{- if .Values.toolset.initContainers }}
       initContainers:
+      {{- if .Values.tls.toolset.cacerts.enabled }}
+      - name: cacerts
+        image: "{{ template "pulsar.imageFullName" (dict "image" 
.Values.images.toolset "root" .) }}"
+        imagePullPolicy: "{{ template "pulsar.imagePullPolicy" (dict "image" 
.Values.images.toolset "root" .) }}"
+        resources: {{ toYaml .Values.initContainer.resources | nindent 10 }}
+        command: ["sh", "-c"]
+        args:
+          - |
+            bin/certs-combine-pem.sh /pulsar/certs/cacerts/ca-combined.pem {{ 
template "pulsar.certs.cacerts" (dict "certs" 
.Values.tls.toolset.cacerts.certs) }}
+        volumeMounts:
+        {{- include "pulsar.toolset.certs.volumeMounts" . | nindent 8 }}
+      {{- end }}
+      {{- if .Values.toolset.initContainers }}
         {{- toYaml .Values.toolset.initContainers | nindent 6 }}
       {{- end }}
       containers:
@@ -87,6 +99,11 @@ spec:
         {{- if .Values.toolset.additionalCommand }}
           {{ .Values.toolset.additionalCommand }}
         {{- end }}
+          {{- if .Values.tls.toolset.cacerts.enabled }}
+          cd /pulsar/certs/cacerts;
+          nohup /pulsar/bin/certs-combine-pem-infinity.sh 
/pulsar/certs/cacerts/ca-combined.pem {{ template "pulsar.certs.cacerts" (dict 
"certs" .Values.tls.toolset.cacerts.certs) }} > 
/pulsar/certs/cacerts/certs-combine-pem-infinity.log 2>&1 &
+          cd /pulsar;
+          {{- end }}
           bin/apply-config-from-env.py conf/client.conf;
           bin/apply-config-from-env.py conf/bookkeeper.conf;
           {{- include "pulsar.toolset.zookeeper.tls.settings" . | nindent 10 }}
@@ -102,11 +119,6 @@ spec:
           readOnly: true
         {{- end }}
         {{- end }}
-        {{- if and .Values.tls.enabled (or .Values.tls.broker.enabled 
.Values.tls.proxy.enabled) }}
-        - mountPath: "/pulsar/certs/proxy-ca"
-          name: proxy-ca
-          readOnly: true
-        {{- end}}
         {{- if .Values.toolset.extraVolumeMounts }}
 {{ toYaml .Values.toolset.extraVolumeMounts | indent 8 }}
         {{- end }}
@@ -122,14 +134,6 @@ spec:
               path: client/token
       {{- end}}
       {{- end}}
-      {{- if and .Values.tls.enabled (or .Values.tls.broker.enabled 
.Values.tls.proxy.enabled) }}
-      - name: proxy-ca
-        secret:
-          secretName: "{{ template "pulsar.certs.issuers.ca.secretName" . }}"
-          items:
-            - key: ca.crt
-              path: ca.crt
-      {{- end}}
       {{- if .Values.toolset.extraVolumes }}
 {{ toYaml .Values.toolset.extraVolumes | indent 6 }}
       {{- end }}
diff --git a/charts/pulsar/templates/zookeeper-statefulset.yaml 
b/charts/pulsar/templates/zookeeper-statefulset.yaml
index 292642a..1834f4a 100755
--- a/charts/pulsar/templates/zookeeper-statefulset.yaml
+++ b/charts/pulsar/templates/zookeeper-statefulset.yaml
@@ -114,8 +114,20 @@ spec:
       securityContext:
 {{ toYaml .Values.zookeeper.securityContext | indent 8 }}
       {{- end }}
-      {{- if .Values.zookeeper.initContainers }}
       initContainers:
+      {{- if .Values.tls.zookeeper.cacerts.enabled }}
+      - name: cacerts
+        image: "{{ template "pulsar.imageFullName" (dict "image" 
.Values.images.zookeeper "root" .) }}"
+        imagePullPolicy: "{{ template "pulsar.imagePullPolicy" (dict "image" 
.Values.images.zookeeper "root" .) }}"
+        resources: {{ toYaml .Values.initContainer.resources | nindent 10 }}
+        command: ["sh", "-c"]
+        args:
+        - |
+          bin/certs-combine-pem.sh /pulsar/certs/cacerts/ca-combined.pem {{ 
template "pulsar.certs.cacerts" (dict "certs" 
.Values.tls.zookeeper.cacerts.certs) }}
+        volumeMounts:
+        {{- include "pulsar.zookeeper.certs.volumeMounts" . | nindent 8 }}
+      {{- end }}
+      {{- if .Values.zookeeper.initContainers }}
         {{- toYaml .Values.zookeeper.initContainers | nindent 6 }}
       {{- end }}
       containers:
@@ -132,6 +144,11 @@ spec:
         {{- if .Values.zookeeper.additionalCommand }}
           {{ .Values.zookeeper.additionalCommand }}
         {{- end }}
+          {{- if .Values.tls.zookeeper.cacerts.enabled }}
+          cd /pulsar/certs/cacerts;
+          nohup /pulsar/bin/certs-combine-pem-infinity.sh 
/pulsar/certs/cacerts/ca-combined.pem {{ template "pulsar.certs.cacerts" (dict 
"certs" .Values.tls.zookeeper.cacerts.certs) }} > 
/pulsar/certs/cacerts/certs-combine-pem-infinity.log 2>&1 &
+          cd /pulsar;
+          {{- end }}
           bin/apply-config-from-env.py conf/zookeeper.conf;
           {{- include "pulsar.zookeeper.tls.settings" . | nindent 10 }}
           bin/generate-zookeeper-config.sh conf/zookeeper.conf;
@@ -220,14 +237,7 @@ spec:
         - name: "{{ template "pulsar.fullname" . }}-{{ 
.Values.zookeeper.component }}-{{ .Values.zookeeper.volumes.datalog.name }}"
           mountPath: /pulsar/data-log
         {{- end }}
-        {{- if and .Values.tls.enabled .Values.tls.zookeeper.enabled }}
-        - mountPath: "/pulsar/certs/zookeeper"
-          name: zookeeper-certs
-          readOnly: true
-        - mountPath: "/pulsar/certs/ca"
-          name: ca
-          readOnly: true
-        {{- end }}
+        {{- include "pulsar.zookeeper.certs.volumeMounts" . | nindent 8 }}
         {{- if .Values.zookeeper.extraVolumeMounts }}
 {{ toYaml .Values.zookeeper.extraVolumeMounts | indent 8 }}
         {{- end }}
@@ -236,27 +246,10 @@ spec:
       - name: "{{ template "pulsar.fullname" . }}-{{ 
.Values.zookeeper.component }}-{{ .Values.zookeeper.volumes.data.name }}"
         emptyDir: {}
       {{- end }}
+      {{- include "pulsar.zookeeper.certs.volumes" . | nindent 6 }}
       {{- if .Values.zookeeper.extraVolumes }}
 {{ toYaml .Values.zookeeper.extraVolumes | indent 6 }}
       {{- end }}
-      {{- if and .Values.tls.enabled .Values.tls.zookeeper.enabled }}
-      - name: zookeeper-certs
-        secret:
-          secretName: "{{ .Release.Name }}-{{ .Values.tls.zookeeper.cert_name 
}}"
-          items:
-            - key: tls.crt
-              path: tls.crt
-            - key: tls.key
-              path: tls.key
-            - key: tls-combined.pem
-              path: tls-combined.pem
-      - name: ca
-        secret:
-          secretName: "{{ template "pulsar.certs.issuers.ca.secretName" . }}"
-          items:
-            - key: ca.crt
-              path: ca.crt
-      {{- end}}
       {{- include "pulsar.imagePullSecrets" . | nindent 6}}
 {{- if and (and .Values.persistence .Values.volumes.persistence) 
.Values.zookeeper.volumes.persistence }}
   volumeClaimTemplates:
diff --git a/charts/pulsar/values.yaml b/charts/pulsar/values.yaml
index 96f9951..2aadc39 100755
--- a/charts/pulsar/values.yaml
+++ b/charts/pulsar/values.yaml
@@ -241,6 +241,13 @@ tls:
     # The dnsNames field specifies a list of Subject Alternative Names to be 
associated with the certificate.
     dnsNames:
     # - example.com
+    cacerts:
+      enabled: false
+      certs:
+        # - name: proxy-cacert
+        #   existingSecret: proxy-cacert
+        #   secretKeys:
+        #     - ca.crt
   # settings for generating certs for broker
   broker:
     enabled: false
@@ -248,26 +255,69 @@ tls:
     # The dnsNames field specifies a list of Subject Alternative Names to be 
associated with the certificate.
     dnsNames:
     # - example.com
+    cacerts:
+      enabled: false
+      certs:
+        # - name: broker-cacert
+        #   existingSecret: broker-cacert
+        #   secretKeys:
+        #     - ca.crt
   # settings for generating certs for bookies
   bookie:
     enabled: false
     cert_name: tls-bookie
+    cacerts:
+      enabled: false
+      certs:
+        # - name: bookie-cacert
+        #   existingSecret: bookie-cacert
+        #   secretKeys:
+        #     - ca.crt
   # settings for generating certs for zookeeper
   zookeeper:
     enabled: false
     cert_name: tls-zookeeper
+    cacerts:
+      enabled: false
+      certs:
+        # - name: zookeeper-cacert
+        #   existingSecret: zookeeper-cacert
+        #   secretKeys:
+        #     - ca.crt
   # settings for generating certs for recovery
   autorecovery:
     cert_name: tls-recovery
+    cacerts:
+      enabled: false
+      certs:
+        # - name: autorecovery-cacert
+        #   existingSecret: autorecovery-cacert
+        #   secretKeys:
+        #     - ca.crt
   # settings for generating certs for toolset
   toolset:
     cert_name: tls-toolset
+    cacerts:
+      enabled: false
+      certs:
+        # - name: toolset-cacert
+        #   existingSecret: toolset-cacert
+        #   secretKeys:
+        #     - ca.crt
   # TLS setting for function runtime instance
   function_instance:
     # controls the use of TLS for function runtime connections towards brokers
     enabled: false
   oxia:
     enabled: false
+  pulsar_metadata:
+    cacerts:
+      enabled: false
+      certs:
+        # - name: pulsar-metadata-cacert
+        #   existingSecret: pulsar-metadata-cacert
+        #   secretKeys:
+        #     - ca.crt
 
 # Enable or disable broker authentication and authorization.
 auth:
@@ -1889,3 +1939,7 @@ initContainer:
     requests:
       memory: 256Mi
       cpu: 0.1
+
+## Array of extra objects to deploy with the release (evaluated as a template)
+##
+extraDeploy: []

Reply via email to