# What Is the Role of atenet in Agent Substrate Networking?

> Discover atenet, Agent Substrate's networking layer. It manages actor traffic with an ingress router and egress gateway, secured by mutual TLS and dynamic configuration.

- Repository: [Agent Substrate/substrate](https://github.com/agent-substrate/substrate)
- Tags: deep-dive
- Published: 2026-08-22

---

**`atenet` is the networking layer of Agent Substrate that manages bidirectional traffic for actors through an ingress router (handling incoming HTTP requests via Envoy and xDS) and an egress gateway (handling outbound CONNECT tunnels), secured with mutual TLS and dynamic configuration.**

Agent Substrate uses `atenet` as its dedicated networking component to enable communication between lightweight actor workloads and external systems. Located in the `agent-substrate/substrate` repository, this service implements a split data-plane architecture that isolates ingress and egress concerns for independent scaling and security hardening.

## The Two Core Data-Plane Services

`atenet` implements two complementary binaries that together provide complete network connectivity for actors.

### Ingress Router (atenet-router)

The `atenet-router` receives HTTP requests targeting specific actors and processes them through an Envoy sidecar. According to the source code in [`cmd/atenet/internal/router/config.go`](https://github.com/agent-substrate/substrate/blob/main/cmd/atenet/internal/router/config.go), the router performs **TLS termination**, **request parking** for saturated workers, and **external-process (ext-proc) extensions** before forwarding traffic over an `atunnel` to worker pods. It also hosts the xDS control plane that dynamically configures Envoy based on the current actor topology, as defined in the Kubernetes manifest [`manifests/ate-install/atenet-router.yaml`](https://github.com/agent-substrate/substrate/blob/main/manifests/ate-install/atenet-router.yaml).

### Egress Gateway (atenet-egress)

The `atenet-egress` service handles outbound connectivity by accepting CONNECT-tunneled traffic from actors needing to reach external services. As implemented in [`manifests/ate-install/atenet-egress.yaml`](https://github.com/agent-substrate/substrate/blob/main/manifests/ate-install/atenet-egress.yaml), it validates the actor's mTLS client certificate against the configured `ActorIdentityCAFile` and proxies the connection outward. Unlike the router, the egress sidecar does **not** run an xDS server, allowing deployment in environments without Kubernetes API access.

## How atenet Routes Traffic Through the Cluster

The end-to-end flow through `atenet` involves several coordinated steps across the Substrate control plane:

1. **Actor-Addressed Ingress**: A client contacts an actor's HTTP address (e.g., `http://my-actor.example.com`), hitting the `atenet-router` Service first.

2. **Dynamic xDS Configuration**: The router runs an xDS server that continuously programs the Envoy sidecar with routes pointing to available worker pods. This is gated by the `ServesIngress` method in [`cmd/atenet/internal/router/config.go`](https://github.com/agent-substrate/substrate/blob/main/cmd/atenet/internal/router/config.go) (lines 60-66), which checks the `routerConfig.Mode` setting.

3. **Request Parking**: If the selected worker is saturated, the router can "park" the request using logic in [`cmd/atenet/internal/router/ingress/parking.go`](https://github.com/agent-substrate/substrate/blob/main/cmd/atenet/internal/router/ingress/parking.go) and retry later when capacity is available.

4. **Ext-Proc Extensions**: Before forwarding, external-process filters in `cmd/atenet/internal/router/extproc/` can modify headers, enforce policies, or collect metrics.

5. **Atunnel Forwarding**: The router establishes mutual TLS connections to worker `atunnel` endpoints using the credentials defined in `UpstreamCredentialBundlePath` (lines 98-104 of [`config.go`](https://github.com/agent-substrate/substrate/blob/main/config.go)).

6. **Egress Handling**: For external calls, actors open CONNECT tunnels to `atenet-egress`, which validates SPIFFE identities (e.g., `spiffe://cluster.local/.../atenet-router`) and proxies traffic outward.

## Security and Operational Configuration

`atenet` employs a strict security model with flexible operational modes.

### Mode Selection and Control Plane

The `Mode` type (`ModeIngress`, `ModeEgress`, `ModeAll`) in [`cmd/atenet/internal/router/config.go`](https://github.com/agent-substrate/substrate/blob/main/cmd/atenet/internal/router/config.go) determines which control-plane components start in [`cmd/atenet/internal/router/router.go`](https://github.com/agent-substrate/substrate/blob/main/cmd/atenet/internal/router/router.go). The router only initializes the xDS server when `ServesIngress()` returns true. This allows operators to deploy single-purpose binaries for specific traffic directions, with the egress component capable of running in standalone `ModeEgress`.

### Mutual TLS and SPIFFE Identities

Both ingress and egress paths enforce mutual TLS using SPIFFE-based identities, visible throughout the codebase including [`cmd/atenet/internal/router/egress/egress.go`](https://github.com/agent-substrate/substrate/blob/main/cmd/atenet/internal/router/egress/egress.go). The `routerConfig` struct in [`cmd/atenet/internal/router/cmd.go`](https://github.com/agent-substrate/substrate/blob/main/cmd/atenet/internal/router/cmd.go) parses environment variables for TLS certificates, OTLP collector addresses, and identity bundles, ensuring all inter-service communication is cryptographically verified.

## Practical Usage Examples

### Calling an Actor Through the Ingress Router

The following example from [`demos/sandbox/client/main.go`](https://github.com/agent-substrate/substrate/blob/main/demos/sandbox/client/main.go) demonstrates how a client posts a command to an actor via the `atenet` router:

```go
func runCommand(ctx context.Context, atenetAddr string, actorRef resources.ActorRef, cmd string) (*ProcessResponse, error) {
    // Build the HTTP URL that the atenet router expects:
    //   http://<atenet-router-svc>:<port>/process
    url := fmt.Sprintf("http://%s/process", atenetAddr)

    // The request body contains the actor reference and the command to execute.
    body := map[string]any{
        "actor":   actorRef,
        "command": cmd,
    }
    // Send the request via the standard net/http client.
    resp, err := http.Post(url, "application/json", json.NewEncoder(body))
    // …handle response…
}

```

This client targets the router's `/process` endpoint, which triggers the ingress flow including potential parking and ext-proc handling before reaching the actor.

### Opening an Outbound Tunnel via the Egress Gateway

Actors reach external services by establishing CONNECT tunnels through `atenet-egress`, as shown in [`internal/e2e/fixtures/egressprobe/main.go`](https://github.com/agent-substrate/substrate/blob/main/internal/e2e/fixtures/egressprobe/main.go):

```go
func openEgressTunnel(ctx context.Context, target string) (net.Conn, error) {
    // The egress service is exposed as atenet-egress.<namespace>.svc:443
    proxy := "atenet-egress.ate-system.svc:443"

    // Establish a CONNECT tunnel with mutual TLS.
    dialer := &tls.Dialer{
        Config: &tls.Config{
            // The actor's SPIFFE identity is injected by the side-car.
            // The egress side-car validates it against the ActorIdentityCA.
        },
    }
    conn, err := dialer.DialContext(ctx, "tcp", proxy)
    if err != nil {
        return nil, err
    }

    // Send the CONNECT request to the egress gateway.
    fmt.Fprintf(conn, "CONNECT %s HTTP/1.1\r\n\r\n", target)
    // …now use conn as a regular TCP stream to the external service…
    return conn, nil
}

```

## Summary

- **`atenet`** provides the complete networking layer for Agent Substrate, split into `atenet-router` for ingress and `atenet-egress` for outbound traffic.
- The **ingress router** uses Envoy with dynamic xDS configuration, request parking, and ext-proc filters to securely forward HTTP requests to actors via `atunnel`.
- The **egress gateway** validates mTLS identities and proxies CONNECT tunnels without requiring Kubernetes API access.
- Configuration is controlled via the `Mode` type and `routerConfig` struct in [`cmd/atenet/internal/router/config.go`](https://github.com/agent-substrate/substrate/blob/main/cmd/atenet/internal/router/config.go), supporting flexible deployment topologies.
- All communication uses mutual TLS with SPIFFE identities, ensuring cryptographic verification between clients, routers, and actors.

## Frequently Asked Questions

### How does atenet route external HTTP requests to an actor?

External requests first hit the `atenet-router` Service, where an Envoy sidecar processes the request. The router's xDS control plane dynamically configures routes to available worker pods using the `ServesIngress` logic in [`cmd/atenet/internal/router/config.go`](https://github.com/agent-substrate/substrate/blob/main/cmd/atenet/internal/router/config.go). If the target worker is saturated, the request is temporarily parked using the implementation in [`cmd/atenet/internal/router/ingress/parking.go`](https://github.com/agent-substrate/substrate/blob/main/cmd/atenet/internal/router/ingress/parking.go) before being forwarded over an mTLS `atunnel` connection to the actor.

### What is the difference between atenet-router and atenet-egress?

`atenet-router` handles inbound traffic, runs an xDS control plane for dynamic Envoy configuration, and supports request parking and ext-proc extensions. `atenet-egress` handles outbound CONNECT tunnels from actors to external services, validates mTLS client certificates against `ActorIdentityCAFile`, and operates without an xDS server, allowing it to run without Kubernetes API permissions.

### How does atenet secure communication between components?

`atenet` enforces mutual TLS on all data paths. The ingress router presents SPIFFE identities when connecting to worker `atunnel` endpoints, while the egress gateway validates actor identities against the configured CA file. TLS configuration is managed through the `routerConfig` struct in [`cmd/atenet/internal/router/cmd.go`](https://github.com/agent-substrate/substrate/blob/main/cmd/atenet/internal/router/cmd.go), which parses certificates and identity bundles from environment variables or Helm values.

### Can atenet components run without Kubernetes API access?

Yes. The `atenet-egress` component specifically requires no Kubernetes API access because it does not run an xDS control plane. It operates in standalone `ModeEgress`, making it suitable for environments where the binary lacks cluster permissions. The ingress router requires API access to watch ActorTemplate resources and generate dynamic xDS configurations.