Skip to content
ALTAIRA LABS
DocsBlog

Expose agents

Omnia uses the Kubernetes Gateway API to expose agents externally. This provides a standard, portable way to manage ingress traffic with support for WebSocket connections.

  • Kubernetes cluster with Gateway API CRDs installed
  • A Gateway controller (Istio, Envoy Gateway, etc.)
Terminal window
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/standard-install.yaml

Istio provides a production-ready Gateway controller:

Terminal window
helm repo add istio https://istio-release.storage.googleapis.com/charts
helm repo update
helm install istio-base istio/base -n istio-system --create-namespace
helm install istiod istio/istiod -n istio-system --wait

Configure the gateway in your Helm values:

gateway:
enabled: true
name: agents
className: istio
listeners:
http:
port: 80
protocol: HTTP

After deploying an AgentRuntime, create an HTTPRoute to expose it:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: my-agent
namespace: default
spec:
parentRefs:
- name: omnia-agents
namespace: omnia-system
hostnames:
- "agents.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /my-agent
backendRefs:
- name: my-agent
port: 8080

After creating an HTTPRoute, the resulting external URL is published to the agent’s status:

Terminal window
kubectl get agentruntime <name> -o jsonpath='{.status.facade.endpoints}'

This displays all discovered external endpoints derived from HTTPRoutes targeting the agent’s facade Service.

The agent’s detail page displays the external URL in the Connect card (under the “External” tab). This mirrors the same status.facade.endpoints data.

If an endpoint shows valid: false, the URL is advertised but will not connect. This typically occurs with path-prefix routes that lack a URLRewrite filter:

# This route will be marked valid: false
rules:
- matches:
- path:
type: PathPrefix
value: /my-agent
backendRefs:
- name: my-agent
port: 8080

Solution: Either use host-based routing (recommended), or add a URLRewrite filter with ReplacePrefixMatch:

rules:
- matches:
- path:
type: PathPrefix
value: /my-agent
filters:
- type: URLRewrite
urlRewrite:
replacePrefixMatch: /
backendRefs:
- name: my-agent
port: 8080

External authentication is governed by the agent’s spec.externalAuth setting (clientKeys, OIDC, or edge trust), not the dashboard’s management-plane token. Configure external auth on the AgentRuntime to control how clients authenticate to the external endpoint.

Terminal window
kubectl get gateway omnia-agents -n omnia-system \
-o jsonpath='{.status.addresses[0].value}'
Terminal window
websocat ws://<gateway-ip>/my-agent/ws
wscat -c ws://<gateway-ip>/my-agent/ws

For production, enable TLS termination:

Terminal window
kubectl create secret tls agents-tls \
--cert=path/to/cert.pem \
--key=path/to/key.pem \
-n omnia-system
gateway:
enabled: true
listeners:
http:
port: 80
protocol: HTTP
https:
enabled: true
port: 443
protocol: HTTPS
tlsSecretName: agents-tls
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: my-agent
spec:
parentRefs:
- name: omnia-agents
namespace: omnia-system
sectionName: https # Use the HTTPS listener
hostnames:
- "agents.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /my-agent
backendRefs:
- name: my-agent
port: 8080

Expose multiple agents through the same gateway:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: all-agents
spec:
parentRefs:
- name: omnia-agents
namespace: omnia-system
hostnames:
- "agents.example.com"
rules:
# Customer service agent
- matches:
- path:
type: PathPrefix
value: /customer-service
backendRefs:
- name: customer-service-agent
port: 8080
# Sales agent
- matches:
- path:
type: PathPrefix
value: /sales
backendRefs:
- name: sales-agent
port: 8080
# Support agent
- matches:
- path:
type: PathPrefix
value: /support
backendRefs:
- name: support-agent
port: 8080

Route to different agents based on hostname:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: customer-agent
spec:
parentRefs:
- name: omnia-agents
namespace: omnia-system
hostnames:
- "customer.agents.example.com"
rules:
- backendRefs:
- name: customer-service-agent
port: 8080
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: sales-agent
spec:
parentRefs:
- name: omnia-agents
namespace: omnia-system
hostnames:
- "sales.agents.example.com"
rules:
- backendRefs:
- name: sales-agent
port: 8080

Omnia also creates an internal gateway for observability tools:

internalGateway:
enabled: true
name: internal
className: istio
port: 8080
grafana:
enabled: true
path: /grafana
prometheus:
enabled: true
path: /prometheus

Access internal tools:

Terminal window
# Get internal gateway IP
kubectl get gateway omnia-internal -n omnia-system \
-o jsonpath='{.status.addresses[0].value}'
# Access Grafana
curl http://<internal-ip>:8080/grafana/
# Access Prometheus
curl http://<internal-ip>:8080/prometheus/
Terminal window
kubectl get gateway -n omnia-system
kubectl describe gateway omnia-agents -n omnia-system
Terminal window
kubectl get httproute
kubectl describe httproute my-agent

The HTTPRoute status should show it’s accepted:

Terminal window
kubectl get httproute my-agent -o jsonpath='{.status.parents[0].conditions}'
Terminal window
kubectl logs -l istio=ingressgateway -n istio-system

If using a different Gateway controller (e.g., Envoy Gateway, Contour):

gateway:
enabled: true
className: envoy # or your controller's class name

Ensure your controller supports WebSocket connections for agent communication.