Skip to content

fix(envoy-ai-gateway): sync mutating webhook CA for mainline HTTPS gateway (EAI-8292) - #823

Draft
Q-Dub wants to merge 14 commits into
mainfrom
EAI-8292-ai-gateway-webhook-ca
Draft

fix(envoy-ai-gateway): sync mutating webhook CA for mainline HTTPS gateway (EAI-8292)#823
Q-Dub wants to merge 14 commits into
mainfrom
EAI-8292-ai-gateway-webhook-ca

Conversation

@Q-Dub

@Q-Dub Q-Dub commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Embed clientConfig.caBundle in the envoy-ai-gateway mutating webhook from the same self-signed secret material on every Helm/ArgoCD render, preventing API-server ↔ controller TLS drift that blocks Envoy HTTPS data-plane pod creation.
  • Add shared scripts/utils/ai-gateway-webhook-health.sh (probe → sync CA from secret → restart ai-gateway-controller).
  • OpenShift install.sh now calls the shared script instead of inline bash.

Fixes the k2 incident where https://aiwbui.wookie.silogen.ai/ failed with connection closed despite healthy app pods — Gateway Programmed=False, Envoy replicas unavailable.

Jira: https://amd.atlassian.net/browse/EAI-8292

Test plan

  • helm template envoy-ai-gateway sources/envoy-ai-gateway/v1.0.0 --namespace envoy-ai-gateway-system renders MutatingWebhookConfiguration with non-empty clientConfig.caBundle
  • Fresh mainline deploy (bloom → ArgoCD): kubectl get gateway https -n envoy-gateway-system shows Programmed=True
  • Webhook probe succeeds: scripts/utils/ai-gateway-webhook-health.sh exits 0 on healthy cluster
  • Envoy data-plane pods exist: kubectl get pods -n envoy-gateway-system -l gateway.envoyproxy.io/owning-gateway-name=https
  • https://aiwbui.<domain>/ completes TLS (307 redirect to sign-in is OK)
  • https://argocd.<domain>/ returns 200
  • Simulate drift (patch webhook caBundle to garbage) → run health script → probe passes and Envoy data plane recovers after --heal-envoy-data-plane
  • OpenShift install path finds script at ${CLUSTER_FORGE_DIR}/cluster-forge/scripts/utils/ai-gateway-webhook-health.sh after tarball extract

Q-Dub and others added 7 commits August 26, 2026 13:02
Render clientConfig.caBundle from the same self-signed secret material
on every Helm/ArgoCD sync so the API server trust anchor stays aligned
with the ai-gateway-controller TLS cert (EAI-8292).

Co-authored-by: Cursor <cursoragent@cursor.com>
Extract shared probe/sync/restart logic for the envoy-ai-gateway pod
mutating webhook so OpenShift install and operators can recover from
caBundle drift without duplicating inline bash (EAI-8292).

Co-authored-by: Cursor <cursoragent@cursor.com>
Replace inline probe_ai_gateway_webhook in install.sh with the shared
scripts/utils/ai-gateway-webhook-health.sh from the extracted tarball.

Co-authored-by: Cursor <cursoragent@cursor.com>
Render cert-manager and self-signed webhook CRs from one helper so rules and failurePolicy cannot drift (EAI-8292).

Co-authored-by: Cursor <cursoragent@cursor.com>
Install-critical helper now lives under scripts/, OpenShift install fails if it is missing, and names/help/caBundle patch are less brittle (EAI-8292).

Co-authored-by: Cursor <cursoragent@cursor.com>
Add post-handoff gate scripts (Gateway programmed, webhook probe-only,
HTTPS AIWB UI) and --probe-only on ai-gateway-webhook-health.sh for
Kaytoo validation and future shared-cluster CI.

Co-authored-by: Cursor <cursoragent@cursor.com>
Add configuration-reference docs for helmParameters and script env vars,
offline install-helper tests (caBundle helm render + cpu profile YAML),
CI install-script-checks job, and restore valid cpu AIMClusterModelSource.

Co-authored-by: Cursor <cursoragent@cursor.com>
@Q-Dub
Q-Dub force-pushed the EAI-8292-ai-gateway-webhook-ca branch from bf642fa to 1fa932e Compare August 26, 2026 10:05
Q-Dub and others added 5 commits August 26, 2026 14:36
Head-node checks hit the MetalLB IP with --resolve instead of the public
VIP, which often fails from inside the same Kaytoo/single-node cluster.

Co-authored-by: Cursor <cursoragent@cursor.com>
Scope out aim-cluster-model-source CPU profile update; belongs in a
separate catalog ticket, not the envoy-ai-gateway webhook CA fix.

Co-authored-by: Cursor <cursoragent@cursor.com>
Replace silogen.ai subdomain examples with <cluster-domain> and drop
Kaytoo-specific invocation that referenced internal hostnames.

Co-authored-by: Cursor <cursoragent@cursor.com>
install-script-checks failed after reverting the CPU catalog update;
keep only webhook caBundle tests on this branch.

Co-authored-by: Cursor <cursoragent@cursor.com>
@silokimmo

Copy link
Copy Markdown
Contributor

Tested this on chalupa-491a (RKE2 v1.34.1+rke2r1, single node, cluster size medium), which had drifted into exactly the EAI-8292 state. The diagnosis and the heal both check out — one gap to flag.

Confirmed the root cause matches

Two self-signed CAs generated 4 minutes apart:

CN notBefore
secret self-signed-cert-for-mutating-webhook ca.crt ai-gateway-controller-ca 10:22:31
webhook clientConfig.caBundle ai-gateway-controller-ca 10:18:17
ReplicaSet FailedCreate: failed calling webhook
"ai-gateway-controller.envoy-ai-gateway-system.svc.cluster.local":
x509: certificate signed by unknown authority ... "ai-gateway-controller-ca"

failurePolicy: Fail meant no pod could be created in envoy-gateway-system, so both Envoy data planes were at 0/1 and both Gateways were Programmed=False reason=NoResources. Every HTTPS endpoint returned connection refused.

ai-gateway-webhook-health.sh worked

--probe-only correctly detected the failure (exit 1). The full heal patched the caBundle, restarted the controller, restarted the https data plane, re-probed clean, exit 0. https went Programmed=True and all endpoints came back (argocd/gitea 200, kc 302, openbao/seaweed-admin/airmui/aiwbui 307).

Gap: restart_envoy_https_data_plane() only selects the https gateway

ai-gateway was broken by the same webhook, but the selector is gateway.envoyproxy.io/owning-gateway-name=https, so it was never restarted. Its ReplicaSet had already exhausted its backoff, so it did not self-recover. I polled for three minutes after the heal:

t+15s  available=0
t+30s  available=0
...
t+180s available=0

Still 0/1, Programmed=False. An explicit rollout restart with owning-gateway-name=ai-gateway brought it up in ~15s.

The problem is that the script exits 0 in this state. The final probe only tests whether the webhook admits pods — which is true — so a cluster can come back half-healed while the script reports success. Same applies to the gateway-programmed.sh platform gate if it only checks https.

Suggested fix:

restart_envoy_data_plane() {
  kubectl rollout restart deployment \
    -l 'gateway.envoyproxy.io/owning-gateway-name in (https,ai-gateway)' \
    -n "${GATEWAY_NAMESPACE}" >/dev/null
  kubectl rollout status deployment \
    -l 'gateway.envoyproxy.io/owning-gateway-name in (https,ai-gateway)' \
    -n "${GATEWAY_NAMESPACE}" --timeout=180s
}

Or select on label existence (-l gateway.envoyproxy.io/owning-gateway-name) to cover any additional Gateways. If the flag is meant to stay https-only, worth renaming it and documenting that other Gateways need separate handling.

Minor

  • The PR description references scripts/utils/ai-gateway-webhook-health.sh (summary + last test-plan checkbox), but the file is added at scripts/ai-gateway-webhook-health.sh. The code is consistent — docs/openshift/install.sh uses the correct path — so it's just stale description text.
  • heal_ai_gateway_webhook() always restarts ai-gateway-controller. On chalupa the controller was already serving the cert matching the secret (verified via openssl s_client against :9443), so only the caBundle patch was needed and the restart cost ~180s. Harmless, and correct in the general case where the controller holds a stale keypair — just noting the patch alone was sufficient here.
  • The caBundle patch persisted across ArgoCD sync loops, as expected: the current chart doesn't render that field, so there's no desired value to revert to.

Checked off from the test plan against a real drifted cluster:

  • scripts/ai-gateway-webhook-health.sh exits 0 on healthy cluster
  • kubectl get gateway https -n envoy-gateway-system shows Programmed=True
  • Envoy data-plane pods exist
  • https://aiwbui.<domain>/ completes TLS (307)
  • https://argocd.<domain>/ returns 200
  • Drift → heal → data plane recovers (with the ai-gateway caveat above)

Q-Dub and others added 2 commits August 27, 2026 07:36
Webhook drift blocks both Envoy gateways but heal only rolled https
Deployments, leaving ai-gateway stuck at 0/1 with Programmed=False while
the final probe still exited 0. Always restart both data planes after
heal and require Gateway Programmed=True before reporting success.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep main's data-driven install.sh and wire ai-gateway-webhook-probe
to the shared scripts/ai-gateway-webhook-health.sh heal path.

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants