From 1fabe75ded45a3052b2f51140fa5bcf4fe88cf6d Mon Sep 17 00:00:00 2001 From: Jarvis Date: Tue, 14 Jul 2026 20:31:12 +0800 Subject: [PATCH 1/2] feat(gateway): support extra trusted CAs via additionalTrustedCAs The gateway outbound trust store (ssl_trusted_certificate) exposes a single CA-file slot through gateway.tls.existingCASecret/certCAFilename. In a Control Plane-managed deployment that slot already carries the CP/DP-Manager CA (the gateway verifies the CP over the same trust store because etcd.auth.tls.verify is true), so there was no clean way to trust an additional private/enterprise CA (e.g. an openid-connect IdP reached over TLS) without merging it into the CP-managed Secret and restarting. Add gateway.tls.additionalTrustedCAs: a list of {secretName, filename} entries. The chart mounts each file into the gateway and appends its path to ssl_trusted_certificate, so the rendered value becomes "system,," - system CAs and the existing CP CA are preserved. Rendering is unchanged when the list is empty. Takes effect after a gateway Pod restart, since the trust store is merged at startup. Backport of the main-line change to the 3.9 chart line. --- charts/gateway/Chart.yaml | 2 +- charts/gateway/README.md | 3 ++- charts/gateway/templates/_helpers.tpl | 23 +++++++++++++++++++++++ charts/gateway/templates/_pod.tpl | 14 ++++++++++++++ charts/gateway/templates/configmap.yaml | 4 ++-- charts/gateway/values.yaml | 4 ++++ 6 files changed, 46 insertions(+), 4 deletions(-) diff --git a/charts/gateway/Chart.yaml b/charts/gateway/Chart.yaml index 78bef5cb..ccd95c7a 100644 --- a/charts/gateway/Chart.yaml +++ b/charts/gateway/Chart.yaml @@ -16,7 +16,7 @@ type: application # Versions are expected to follow Semantic Versioning (https://semver.org/) # major.minor mirrors the API7 EE release line (3.9.x), patch is this chart's # own counter on that line and is decoupled from the app patch (see appVersion). -version: 3.9.5 +version: 3.9.6 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/charts/gateway/README.md b/charts/gateway/README.md index 4c72f24a..04c19721 100644 --- a/charts/gateway/README.md +++ b/charts/gateway/README.md @@ -193,8 +193,9 @@ The command removes all the Kubernetes components associated with the chart and | gateway.readinessProbe | object | `{}` | kubernetes readiness probe, we will provide a probe based on tcpSocket to gateway's HTTP port by default. | | gateway.stream | object | `{"autoAssignNodePort":false,"enabled":false,"only":false,"tcp":[],"udp":[]}` | API7 Gateway service settings for stream. L4 proxy (TCP/UDP) | | gateway.stream.autoAssignNodePort | bool | `false` | Whether to set nodePort to the same value as the TCP/UDP port when gateway.type is NodePort, make sure the nodePort to be in the valid NodePort range of kubernetes service. | -| gateway.tls | object | `{"additionalContainerPorts":[],"certCAFilename":"","containerPort":9443,"enabled":true,"existingCASecret":"","fallbackSNI":"","http2":{"enabled":true},"ip":"0.0.0.0","nodePort":null,"servicePort":443,"sslProtocols":"TLSv1.2 TLSv1.3"}` | API7 Gateway service settings for tls | +| gateway.tls | object | `{"additionalContainerPorts":[],"additionalTrustedCAs":[],"certCAFilename":"","containerPort":9443,"enabled":true,"existingCASecret":"","fallbackSNI":"","http2":{"enabled":true},"ip":"0.0.0.0","nodePort":null,"servicePort":443,"sslProtocols":"TLSv1.2 TLSv1.3"}` | API7 Gateway service settings for tls | | gateway.tls.additionalContainerPorts | list | `[]` | Support multiple https ports, See [Configuration](https://github.com/apache/apisix/blob/0bc65ea9acd726f79f80ae0abd8f50b7eb172e3d/conf/config-default.yaml#L99) | +| gateway.tls.additionalTrustedCAs | list | `[]` | Additional CA certificates to append to the gateway's outbound trust store (`ssl_trusted_certificate`), on top of the system CAs and `existingCASecret`. Each entry mounts `filename` from the given Secret `secretName` into the gateway and adds it to the trust list, so the gateway can verify external services signed by a private/enterprise CA (e.g. an `openid-connect` identity provider) without replacing the Control Plane-managed CA in `existingCASecret`. Takes effect after a gateway Pod restart, because the trust store is merged at startup. | | gateway.tls.certCAFilename | string | `""` | Filename be used in the gateway.tls.existingCASecret | | gateway.tls.existingCASecret | string | `""` | Specifies the name of Secret contains trusted CA certificates in the PEM format used to verify the certificate when APISIX needs to do SSL/TLS handshaking with external services (e.g. etcd) | | gateway.tls.fallbackSNI | string | `""` | If set this, when the client doesn't send SNI during handshake, the fallback SNI will be used instead | diff --git a/charts/gateway/templates/_helpers.tpl b/charts/gateway/templates/_helpers.tpl index a5e0bd62..a2446bbd 100644 --- a/charts/gateway/templates/_helpers.tpl +++ b/charts/gateway/templates/_helpers.tpl @@ -196,3 +196,26 @@ Output: JSON {"entries": [{"port": 9200, "nodePort": ""}, ...]} {{- end -}} {{- dict "entries" $result | toJson -}} {{- end -}} + +{{/* +Build the value of `apisix.ssl.ssl_trusted_certificate` — the gateway's outbound +trust store. Starts from the system CA bundle (`system`), then appends the +Control Plane CA (gateway.tls.existingCASecret) and every entry in +gateway.tls.additionalTrustedCAs, matching the mount paths rendered in _pod.tpl. +Returns an empty string when TLS is disabled or no CA is configured, so the +caller can omit the key entirely. +*/}} +{{- define "gateway.sslTrustedCertificate" -}} +{{- if .Values.gateway.tls.enabled -}} +{{- $paths := list -}} +{{- if .Values.gateway.tls.existingCASecret -}} +{{- $paths = append $paths (printf "/usr/local/apisix/conf/ssl/%s" .Values.gateway.tls.certCAFilename) -}} +{{- end -}} +{{- range $i, $ca := .Values.gateway.tls.additionalTrustedCAs -}} +{{- $paths = append $paths (printf "/usr/local/apisix/conf/ssl/additional-ca-%d/%s" $i $ca.filename) -}} +{{- end -}} +{{- if $paths -}} +{{- printf "system,%s" (join "," $paths) -}} +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/gateway/templates/_pod.tpl b/charts/gateway/templates/_pod.tpl index 494e0bbd..3b1a7eee 100644 --- a/charts/gateway/templates/_pod.tpl +++ b/charts/gateway/templates/_pod.tpl @@ -189,6 +189,13 @@ spec: name: ssl subPath: {{ .Values.gateway.tls.certCAFilename }} {{- end }} + {{- if .Values.gateway.tls.enabled }} + {{- range $i, $ca := .Values.gateway.tls.additionalTrustedCAs }} + - mountPath: /usr/local/apisix/conf/ssl/additional-ca-{{ $i }} + name: additional-ca-{{ $i }} + readOnly: true + {{- end }} + {{- end }} {{- if .Values.etcd.auth.tls.enabled }} - mountPath: /etcd-ssl @@ -296,6 +303,13 @@ spec: secretName: {{ .Values.gateway.tls.existingCASecret | quote }} name: ssl {{- end }} + {{- if .Values.gateway.tls.enabled }} + {{- range $i, $ca := .Values.gateway.tls.additionalTrustedCAs }} + - secret: + secretName: {{ $ca.secretName | quote }} + name: additional-ca-{{ $i }} + {{- end }} + {{- end }} {{- if .Values.etcd.auth.tls.enabled }} - secret: secretName: {{ .Values.etcd.auth.tls.existingSecret | quote }} diff --git a/charts/gateway/templates/configmap.yaml b/charts/gateway/templates/configmap.yaml index a1cea487..fbd36fe6 100644 --- a/charts/gateway/templates/configmap.yaml +++ b/charts/gateway/templates/configmap.yaml @@ -142,8 +142,8 @@ data: {{- end }} ssl_protocols: {{ .Values.gateway.tls.sslProtocols | quote }} ssl_ciphers: "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA" - {{- if and .Values.gateway.tls.enabled .Values.gateway.tls.existingCASecret }} - ssl_trusted_certificate: "system,/usr/local/apisix/conf/ssl/{{ .Values.gateway.tls.certCAFilename }}" + {{- with (include "gateway.sslTrustedCertificate" .) }} + ssl_trusted_certificate: {{ . | quote }} {{- end }} {{- if .Values.gateway.tls.fallbackSNI }} fallback_sni: {{ .Values.gateway.tls.fallbackSNI }} diff --git a/charts/gateway/values.yaml b/charts/gateway/values.yaml index c9afaaa9..80f2a93a 100644 --- a/charts/gateway/values.yaml +++ b/charts/gateway/values.yaml @@ -350,6 +350,10 @@ gateway: existingCASecret: "" # -- Filename be used in the gateway.tls.existingCASecret certCAFilename: "" + # -- Additional CA certificates to append to the gateway's outbound trust store (`ssl_trusted_certificate`), on top of the system CAs and `existingCASecret`. Each entry mounts `filename` from the given Secret `secretName` into the gateway and adds it to the trust list, so the gateway can verify external services signed by a private/enterprise CA (e.g. an `openid-connect` identity provider) without replacing the Control Plane-managed CA in `existingCASecret`. Takes effect after a gateway Pod restart, because the trust store is merged at startup. + additionalTrustedCAs: [] + # - secretName: keycloak-ca + # filename: keycloak-ca.crt http2: enabled: true # -- TLS protocols allowed to use. From 068350012e4f58e08a40ac0f63ad43cebb2b3ee9 Mon Sep 17 00:00:00 2001 From: Jarvis Date: Tue, 14 Jul 2026 20:41:45 +0800 Subject: [PATCH 2/2] fix(gateway): project only the CA file from additionalTrustedCAs Secret Add an items projection so each additionalTrustedCAs volume mounts only the configured filename from the Secret, instead of every key. Least-privilege: avoids exposing unrelated Secret keys in the gateway filesystem. --- charts/gateway/templates/_pod.tpl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/charts/gateway/templates/_pod.tpl b/charts/gateway/templates/_pod.tpl index 3b1a7eee..fe7165e9 100644 --- a/charts/gateway/templates/_pod.tpl +++ b/charts/gateway/templates/_pod.tpl @@ -307,6 +307,9 @@ spec: {{- range $i, $ca := .Values.gateway.tls.additionalTrustedCAs }} - secret: secretName: {{ $ca.secretName | quote }} + items: + - key: {{ $ca.filename | quote }} + path: {{ $ca.filename | quote }} name: additional-ca-{{ $i }} {{- end }} {{- end }}