AISIX 1.1.0
This release hardens the path between the control plane and the gateway.
Release date: September 7, 2026
This release hardens the path between the control plane and the gateway. A gateway now opens its proxy port only once it has a configuration to serve, recovers on its own from an etcd outage, an expired etcd token, or a watch that is never confirmed, and loads configuration sets that previously exceeded an internal message-size ceiling. A2A agents complete the client-header forwarding contract, and the On-Premises control-plane chart gains fixed NodePorts and stops waiting on a bundled database it was told not to use.
Behavior Changes
-
The gateway binds its proxy listener only after it has applied a configuration. In etcd mode a cold-booting instance keeps the proxy port closed until its first configuration read succeeds, instead of accepting connections immediately and answering every request
401 invalid_api_keybecause it knew no API keys yet. An orchestrator that treats "the port accepts" as "this instance is ready" no longer routes traffic to an instance that has nothing to serve. There is no configuration knob and no opt-out; this is the startup order now. The wait only ever applies to an instance that has never applied a configuration. File mode passes the gate immediately, and so does a restart that finds an on-disk snapshot cache: such an instance restores the snapshot and binds in well under a second even while its configuration source is unreachable, so a pod that has run before comes straight back up during a control-plane outage. A first boot with no cached snapshot is the only case that waits, and against a reachable control plane that wait is tens of milliseconds at realistic configuration sizes./livezand/readyzare served on the proxy listener, so a probe aimed at that port gets a refused connection rather than a response during the window; the same two paths on the admin listener, and/status/readyand/status/configon the metrics listener, are bound before the gate and answer throughout. Helm users should take the 1.1.0 chart alongside the 1.1.0 image: the chart's startup budget was widened to match this order. -
The
etcd.dial_timeout_msandetcd.request_timeout_mssettings now take effect. Both were parsed and then read by nothing in earlier releases, so every deployment ran with no etcd timeouts whatever the file said. Both keys are optional and unset means unbounded; there is no implicit5000.request_timeout_msbounds each single request and response etcd call — the configuration range read at boot and on every watch reconnect, creating the watch, and the admin API's reads — and never the established watch stream.dial_timeout_msbounds the whole dial, including the TLS handshake and the authentication exchange. A configuration file copied from the previous release's shipped examples already carries both keys at5000, so review it before upgrading; see Upgrade Notes. -
A gateway with etcd credentials configured no longer exits when etcd is unreachable at startup. Previously, setting
etcd.userandetcd.password_envmade an unreachable etcd fatal: the process worked through a fixed ladder of five connection attempts five seconds apart and then exited, roughly 20 to 25 seconds in, without ever binding a listener. Such an instance now behaves like an unauthenticated one — it starts, holds the proxy listener closed, retries on its existing backoff, and binds as soon as a configuration arrives. Credentials that etcd actively refuses — a wrong user or password, a user without the required permission, or credentials sent to a cluster with authentication disabled — remain fatal, and now stop the boot on etcd's first answer rather than after a fixed retry ladder. Anything that relied on the process exiting to signal "etcd is down" should read/status/readyinstead.
New Features
-
A2A agents can forward inbound client headers upstream. A new
forward_client_headerslist on an A2A agent names the client headers the gateway relays to that agent, as single-*glob patterns matched case-insensitively. It applies to every JSON-RPC method served at/a2a/<name>—message/send,message/stream, and every task operation — and to the agent-card fetch at/a2a/<name>/.well-known/agent-card.json. This completes the forwarding contract across all four proxy faces, alongside Provider Keys, passthrough routes, and MCP servers. Empty is the default and forwards nothing, so no existing agent changes behavior.Naming the credential slot the agent's
auth_typefills —authorizationforbearer,x-api-keyforapi_key— hands the agent the caller's own credential in place of the gateway's, never both, which lets an internal agent that already authorizes on the end user's identity keep doing so. A credential slot and thetraceparentandtracestateheaders are forwarded only when a pattern names them exactly; a broad glob such as*orx-*never sweeps them in. Headers whose relay would break the exchange are refused however broad the pattern:host, hop-by-hop headers, thex-aisix-*namespace, the headers describing a body the gateway re-serializes, anda2a-version, which is the gateway's own announcement of the version pinned inprotocol_version.One limitation is worth knowing before you forward
cookie. The gateway terminates inbound HTTP/2 and performs no cookie reassembly, so an HTTP/2 caller that splitscookieacross several header fields — an HPACK compression option that not every client exercises — has only the first of them forwarded. This is true of A2A agents, MCP servers, and Provider Keys alike; a passthrough route relays every value.The setting is available in the Dashboard on the A2A agent create and edit forms under Advanced, and through the Admin API. Saving a non-empty list while some gateways in scope still run a version that predates it returns a compatibility warning; those gateways relay nothing until they are upgraded, which is the fail-closed direction.
Improvements
-
The gateway loads configuration sets larger than 4 MiB. The gateway reads its whole prefix in a single etcd range response, and a 4 MiB gRPC decode ceiling meant an environment that grew past that size never loaded — a limit crossed by how many resources an environment holds, not by any one of them being large. It did not self-heal: a running instance silently stopped seeing configuration changes, and a restarted or newly scheduled one never applied a configuration at all. The ceiling is lifted on both the configuration read path and the admin read surface. Deployments below the old limit are unaffected.
-
The control plane no longer caps the size of a resource it writes to the gateways. Two message-size ceilings on the control plane's own write path — a 2 MiB send limit on the outbox client and a 4 MiB receive limit on the embedded store — could reject a single oversized projected resource on every poll, forever. Per-key isolation meant the rest of the queue kept draining, so the visible result was one resource whose configuration never reached the gateways, with nothing surfaced to whoever saved it. Neither ceiling was chosen for this path and both are removed. Reaching either required an unusually large projected value, such as an API key granting many thousands of models.
-
A gateway waiting on its configuration source now says so. While the first configuration read is outstanding, the gateway logs when the wait starts and repeats a warning every ten seconds. An endpoint that accepts TCP and then answers nothing previously produced a process with no port and no log line at all.
-
The On-Premises control-plane chart accepts fixed NodePorts for the API and Dashboard services.
api.service.nodePortandui.service.nodePortjoin the existingdpm.service.nodePort, each rendered only when its Service type isNodePortand a value is set; both default to empty, so an installation that does not set them keeps dynamic allocation. This lets an operator setapi.publicBaseURLto a known endpoint before installation. NodePort access to the API and Dashboard is plain HTTP: the Dashboard NodePort is not a standalone entry point but the upstream of a same-origin proxy that routes/api/*to the API, and that proxy should terminate TLS unless it is on a trusted private network.
Fixes
-
An expired or invalidated etcd authentication token no longer requires a gateway restart. The etcd client authenticated once at connect and never again, so a token whose lifetime elapsed while the connection was idle — the normal state of a gateway with stable configuration — or one invalidated by a change to etcd's authentication store left every later call refused until the process was restarted. The gateway now discards the connection, re-authenticates, and retries the call once, on both the configuration read path and the admin read surface. Credentials etcd genuinely refuses are still reported as such and are not retried in a loop.
-
The gateway no longer loses its last configuration snapshot when stopped shortly after an update. Snapshot-cache writes were spawned detached and nothing waited for them, so an instance stopped soon after applying a change could exit with the write unfinished and restart without its last-known-good snapshot. In-flight writes are now drained at shutdown, bounded at five seconds. Snapshot writes also commit in apply order: a write for an older revision no longer overwrites a newer one, so a gateway restarted after a burst of updates cannot come back onto a snapshot it had already moved past. The graceful-drain sequence, the drain window, and
preStopbehavior are unchanged. -
A configuration watch that is never confirmed is now detected. An etcd that answered range reads but never confirmed the watch left the gateway serving its first snapshot forever, blind to every later change, while
/status/configstill reported it connected. Whenrequest_timeout_msis set, an unconfirmed watch creation is aborted and retried on the existing backoff. -
MCP access-control reprojection now covers every affected row. The reprojection that refreshes MCP access control on upgrade paginated in a way that could skip rows, leaving those rows projected in the retired shape the flattening was meant to replace. It now walks every API key and MCP policy explicitly. Upgrading the control plane performs one additional projection write per current API key and MCP policy. No API, configuration, or resource shape changes, and no operator action is required.
-
The On-Premises control-plane chart no longer waits for the bundled PostgreSQL when an external database is configured. Setting
postgresql.builtin=falsedisabled the bundled server, but the API and Data Plane Manager still ran a PostgreSQL readiness init container built frompostgresql.image.*, so in a private network an unavailable PostgreSQL image could block startup even with a healthy external database. The readiness init is now rendered only whenpostgresql.builtin=true. Bundled deployments are unchanged and remain the default. Operators using an external database must ensure it is ready before the control plane starts.
API Changes
The OpenAPI structural comparison reports no breaking changes. All additions are optional and confined to the A2A agent surface.
| Endpoint | Change |
|---|---|
| A2A agent representations add optional forward_client_headers. |
| Accept optional forward_client_headers, an array of header-name glob patterns; [] clears an existing list. Entries are validated against the same rules as the other forwarding surfaces — RFC 7230 token grammar, at most one * per entry, and a 64-entry cap — and a pattern that could only ever name a header this surface never relays is rejected with 400. A PATCH carrying only forward_client_headers is a valid update. |
| Successful save responses may include warnings when gateways in the environments the agent is exposed to run a version that will not execute the saved forward_client_headers. The warning shape is the existing CompatibilityWarning; this is the first release in which an A2A save can carry one. |
One guarantee narrowed without any shape changing, and it is worth reading if you
built against the A2A agent's auth_type. Through 1.0.0 the resources-file schema for
that field said the gateway's credential is never forwarded from or exposed to the
calling client. It now says the credential is not exposed to the caller unless
forward_client_headers names the slot auth_type fills, in which case the agent
receives the caller's credential in place of the gateway's. The Admin API states the
same rule, which it did not describe before this release. The field's shape and enum
values are unchanged on both surfaces.
Upgrade Notes
These notes apply when you upgrade from any release earlier than 1.1.0, including an upgrade that passes over it on the way to a later release.
- Check your
etcd:block before upgrading.etcd.dial_timeout_msandetcd.request_timeout_mstake effect for the first time in this release, and the previous release shipped both of them active at5000inconfig.example.yamlandconfig.managed.yaml. A configuration file copied from either therefore acquires a live 5-second bound on the configuration range read. A deployment whose configuration set does not load within that bound fails the read and retries it, and — because the gateway now binds its proxy listener only after a successful apply — does not begin serving. Removerequest_timeout_msunless you specifically want a slow etcd to fail fast, and note the trade-off: the unconfirmed-watch abort described under Fixes only takes effect whilerequest_timeout_msis set. If you keep the key, size it against your own configuration set rather than the number that used to be in the example.dial_timeout_ms: 5000carries no comparable risk. The shipped examples now leave both keys inactive, and unset means unbounded. - Check
api.service.nodePortandui.service.nodePortif your control-plane Helm values file already sets either. Both keys were ignored until this release and are now rendered, so upgrading the chart can move a port that Kubernetes had been allocating dynamically. Remove the key to keep dynamic allocation.