feat: support a CA bundle for the control plane connection - #447
feat: support a CA bundle for the control plane connection#447shreemaan-abhishek wants to merge 8 commits into
Conversation
tlsVerify offered only two states: verify against the system trust store, or do not verify at all. A control plane using a self-signed or private-CA certificate has no way to satisfy the first, so the only escape from the connection error is tlsVerify: false -- which turns the insecure opt-out into copy-paste boilerplate. Add the missing third state: an optional PEM-encoded caBundle on GatewayProxy.spec.provider.controlPlane, carried through the translated config to the ADC server, which verifies the control plane against it in place of the system trust store. Unusable CA material is rejected up front -- by a CEL rule at admission and by a PEM parse in the translator -- rather than surfacing later as an opaque TLS failure.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds an optional PEM CA bundle to GatewayProxy control-plane configuration, validates and translates it into ADC configuration, sends it in ADC requests, and logs only its presence. ChangesControl-plane CA bundle support
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant GatewayProxy
participant TranslateGatewayProxyToConfig
participant HTTPADCExecutor
participant ADCServer
GatewayProxy->>TranslateGatewayProxyToConfig: provide caBundle and tlsVerify
TranslateGatewayProxyToConfig->>TranslateGatewayProxyToConfig: validate PEM certificates
TranslateGatewayProxyToConfig->>HTTPADCExecutor: set Config.CaBundle
HTTPADCExecutor->>ADCServer: send caCert in PUT request
Possibly related PRs
🚥 Pre-merge checks | ✅ 5 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@api/v1alpha1/gatewayproxy_types.go`:
- Line 123: The caBundle validation currently accepts certificate-looking
content without enforcing a strictly valid PEM certificate bundle. Update the
validation logic around the GatewayProxy caBundle handling in
internal/adc/translator/gatewayproxy.go:60-64 to parse every PEM block, reject
trailing garbage and non-certificate blocks, and accept only valid certificates;
then update the caBundle XValidation annotation in
api/v1alpha1/gatewayproxy_types.go:123 and regenerate the corresponding CRD
validation in config/crd/bases/apisix.apache.org_gatewayproxies.yaml:168-170.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: a05e8c5e-fca5-4cea-88a4-9b2035151478
📒 Files selected for processing (9)
api/adc/types.goapi/v1alpha1/gatewayproxy_types.goconfig/crd-nocel/apisix.apache.org_v2.yamlconfig/crd/bases/apisix.apache.org_gatewayproxies.yamldocs/en/latest/reference/api-reference.mdinternal/adc/client/executor.gointernal/adc/client/executor_test.gointernal/adc/translator/gatewayproxy.gointernal/adc/translator/gatewayproxy_test.go
conformance test report - apisix-standalone modeapiVersion: gateway.networking.k8s.io/v1
date: "2026-08-26T10:00:21Z"
gatewayAPIChannel: experimental
gatewayAPIVersion: v1.6.0
implementation:
contact:
- https://github.com/apache/apisix-ingress-controller/issues
organization: APISIX
project: apisix-ingress-controller
url: https://github.com/apache/apisix-ingress-controller.git
version: v2.0.0
kind: ConformanceReport
mode: default
profiles:
- core:
result: partial
skippedTests:
- HTTPRouteHTTPSListener
- HTTPRouteInvalidBackendRefUnknownKind
- HTTPRouteInvalidCrossNamespaceBackendRef
- HTTPRouteInvalidNonExistentBackendRef
- HTTPRouteListenerHostnameMatching
- HTTPRouteMultipleGateways
- HTTPRouteNoBackendRefs
statistics:
Failed: 0
Passed: 30
Skipped: 7
extended:
result: partial
skippedTests:
- HTTPRouteRedirectPortAndScheme
statistics:
Failed: 0
Passed: 12
Skipped: 1
supportedFeatures:
- GatewayAddressEmpty
- GatewayPort8080
- HTTPRouteBackendProtocolWebSocket
- HTTPRouteDestinationPortMatching
- HTTPRouteHostRewrite
- HTTPRouteMethodMatching
- HTTPRoutePathRewrite
- HTTPRoutePortRedirect
- HTTPRouteQueryParamMatching
- HTTPRouteRequestMirror
- HTTPRouteResponseHeaderModification
- HTTPRouteSchemeRedirect
unsupportedFeatures:
- BackendTLSPolicy
- BackendTLSPolicySANValidation
- GatewayBackendClientCertificate
- GatewayFrontendClientCertificateValidation
- GatewayFrontendClientCertificateValidationInsecureFallback
- GatewayHTTPListenerIsolation
- GatewayHTTPSListenerDetectMisdirectedRequests
- GatewayInfrastructurePropagation
- GatewayStaticAddresses
- HTTPRoute303RedirectStatusCode
- HTTPRoute307RedirectStatusCode
- HTTPRoute308RedirectStatusCode
- HTTPRouteBackendProtocolH2C
- HTTPRouteBackendRequestHeaderModification
- HTTPRouteBackendTimeout
- HTTPRouteCORS
- HTTPRouteNamedRouteRule
- HTTPRouteParentRefPort
- HTTPRoutePathRedirect
- HTTPRouteRequestMultipleMirrors
- HTTPRouteRequestPercentageMirror
- HTTPRouteRequestTimeout
- HTTPRouteRetry
- HTTPRouteRetryBackendTimeout
- HTTPRouteRetryConnectionError
- ListenerSet
name: GATEWAY-HTTP
summary: Core tests partially succeeded with 7 test skips. Extended tests partially
succeeded with 1 test skips.
- core:
result: partial
skippedTests:
- GRPCRouteListenerHostnameMatching
statistics:
Failed: 0
Passed: 14
Skipped: 1
extended:
result: success
statistics:
Failed: 0
Passed: 1
Skipped: 0
supportedFeatures:
- GatewayAddressEmpty
- GatewayPort8080
unsupportedFeatures:
- GatewayBackendClientCertificate
- GatewayFrontendClientCertificateValidation
- GatewayFrontendClientCertificateValidationInsecureFallback
- GatewayHTTPListenerIsolation
- GatewayHTTPSListenerDetectMisdirectedRequests
- GatewayInfrastructurePropagation
- GatewayStaticAddresses
- ListenerSet
name: GATEWAY-GRPC
summary: Core tests partially succeeded with 1 test skips. Extended tests succeeded.
- core:
result: partial
skippedTests:
- TLSRouteHostnameIntersection
- TLSRouteInvalidBackendRefNonexistent
- TLSRouteInvalidBackendRefUnknownKind
- TLSRouteSimpleSameNamespace
statistics:
Failed: 0
Passed: 16
Skipped: 4
extended:
result: partial
skippedTests:
- TLSRouteTerminateSimpleSameNamespace
statistics:
Failed: 0
Passed: 3
Skipped: 1
supportedFeatures:
- GatewayAddressEmpty
- GatewayPort8080
- TLSRouteModeTerminate
unsupportedFeatures:
- GatewayBackendClientCertificate
- GatewayFrontendClientCertificateValidation
- GatewayFrontendClientCertificateValidationInsecureFallback
- GatewayHTTPListenerIsolation
- GatewayHTTPSListenerDetectMisdirectedRequests
- GatewayInfrastructurePropagation
- GatewayStaticAddresses
- ListenerSet
- TLSRouteModeMixed
name: GATEWAY-TLS
summary: Core tests partially succeeded with 4 test skips. Extended tests partially
succeeded with 1 test skips.
succeededProvisionalTests:
- GatewayOptionalAddressValue |
conformance test report - apisix modeapiVersion: gateway.networking.k8s.io/v1
date: "2026-08-26T10:00:42Z"
gatewayAPIChannel: experimental
gatewayAPIVersion: v1.6.0
implementation:
contact:
- https://github.com/apache/apisix-ingress-controller/issues
organization: APISIX
project: apisix-ingress-controller
url: https://github.com/apache/apisix-ingress-controller.git
version: v2.0.0
kind: ConformanceReport
mode: default
profiles:
- core:
result: partial
skippedTests:
- HTTPRouteHTTPSListener
- HTTPRouteInvalidBackendRefUnknownKind
- HTTPRouteInvalidCrossNamespaceBackendRef
- HTTPRouteInvalidNonExistentBackendRef
- HTTPRouteListenerHostnameMatching
- HTTPRouteMultipleGateways
- HTTPRouteNoBackendRefs
statistics:
Failed: 0
Passed: 30
Skipped: 7
extended:
result: partial
skippedTests:
- HTTPRouteRedirectPortAndScheme
statistics:
Failed: 0
Passed: 12
Skipped: 1
supportedFeatures:
- GatewayAddressEmpty
- GatewayPort8080
- HTTPRouteBackendProtocolWebSocket
- HTTPRouteDestinationPortMatching
- HTTPRouteHostRewrite
- HTTPRouteMethodMatching
- HTTPRoutePathRewrite
- HTTPRoutePortRedirect
- HTTPRouteQueryParamMatching
- HTTPRouteRequestMirror
- HTTPRouteResponseHeaderModification
- HTTPRouteSchemeRedirect
unsupportedFeatures:
- BackendTLSPolicy
- BackendTLSPolicySANValidation
- GatewayBackendClientCertificate
- GatewayFrontendClientCertificateValidation
- GatewayFrontendClientCertificateValidationInsecureFallback
- GatewayHTTPListenerIsolation
- GatewayHTTPSListenerDetectMisdirectedRequests
- GatewayInfrastructurePropagation
- GatewayStaticAddresses
- HTTPRoute303RedirectStatusCode
- HTTPRoute307RedirectStatusCode
- HTTPRoute308RedirectStatusCode
- HTTPRouteBackendProtocolH2C
- HTTPRouteBackendRequestHeaderModification
- HTTPRouteBackendTimeout
- HTTPRouteCORS
- HTTPRouteNamedRouteRule
- HTTPRouteParentRefPort
- HTTPRoutePathRedirect
- HTTPRouteRequestMultipleMirrors
- HTTPRouteRequestPercentageMirror
- HTTPRouteRequestTimeout
- HTTPRouteRetry
- HTTPRouteRetryBackendTimeout
- HTTPRouteRetryConnectionError
- ListenerSet
name: GATEWAY-HTTP
summary: Core tests partially succeeded with 7 test skips. Extended tests partially
succeeded with 1 test skips.
- core:
result: partial
skippedTests:
- GRPCRouteListenerHostnameMatching
statistics:
Failed: 0
Passed: 14
Skipped: 1
extended:
result: success
statistics:
Failed: 0
Passed: 1
Skipped: 0
supportedFeatures:
- GatewayAddressEmpty
- GatewayPort8080
unsupportedFeatures:
- GatewayBackendClientCertificate
- GatewayFrontendClientCertificateValidation
- GatewayFrontendClientCertificateValidationInsecureFallback
- GatewayHTTPListenerIsolation
- GatewayHTTPSListenerDetectMisdirectedRequests
- GatewayInfrastructurePropagation
- GatewayStaticAddresses
- ListenerSet
name: GATEWAY-GRPC
summary: Core tests partially succeeded with 1 test skips. Extended tests succeeded.
- core:
result: partial
skippedTests:
- TLSRouteHostnameIntersection
- TLSRouteInvalidBackendRefNonexistent
- TLSRouteInvalidBackendRefUnknownKind
- TLSRouteSimpleSameNamespace
statistics:
Failed: 0
Passed: 16
Skipped: 4
extended:
result: partial
skippedTests:
- TLSRouteTerminateSimpleSameNamespace
statistics:
Failed: 0
Passed: 3
Skipped: 1
supportedFeatures:
- GatewayAddressEmpty
- GatewayPort8080
- TLSRouteModeTerminate
unsupportedFeatures:
- GatewayBackendClientCertificate
- GatewayFrontendClientCertificateValidation
- GatewayFrontendClientCertificateValidationInsecureFallback
- GatewayHTTPListenerIsolation
- GatewayHTTPSListenerDetectMisdirectedRequests
- GatewayInfrastructurePropagation
- GatewayStaticAddresses
- ListenerSet
- TLSRouteModeMixed
name: GATEWAY-TLS
summary: Core tests partially succeeded with 4 test skips. Extended tests partially
succeeded with 1 test skips.
succeededProvisionalTests:
- GatewayOptionalAddressValue |
conformance test reportapiVersion: gateway.networking.k8s.io/v1
date: "2026-08-26T10:20:20Z"
gatewayAPIChannel: experimental
gatewayAPIVersion: v1.6.0
implementation:
contact:
- https://github.com/apache/apisix-ingress-controller/issues
organization: APISIX
project: apisix-ingress-controller
url: https://github.com/apache/apisix-ingress-controller.git
version: v2.0.0
kind: ConformanceReport
mode: default
profiles:
- core:
failedTests:
- GatewayModifyListeners
- HTTPRouteMultipleGateways
- HTTPRouteNoBackendRefs
result: failure
skippedTests:
- HTTPRouteHTTPSListener
statistics:
Failed: 3
Passed: 33
Skipped: 1
extended:
result: partial
skippedTests:
- HTTPRouteRedirectPortAndScheme
statistics:
Failed: 0
Passed: 12
Skipped: 1
supportedFeatures:
- GatewayAddressEmpty
- GatewayPort8080
- HTTPRouteBackendProtocolWebSocket
- HTTPRouteDestinationPortMatching
- HTTPRouteHostRewrite
- HTTPRouteMethodMatching
- HTTPRoutePathRewrite
- HTTPRoutePortRedirect
- HTTPRouteQueryParamMatching
- HTTPRouteRequestMirror
- HTTPRouteResponseHeaderModification
- HTTPRouteSchemeRedirect
unsupportedFeatures:
- BackendTLSPolicy
- BackendTLSPolicySANValidation
- GatewayBackendClientCertificate
- GatewayFrontendClientCertificateValidation
- GatewayFrontendClientCertificateValidationInsecureFallback
- GatewayHTTPListenerIsolation
- GatewayHTTPSListenerDetectMisdirectedRequests
- GatewayInfrastructurePropagation
- GatewayStaticAddresses
- HTTPRoute303RedirectStatusCode
- HTTPRoute307RedirectStatusCode
- HTTPRoute308RedirectStatusCode
- HTTPRouteBackendProtocolH2C
- HTTPRouteBackendRequestHeaderModification
- HTTPRouteBackendTimeout
- HTTPRouteCORS
- HTTPRouteNamedRouteRule
- HTTPRouteParentRefPort
- HTTPRoutePathRedirect
- HTTPRouteRequestMultipleMirrors
- HTTPRouteRequestPercentageMirror
- HTTPRouteRequestTimeout
- HTTPRouteRetry
- HTTPRouteRetryBackendTimeout
- HTTPRouteRetryConnectionError
- ListenerSet
name: GATEWAY-HTTP
summary: Core tests failed with 3 test failures. Extended tests partially succeeded
with 1 test skips.
- core:
failedTests:
- GatewayModifyListeners
result: failure
statistics:
Failed: 1
Passed: 14
Skipped: 0
extended:
result: success
statistics:
Failed: 0
Passed: 1
Skipped: 0
supportedFeatures:
- GatewayAddressEmpty
- GatewayPort8080
unsupportedFeatures:
- GatewayBackendClientCertificate
- GatewayFrontendClientCertificateValidation
- GatewayFrontendClientCertificateValidationInsecureFallback
- GatewayHTTPListenerIsolation
- GatewayHTTPSListenerDetectMisdirectedRequests
- GatewayInfrastructurePropagation
- GatewayStaticAddresses
- ListenerSet
name: GATEWAY-GRPC
summary: Core tests failed with 1 test failures. Extended tests succeeded.
- core:
failedTests:
- GatewayModifyListeners
- TLSRouteHostnameIntersection
- TLSRouteInvalidBackendRefNonexistent
- TLSRouteInvalidBackendRefUnknownKind
- TLSRouteSimpleSameNamespace
result: failure
statistics:
Failed: 5
Passed: 15
Skipped: 0
extended:
failedTests:
- TLSRouteTerminateSimpleSameNamespace
result: failure
statistics:
Failed: 1
Passed: 3
Skipped: 0
supportedFeatures:
- GatewayAddressEmpty
- GatewayPort8080
- TLSRouteModeTerminate
unsupportedFeatures:
- GatewayBackendClientCertificate
- GatewayFrontendClientCertificateValidation
- GatewayFrontendClientCertificateValidationInsecureFallback
- GatewayHTTPListenerIsolation
- GatewayHTTPSListenerDetectMisdirectedRequests
- GatewayInfrastructurePropagation
- GatewayStaticAddresses
- ListenerSet
- TLSRouteModeMixed
name: GATEWAY-TLS
summary: Core tests failed with 5 test failures. Extended tests failed with 1 test
failures.
succeededProvisionalTests:
- GatewayOptionalAddressValue |
x509.CertPool skips PEM blocks it cannot decode, so a bundle whose second certificate is broken passed validation here and failed later at the ADC server, which parses the whole bundle. Reject it up front instead.
|
Pushed a follow-up from the review of the ADC-side PR (api7/adc#537): the CA bundle is now validated by parsing every certificate in it.
Test cases added for a header with no certificate, an unparseable body, a private key in place of a certificate, and one good plus one broken certificate; a multi-certificate bundle is still accepted. |
Both call sites pass http.MethodPut, and the new test made unparam report it. Set the method inside instead of threading it through.
# Conflicts: # api/adc/types.go # internal/adc/client/executor.go # internal/adc/client/executor_test.go
| // Set it when the control plane uses a self-signed or private CA certificate. | ||
| // It has no effect when tlsVerify is false. | ||
| // +optional | ||
| CaBundle string `json:"caBundle,omitempty"` |
There was a problem hiding this comment.
[P1] Update the Helm-bundled CRD before exposing this field. api7/api7-helm-chart still has no caBundle property in charts/ingress-controller/crds/apisix-crds.yaml. With that standard installation the API server prunes this unknown field, so the controller never receives it. Please add the paired Helm chart PR and release dependency.
| // CaCert is the PEM-encoded CA certificate (or bundle) the ADC server verifies | ||
| // the control plane against. Older ADC servers ignore it, and omitempty keeps | ||
| // requests without a CA bundle byte for byte what they were. | ||
| CaCert string `json:"caCert,omitempty"` |
There was a problem hiding this comment.
[P1] Ship an ADC version that honors caCert. This repository still pins ADC 0.27.1 and the API7 Helm chart pins 0.26.0, while api7/adc#537 is open and unreleased; both released sidecars accept this unknown option but ignore it. The CRD can therefore be accepted while private-CA verification still fails in every normal install. Please merge and release the ADC change, bump the pinned/chart image, and exercise this TLS path end to end before merging this PR.
The CA bundle reaches the ADC server as caCert, which lands in 0.29.0 (api7/adc#552). Older sidecars accept the option and ignore it, so the CRD field would be set while verification still fails.
|
Follow-up: pinned ADC 0.29.0, keeping this in step with apache/apisix-ingress-controller#2826. Worth recording, since the PR body said otherwise: api7/adc#537 was closed, not merged. The server-side support landed via api7/adc#552 ( Verified against the published image rather than assumed: |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@Makefile`:
- Line 33: Update the Makefile download rule that uses ADC_VERSION so Windows
selects the ADC .zip asset and extracts it with the appropriate
Windows-compatible command, while Linux and macOS continue using .tar.gz.
Preserve support for ADC_VERSION=dev and ensure the platform-specific archive
naming and extraction paths remain consistent.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
|
|
||
| DASHBOARD_VERSION ?= dev | ||
| ADC_VERSION ?= 0.27.1 | ||
| ADC_VERSION ?= 0.29.0 |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n -C 5 'ADC_VERSION|kind-load-adc-image|ghcr.io/api7/adc' \
Makefile .github/workflows
curl -fsSL https://api.github.com/repos/api7/adc/releases/tags/v0.29.0 |
python -c '
import json
import sys
release = json.load(sys.stdin)
assert release["tag_name"] == "v0.29.0"
for asset in release["assets"]:
print(asset["name"])
'Repository: api7/api7-ingress-controller
Length of output: 10521
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- Makefile platform variables and ADC targets ---'
rg -n -C 8 '^(GOOS|GOARCH)|ADC_BIN|^adc:|adc_\$\{ADC_VERSION\}|CA.?bundle|ca.?bundle' Makefile
printf '%s\n' '--- Workflow ADC and CA-bundle references ---'
rg -n -i -C 6 'ADC_VERSION|adc(\.js|-temp)?|ca.?bundle' .github/workflowsRepository: api7/api7-ingress-controller
Length of output: 11607
Handle Windows ADC archives in the download rule.
CI intentionally uses ADC_VERSION=dev in the E2E workflows. The v0.29.0 Linux and macOS assets match the .tar.gz download rule, but its Windows assets use .zip. If Windows is supported, select the correct archive format and extraction command.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@Makefile` at line 33, Update the Makefile download rule that uses ADC_VERSION
so Windows selects the ADC .zip asset and extracts it with the appropriate
Windows-compatible command, while Linux and macOS continue using .tar.gz.
Preserve support for ADC_VERSION=dev and ensure the platform-specific archive
naming and extraction paths remain consistent.
Puts an openresty in front of the admin API to stand in for a control plane published over TLS, with a certificate signed by a CA generated per test -- the case caBundle exists for, since nothing in the system trust store can verify it. Three specs: the route is programmed when the bundle is trusted, the sync fails on certificate verification when it is absent, and the API server rejects a caBundle that is not a certificate. The certificates are generated locally rather than with the scaffold's GenerateMACert, which gives the CA and the leaf the same subject; OpenSSL reads that as self-issued and rejects it without ever chaining to the CA.
|
Added in The admin API only listens on plain HTTP, so the spec puts an openresty in front of it to stand in for a control plane published over TLS. Its certificate is signed by a CA generated per test, which is exactly the case Three specs:
Run locally against kind, both provider modes: Writing it turned up something worth flagging separately: the spec generates its certificates locally instead of using It goes unnoticed today because the current callers verify with Go's x509 (webhook |
|
Merged Note on the one red job, Every job covering this PR's specs ( |
…envelope Follows the value/valueFrom shape adminKey already uses on the same struct, so a valueFrom source can be added later without breaking existing resources. Only the inline value is supported today. The PEM check moves from a provider-level CEL rule onto the field.
Closes #446
What this PR does
GatewayProxy.spec.provider.controlPlane.tlsVerifyoffers only two states today:tlsVerify: false— no verification.tlsVerify: true— verify against the system trust store only, which works only if the control plane's certificate chains to a publicly trusted CA.There is no way to supply a custom CA, so for the common case of a self-signed or private-CA control plane a user who wants verification on has no path to make it succeed. The only escape from the resulting connection error is
tlsVerify: false— which risks turning the insecure opt-out into copy-paste boilerplate, and undercuts the secure default being introduced in #438.This adds the missing third state —
tlsVerify: true+ a CA bundle:Design notes
Inline PEM, not a Secret/ConfigMap ref (one of the open questions in #446). A CA certificate is public material, so a Secret buys no confidentiality here, and an inline field is what Kubernetes itself uses for the same job (
WebhookClientConfig.CABundle). It also keeps the change to the data path: no new watch, index, or RBAC rule, and rotating the bundle is an edit of the GatewayProxy the controller already reconciles on. AcaBundleRefcan be layered on later without breaking this field.Invalid CA material fails fast, in two places. A CEL rule rejects a non-PEM
caBundleat admission, and the translator parses it withx509.CertPool.AppendCertsFromPEMand returns an error before any config is pushed — so a typo surfaces as a clear message instead of an opaque TLS failure at connect time.Interaction with
tlsVerify. The bundle replaces the system trust store when verification is on, and is ignored when it is off — the controller logs that case rather than silently doing nothing. It is still sent, so flippingtlsVerifyback on needs no other change.Wire compatibility. The bundle reaches the ADC server as
caCertin the task options,omitemptyso that a GatewayProxy without a CA bundle produces byte-for-byte the request an older ADC server already accepts. Logging carries onlyhasCaCert/hasCaBundlebooleans, never the material itself.Dependency
The ADC-side blocker flagged in #446— resolved. api7/adc#537 was closed in favour of api7/adc#552, which shipped in ADC v0.29.0 using the samecaCerttask option this PR sends. This PR pins 0.29.0 in theMakefile.Sync
Paired open source PR, same change: apache/apisix-ingress-controller#2826. The Go hunks are identical between the two repos; this side additionally updates
config/crd-nocel, which has no upstream counterpart.Changes
api/v1alpha1/gatewayproxy_types.go:caBundleonControlPlaneProvider, plus the CEL validation rule.api/adc/types.go:Config.CaBundle;MarshalJSONreportshasCaBundlerather than the PEM.internal/adc/translator/gatewayproxy.go: validate the PEM, warn whentlsVerifyis off, set it on the config.internal/adc/client/executor.go: carry it to the ADC server ascaCert.crd-nocelbundle (no CEL rule there, by design), API reference updated by hand to match.Tests
internal/adc/translator/gatewayproxy_test.go(new): the bundle reachesConfig, stays empty when unset, is rejected when not PEM, and survivestlsVerify: false.internal/adc/client/executor_test.go(new):caCertis absent from the request body without a bundle and present with one, withtlsSkipVerifystill false.Both CRD variants were also exercised against a real API server via envtest:
config/crd/basesadmits a PEM bundle and rejectsnot-a-certificatewithcaBundle must be a PEM-encoded certificate, and theconfig/crd-nocelbundle installs cleanly and round-tripscaBundle. Those checks are not committed, since this package has no envtest specs today and adding the first one would makego test ./internal/controllerrequire the kubebuilder assets.Summary by CodeRabbit
New Features
caBundle) to verify control-plane TLS certificates.Bug Fixes
Documentation / Tests