@@ -10,29 +10,30 @@ by default.
1010Egress capture has no global on/off switch. ate-api watches Gateways labeled
1111` ate.dev/egress-pep ` . On actor resume, ate-api picks the best matching PEP
1212Gateway for that actor and sends one optional PEP address to ateom. An empty PEP
13- address means no redirect, so capture is enabled per actor purely by whether a
14- matching labeled Gateway exists . The reusable capture core lives in
15- ` internal/egress ` :
13+ address means no redirect, so capture is enabled per actor only when a matching
14+ programmed labeled Gateway with an HTTP listener resolves . The reusable capture
15+ core lives in ` internal/egress ` :
1616it owns capture listeners, authority derivation, CONNECT tunnel transports, and
1717byte proxying. The runtime-specific ` ateom ` egress proxy setup supplies the
1818original-destination lookup and packet-capture rules.
1919
20- The current gVisor implementation starts a local capture listener and installs
21- actor-network redirects for TCP/80 and TCP/443 . From the actor's point of view
22- it still opens a normal HTTP or HTTPS connection to the original destination.
23- MicroVM or future hypervisor implementations should reuse
24- ` internal/egress ` for the local listener, authority derivation, tunnel
25- transport, and byte proxying. Each runtime still provides its own egress proxy
26- setup for redirecting actor traffic and recovering the original destination.
20+ The current gVisor and MicroVM implementations start a local capture listener
21+ and install actor-network redirects for TCP egress . From the actor's point of
22+ view it still opens a normal TCP connection to the original destination. Future
23+ hypervisor implementations should reuse ` internal/egress ` for the local
24+ listener, authority derivation, tunnel transport, and byte proxying. Each
25+ runtime still provides its own egress proxy setup for redirecting actor traffic
26+ and recovering the original destination.
2727
2828The redirected connection lands on ` ateom ` , which records the original
2929destination and derives a stable CONNECT authority from the first bytes of the
3030actor connection:
3131
3232| Actor traffic | Authority source | Example CONNECT authority |
3333| --- | --- | --- |
34- | HTTPS / TCP 443 | TLS ClientHello SNI | ` httpbin.org:443 ` |
35- | Plaintext HTTP / TCP 80 | HTTP ` Host ` header | ` example.com:80 ` |
34+ | HTTPS / any TCP port | TLS ClientHello SNI + original destination port | ` httpbin.org:443 ` |
35+ | Plaintext HTTP / any TCP port | HTTP ` Host ` header, defaulting to original destination port when the header has no port | ` example.com:80 ` |
36+ | Other TCP | Original destination address | ` 203.0.113.10:2222 ` |
3637
3738The shared capture core then opens a plaintext HTTP/2 CONNECT stream to the PEP
3839address selected by ate-api. Only Gateways with condition ` Programmed=True ` are
@@ -45,11 +46,12 @@ stays pending). The port is the Gateway's HTTP listener port. Agentgateway maps
4546the CONNECT authority to its configured TCP listener and routes the tunnel to a
4647Kubernetes Service backed by an EndpointSlice.
4748
48- The demo setup configures only ` httpbin.org:443 ` for egress.
49- Other hosts or plaintext HTTP destinations need their own agentgateway
50- Service, EndpointSlice, listener, and route. For HTTPS, TLS is still end-to-end
51- between the actor and the external service; agentgateway only routes the
52- encrypted bytes after CONNECT succeeds.
49+ The demo setup configures only ` httpbin.org:443 ` for egress. Any other CONNECT
50+ authority, including plaintext HTTP destinations or fallback original IP: port
51+ authorities, needs its own matching agentgateway Service, EndpointSlice,
52+ listener, and route. For HTTPS, TLS is still end-to-end between the actor and
53+ the external service; agentgateway only routes the encrypted bytes after
54+ CONNECT succeeds.
5355
5456### Selecting a PEP for an actor
5557
@@ -73,7 +75,7 @@ highest-precedence match (`resolveEgressPEPAddress` in
7375| Situation | Result |
7476| --- | --- |
7577| Multiple candidates tied at the top score | Lowest ` (namespace, name) ` wins; the others are ** silently ignored** |
76- | No labeled candidate | Empty PEP address → no redirect, capture off |
78+ | No matching programmed candidate | Empty PEP address → no redirect, capture off |
7779
7880Don't deploy multiple PEPs at the same tier for the same actor — use the
7981scoping labels to raise the intended one's tier instead of relying on name
@@ -88,8 +90,8 @@ label a Gateway can:
8890
8991- ** Intercept actor egress** : copy an actor's ` ate.dev/atespace ` +
9092 ` ate.dev/actor ` labels onto their own Gateway to out-score its real PEP.
91- - ** Block all resumes** : label a Gateway with no HTTP listener (broken PEP
92- config fails resolution cluster-wide by design).
93+ - ** Block resumes** : label a programmed Gateway with no HTTP listener (broken
94+ PEP config fails PEP resolution by design).
9395
9496Substrate deliberately does not second-guess labeled Gateways. If Gateway RBAC
9597can't be that strict, scope the watch to an allowlist of PEP namespaces in
@@ -163,7 +165,7 @@ sequenceDiagram
163165 rect rgb(255, 248, 225)
164166 Note over OM,EXT: Actor egress connection
165167 OM->>CAP: Actor conn (nftables redirect) to httpbin.org:443
166- CAP->>CAP: Get original destination<br/>sniff SNI or Host
168+ CAP->>CAP: Get original destination<br/>classify SNI, Host, or original dst
167169 CAP->>PEP: HTTP/2 CONNECT httpbin.org:443<br/>with actor metadata
168170 PEP->>EXT: Route via TCPRoute
169171 Note over CAP,EXT: TLS remains end-to-end<br/>PEP routes encrypted bytes only
@@ -218,8 +220,9 @@ system. No fixed PEP address is configured; ate-api derives the address from the
218220labeled Gateway's HTTP listener.
219221
220222The install script resolves ` httpbin.org ` during install and creates the
221- ` httpbin-egress ` Service and EndpointSlice for those IPs. ` ateom ` derives the
222- CONNECT authority from SNI for this HTTPS demo.
223+ ` httpbin-egress ` Service and EndpointSlice for those IPs. For the default HTTPS
224+ demo request, ` ateom ` derives the CONNECT authority from TLS SNI and the
225+ original destination port.
223226
224227Verify the static agentgateway resources and PEP label:
225228
@@ -299,8 +302,9 @@ curl -i -X POST --get \
299302 " http://localhost:8000"
300303```
301304
302- Do not use this query parameter for a different host unless you also update the
303- agentgateway route. ` ateom ` will derive the new host from SNI, but the demo
305+ Do not use this query parameter for a different host or port unless you also
306+ update the agentgateway route. ` ateom ` will derive the new CONNECT authority
307+ from TLS SNI, the HTTP ` Host ` header, or the original destination, but the demo
304308agentgateway config only routes ` httpbin.org:443 ` .
305309
306310## Verify capture was installed
490494 http://localhost:8000
491495 ```
492496
493- The authoritative signal is the ateom capture log, which names the PEP the
494- actor actually tunnelled through (see "Verify capture was installed" for how
495- to find the worker pod):
497+ The authoritative signal is the ateom capture log, which names the PEP
498+ configured for the actor's current activation (see "Verify capture was
499+ installed" for how to find the worker pod):
496500
497501 ``` bash
498502 kubectl logs -n " ${ateom_ns} " " ${ateom_pod} " -c ateom | grep " Started actor egress capture listener"
@@ -593,21 +597,12 @@ PEP address, so `egressPepAddress` on the actor can report a binding the
593597sandbox does not enforce. If capture logs are missing despite a resolved PEP,
594598check the WorkerPool's ateom image version.
595599
596- If the capture listener logs are missing, confirm that the actor is running on a
597- fresh worker pod created after egress was enabled:
600+ If the egress request fails after changing the ` url ` host or port, remember that
601+ this demo only configures agentgateway for ` httpbin.org:443 ` . Add matching static
602+ agentgateway backend resources for the CONNECT authority that ` ateom ` will send:
598603
599- ``` bash
600- kubectl ate get actor my-egress-1 -a demo
601- kubectl get pods -n ate-demo-egress -l ate.dev/worker-pool=egress
602- ```
603-
604- If the egress request fails after changing the ` url ` host, remember that this demo only
605- configures agentgateway for ` httpbin.org:443 ` . Add matching static agentgateway
606- backend resources for the new destination:
607-
608- - HTTPS: Service, EndpointSlice, TCP listener on ` 443 ` , and TCPRoute.
609- - Plaintext HTTP: Service, EndpointSlice, TCP listener on ` 80 ` , and TCPRoute.
610-
611- Traffic without SNI or a plaintext HTTP ` Host ` header falls back to the captured
612- original destination IP and port, which requires matching agentgateway routing
613- for that address.
604+ - HTTPS: SNI plus the original destination port, for example ` example.com:443 ` .
605+ - Plaintext HTTP: ` Host ` header authority, defaulting to the original
606+ destination port when the header has no port, for example ` example.com:80 ` .
607+ - Other TCP: captured original destination IP and port, for example
608+ ` 203.0.113.10:2222 ` .
0 commit comments