Repository navigation
Description
A Task today has no network access in either direction, and AX gives users no way to change that. As a result, a Task cannot reach its model, its repository, or its tools does nothing useful, so AX cannot be used for real workloads until this is fixed.
Proposal
Add a fourth primitive, Gateway (ax.io/v1alpha1), that declares which traffic may enter and leave a Task. A Task binds at most one Gateway by name, the same way it binds a Workspace. Both directions are lists of allow rules, and anything that matches no rule is denied. Without a Gateway a Task behaves as it does today.
apiVersion: ax.io/v1alpha1
kind: Gateway
metadata:
name: review-bot
atespace: default
spec:
ingress:
rules:
# The team's frontend may call the agent's HTTP API.
- from:
spiffeIds: ["spiffe://cluster.local/ns/team-a/sa/frontend"]
ports: {numbers: [8080]}
# A CI service account may reach the agent's gRPC endpoint.
- from:
spiffeIds: ["spiffe://cluster.local/ns/ci/sa/runner"]
ports: {numbers: [9090]}
egress:
rules:
- https:
hostnames: ["api.anthropic.com"]
---
apiVersion: ax.io/v1alpha1
kind: Task
metadata:
name: review-bot
spec:
image: "ghcr.io/my-org/my-agent-image@sha256:..."
gateway:
name: review-bot- Ingress. The router checks the caller's SPIFFE ID and the destination port against the target Task's rules, on top of its cluster-wide allowlist. A Task with no
ingressrules is reachable only by AX itself: readiness checks, andax sshwhenspec.debugis set. Once Tasks get SPIFFE identities (docs/roadmap.md), one Task can allow another by listing its SPIFFE ID infrom.spiffeIds. - Egress. Rules allow
http,https, ortlsPassthroughtraffic to the listed hostnames and ports.httpsrules can inject credentials into matching requests, so secrets never enter the sandbox.
The Gateway must be compatible with Agent Substrate. Egress maps onto Substrate's existing per-actor EgressPolicy. Ingress needs a per-actor ingress API in Substrate, which we should propose upstream using the example above, rather than enforce ingress in AX and bypass the router.
Open questions
- Should a
Modelcontribute anhttpsrule with credential injection for its provider endpoint automatically, so users don't have to write it? - Is
Gatewaythe right name, given that Substrate already uses "egress gateway" for its component?
Definition of done
Gatewaydefined inax.proto, mapped intypes.go, validated inresources.go, and documented indocs/manifests.mdanddocs/networking.md; postgresschema.sqlandschema.goupdated.ax apply/get/describe/delete gatewaywork.- E2E: a Task bound to a Gateway reaches an allowed host and is refused for everything else; an allowed caller reaches the Task and any other caller is refused. A Task with no Gateway behaves as it does today.
Activity
yongruilin commentedon Nov 2, 2026
+1
On the two open questions:
Model,ax-servershould automatically contribute the provider'shttpsrule + credential injection, so standard tasks work out of the box without needing a policy manifest unless they require extra hosts (e.g. GitHub) or inbound access.NetworkPolicyorTrafficPolicy? K8s Gateway API and Substrate (egress gateway) both useGatewayfor proxy infra, whereas IIUC this resource declares per-task traffic and credential rules.yongruilin commentedon Nov 2, 2026
This is part of the Task lifecycle. cc @siyuanfoundation
yongruilin commentedon Nov 2, 2026
@rakyll Here's a proto sketch, named
TrafficPolicy: in Substrate, "gateway" is the proxy that enforces these rules (agent-substrate/substrate#3258 is about swapping it), andNetworkPolicycollides with the Kubernetes NetworkPolicy Substrate puts on worker pools. Let me know if it makes sense?ax apply/get/describe/delete trafficpolicymirrorModel; creating a task that binds a missing policy fails.Gatewayresource for Task network policy #549") ships egress + credential injection (ate-secret://k8s.io/...) and rejects non-emptyingress.rulesuntil Enhancing Network Ingress agent-substrate/substrate#431 lands.TaskSpec.modelfor automatic Model rules (Q1), plus setup-scoped egress forWorkspace.mastersingh24 commentedon Nov 3, 2026
+1. We've run both directions on our fork for a few weeks, on Agent Substrate v0.5 and now v1.0.0-rc.1, so here's what we learned in case it helps the design.
Egress. Ours is a list of host rules on the Task with injected credentials, which is close to the egress half here. Our triage agents call Vertex AI and the GKE API like this:
It has worked well. The agent never holds the token, and the egress gateway swaps in a fresh one on every request. Three things came up:
Ingress. Until per-actor ingress lands in Substrate, the router's CONNECT path already reaches any port in the actor (my last comment on #501). The cluster-wide allowlist decides who can do that. On v1.0 any listed client can reach any actor: we list ax-server, our incident watcher, a dashboard, our e2e runner, and
kubectl ate proxy's atenet-client identity. So per-taskfrom.spiffeIdswould be a real improvement.One thing the proposal doesn't mention, and the reason we kept a small patch: waking up cleanly. When a request wakes a suspended task, the router waits for Substrate's wakeup probe, which asks the runner's
/readyz. The runner reports ready before the agent's own server is listening again, so the first request after a resume could fail. Our patch lets the Task name its server port and makes/readyzwait until that port accepts connections. If ingress rules list ports anyway, the runner could take its readiness port from there, or the Task could name it separately. Either would let us drop our patch.Naming.
TrafficPolicyreads well to us, and avoids both Substrate's "egress gateway" and Kubernetes NetworkPolicy.When this lands, we'll move our fork's egress and port fields onto it.