feat: add ADC-backed admission validation for APISIX CRDs#2758
Open
AlinsRan wants to merge 15 commits intoapache:masterfrom
Open
feat: add ADC-backed admission validation for APISIX CRDs#2758AlinsRan wants to merge 15 commits intoapache:masterfrom
AlinsRan wants to merge 15 commits intoapache:masterfrom
Conversation
Validate ApisixRoute, ApisixConsumer, ApisixTls and Consumer resources against a live APISIX instance during admission instead of only producing warnings. Key changes: - Add ADCValidationErrors / ADCValidationError types (internal/types) - Add Validate() to HTTPADCExecutor and Client; introduce the /configs/validate endpoint support in executor.go (TLS min-version set to 1.2, request body no longer logged in full) - Add internal/controller/webhook_validation.go: lightweight helpers (PrepareApisixRouteForValidation, PrepareApisixConsumerForValidation, PrepareConsumerForValidation, PrepareApisixTlsForValidation) that build a TranslateContext without starting the full reconciler loop - Add internal/webhook/v1/adc_validation.go: adcAdmissionValidator that translates a CRD into an ADC payload and posts it to APISIX for structural validation; fails open on infrastructure errors - Wire adcAdmissionValidator into all four webhook validators; init errors are logged and ignored (fail-open) - ApisixTls: skip ADC validation when secrets are missing to preserve the existing warn-only behaviour for that case - Consumer: validate duplicate key-auth credential keys scoped to the same GatewayRef using a field-index query; malformed inline JSON is logged and skipped (not a hard denial) - global_rules and plugin_metadata are now populated in the ADC validate payload so APISIX can resolve plugin references Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ApisixRoute and ApisixConsumer: skip ADC validation when collectWarnings already found missing references (services / secrets). This preserves the existing warn-and-admit behaviour for incomplete resources, matching the pattern already used for ApisixTls. Also fix trailing newline in consumer_webhook.go caught by gofmt. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add e2e tests covering ADC-backed admission validation for all four webhook resource types. Each new test case is gated with a provider check so it only runs against the apisix-standalone backend. - ApisixRoute: reject route with invalid response-rewrite plugin config - ApisixConsumer: reject consumer with invalid jwt-auth algorithm - ApisixTls: reject TLS resource backed by invalid certificate material - Consumer: reject consumer with invalid jwt-auth algorithm Also add the expectAdmissionDenied helper to the webhook package and update the ApisixTls warn-on-missing test to use real generated certificate material for the success assertion. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add update-path e2e coverage for all four webhook resource types. ValidateUpdate is wired to the same ADC validator as ValidateCreate, and these tests verify that invalid configs are rejected on update too. - ApisixRoute: reject update with invalid response-rewrite plugin config - ApisixConsumer: reject update with invalid jwt-auth algorithm - ApisixTls: reject update when referenced secret contains invalid cert data - Consumer: reject update with invalid jwt-auth algorithm Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add expectUpdateDenied helper: UPDATE denials leave the resource intact so the resource-not-found check in expectAdmissionDenied is wrong for update scenarios - Use expectUpdateDenied in all four UPDATE It blocks - Redesign ApisixTls UPDATE test: change the secret reference in the spec instead of swapping secret content; spec must actually change to trigger the UPDATE admission webhook Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Both apisix and apisix-standalone backends now support /apisix/admin/configs/validate via ADC PR api7/adc#434. The CI uses apache/apisix:dev and ghcr.io/api7/adc:dev which include this support, so the skip guard is no longer needed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Previously the apisix-standalone backend bypassed the ADC server and called APISIX's /apisix/admin/configs/validate directly. With api7/adc#440, the ADC server now exposes a /validate endpoint (same input format as /sync) that handles both apisix-standalone and apisix backends uniformly. Changes: - Remove apisix-standalone special-case in runHTTPValidateForSingleServer; all backends now call ADC server POST /validate - Fix ADCValidateResult.ErrorMessage JSON tag: errorMessage -> message to match the ADC server response format from api7/adc#440 - Remove buildAPISIXValidateRequest, apisixValidateRequest, newBackendHTTPClient, buildAPISIXValidatePayload and helpers - Update unit tests accordingly Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The ADC server registers PUT /validate (not POST), matching the same HTTP method used for PUT /sync. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
APISIX validates plugin schemas but not credential schemas via /validate. Switch the invalid Consumer config in e2e tests to use spec.plugins with jwt-auth algorithm: INVALID_ALGO, which triggers proper ADC validation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove redundant failurePolicy=fail from all 4 webhook marker lines, keeping only failurePolicy=Ignore (kubebuilder uses the last occurrence, having both was ambiguous and wrong). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the len(warnings) > 0 guard that was skipping ADC validation when service or secret references were missing. ApisixRoute plugin schemas can be validated by ADC independently of whether the backend service exists. Running ADC even with missing references provides stronger safety guarantees. Also update the warning test to only test missing service references, consistent with the enterprise version. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds live ADC-backed admission validation to the existing webhook validators for
ApisixRoute,ApisixConsumer,ApisixTls, andConsumerresources.Previously the webhooks only emitted warnings for missing references (services, secrets). With this change, resources are also structurally validated against a live APISIX instance before being admitted.
Changes
Core infrastructure
internal/types/error.go: AddADCValidationErrors,ADCValidationError,ADCValidationServerAddrError, andADCValidationDetailtypes to carry structured validation error details.internal/adc/client/executor.go:Validate()to theADCExecutorinterface andHTTPADCExecutorrunHTTPValidate/runHTTPValidateForSingleServerthat POST to the/configs/validateendpointbuildHTTPRequestto accept an HTTP method and path (supporting both/syncand/configs/validate)internal/adc/client/client.go: AddClient.Validate()which calls the executor's validate path and aggregatesADCValidationErrors.Webhook validation helpers
internal/controller/webhook_validation.go(new): LightweightPrepare*ForValidationhelpers for each CRD type that build aTranslateContextwithout running the full reconciler loop. Used by the admission webhook to resolve references before translating.Admission validator
internal/webhook/v1/adc_validation.go(new):adcAdmissionValidatorthat:client.Validate()ADCValidationErrorscause denial)global_rulesandplugin_metadatain the validate payload so plugin references can be resolvedWebhook wiring
apisixroute_webhook.go,apisixconsumer_webhook.go,apisixtls_webhook.go,consumer_webhook.go: WireadcAdmissionValidator; ADC init errors are logged and ignored (fail-open).apisixtls_webhook.go: Skip ADC validation when secrets are missing to preserve the existing warn-only behaviour for that case.consumer_webhook.go: Validate duplicatekey-authcredential keys scoped to the sameGatewayRefusing a field-index query (O(1) instead of O(N) full list). Malformed inline JSON credentials are logged and skipped rather than causing a hard denial.Behaviour notes
Examples
Deny: invalid plugin configuration on ApisixRoute
Applying an
ApisixRoutewhoseresponse-rewriteplugin receivesstatus_codeas a string instead of an integer is rejected immediately:Deny: invalid jwt-auth algorithm on ApisixConsumer
Warn + Admit: missing backend Service on ApisixRoute
When a referenced Service does not yet exist, the resource is admitted with a warning (eventual consistency):
Deny: SNI conflict on ApisixTls
When two
ApisixTlsresources claim the same SNI, the second one is denied: