Expose agents
Route traffic from outside the cluster to an agent’s facade through a Gateway API Gateway.
Prerequisites
Section titled “Prerequisites”- A Kubernetes cluster with the Gateway API CRDs and a Gateway controller.
- An AgentRuntime with
spec.externalAuthset. Without it the external listener has no validators and rejects every request with a 401. See Configure authentication.
Install the Gateway API CRDs:
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/standard-install.yamlIf you have no controller, Istio is one option:
helm repo add istio https://istio-release.storage.googleapis.com/chartshelm repo update
helm install istio-base istio/base -n istio-system --create-namespacehelm install istiod istio/istiod -n istio-system --waitEnable the gateway
Section titled “Enable the gateway”Set these Helm values. className must match your controller (istio, envoy, and so on):
gateway: enabled: true name: agents className: istioThe chart creates a Gateway named <fullname>-agents in the release namespace. For a release named omnia in omnia-system that is omnia-agents. For all gateway and internalGateway values, see Helm values.
Route to the agent
Section titled “Route to the agent”Choose one.
Let the operator create the route
Section titled “Let the operator create the route”Set defaultExposure in the Helm values. The operator then creates a host-based HTTPRoute for each agent that opts in:
defaultExposure: enabled: true baseDomain: agents.example.com gateway: name: omnia-agents namespace: omnia-systemOpt each facade in on its own entry, or use the Expose externally switch on the agent’s Connectivity tab in the dashboard, which sets it on the primary facade:
spec: facades: - type: websocket expose: enabled: true - type: a2a expose: enabled: trueThe operator creates one HTTPRoute per exposed facade, each to that facade’s own Service port. The hostname is <agent>.<namespace>.<baseDomain> for the primary facade and <agent>-<type>.<namespace>.<baseDomain> for a secondary one, so the agent above is reachable at wss://<agent>.<namespace>.<baseDomain>/ws and https://<agent>-a2a.<namespace>.<baseDomain>/a2a. Set expose.host on a facade to override its hostname; do not give two facades the same host, because every route matches the root path and the Gateway serves only the older one. The Gateway listener’s certificate must cover each hostname. See facades[].expose.
Write the route yourself
Section titled “Write the route yourself”The backend is the agent’s Service, which has the agent’s name, on the facade port (8080 by default). Host-based routing needs no rewrite:
apiVersion: gateway.networking.k8s.io/v1kind: HTTPRoutemetadata: name: my-agent namespace: defaultspec: parentRefs: - name: omnia-agents namespace: omnia-system hostnames: - "my-agent.agents.example.com" rules: - backendRefs: - name: my-agent port: 8080To share one hostname between agents, match a path prefix and strip it. The facade serves /ws, so without the rewrite it receives /my-agent/ws and rejects the connection:
rules: - matches: - path: type: PathPrefix value: /my-agent filters: - type: URLRewrite urlRewrite: path: type: ReplacePrefixMatch replacePrefixMatch: / backendRefs: - name: my-agent port: 8080Enable HTTPS
Section titled “Enable HTTPS”Create the TLS Secret in the Gateway’s namespace:
kubectl create secret tls agents-tls \ --cert=path/to/cert.pem \ --key=path/to/key.pem \ -n omnia-systemEnable the HTTPS listener:
gateway: listeners: https: enabled: true tlsSecretName: agents-tlsIn a hand-written route, add sectionName: https to the parentRefs entry.
Verify
Section titled “Verify”Print the endpoints the operator discovered from the route:
kubectl get agentruntime my-agent \ -o jsonpath='{.status.facade.endpoints}'The same list appears on the agent’s Connectivity tab in the dashboard. Each entry has a url and a valid flag.
Get the Gateway address and point the hostname at it in DNS:
kubectl get gateway omnia-agents -n omnia-system \ -o jsonpath='{.status.addresses[0].value}'Connect with a credential that spec.externalAuth accepts. <url> is the url from the endpoint list:
websocat -H "Authorization: Bearer $TOKEN" <url>Troubleshooting
Section titled “Troubleshooting”An endpoint with valid: false is advertised but will not connect. A path-prefix route without the ReplacePrefixMatch rewrite above gives the reason path prefix not stripped before facade. Add the rewrite or switch to host-based routing.
A 401 means the request reached the facade but no spec.externalAuth validator admitted it. Check that the agent sets externalAuth and that the client sends a matching credential.
No endpoints listed: the route’s backend name must equal the AgentRuntime name and its port must be a facade port, and the parent Gateway must resolve.
Check that the Gateway and route are accepted:
kubectl describe gateway omnia-agents -n omnia-systemkubectl describe httproute my-agent