This document provides detailed coverage of the reverse connection feature in Agent Protocol v2, which allows agents to connect to the proxy instead of the proxy connecting to agents.
Overview
Traditional agent deployment requires the proxy to initiate connections to agents:
┌─────────┐ ┌─────────┐
│ Proxy │ ──── Connect ────► │ Agent │
└─────────┘ └─────────┘
This model has limitations:
- Agents behind NAT cannot be reached
- Firewall rules must allow inbound connections to agents
- Static agent discovery required
- Scaling requires configuration changes
Reverse connections flip this model:
┌─────────┐ ┌─────────┐
│ Proxy │ ◄──── Connect ──── │ Agent │
│ │ │ (NAT) │
│ Listener│ │ │
└─────────┘ └─────────┘
Benefits:
- NAT Traversal: Agents behind NAT/firewalls can connect out
- Dynamic Scaling: Agents register on startup, no config changes
- Zero-Config Discovery: Agents announce their capabilities
- Load-Based Pooling: Agents can open multiple connections
Architecture
Component Overview
┌─────────────────────────────────────────────────────────────┐
│ Proxy │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ReverseConnectionListener │ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ UDS Socket │ │ TCP Socket │ │ │
│ │ │ (local) │ │ (remote) │ │ │
│ │ └──────┬──────┘ └──────┬──────┘ │ │
│ │ │ │ │ │
│ │ └────────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌───────────────┐ │ │
│ │ │ Registration │ │ │
│ │ │ Validator │ │ │
│ │ └───────┬───────┘ │ │
│ │ │ │ │
│ └─────────────────┼────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ AgentPool │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ waf-1 │ │ waf-2 │ │ auth-1 │ │ │
│ │ │(reverse) │ │(reverse) │ │(reverse) │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────┘
Registration Flow
Agent Proxy
│ │
│ 1. TCP/UDS Connect │
│ ───────────────────────────────────────────────────────►│
│ │
│ 2. RegistrationRequest │
│ { │
│ protocol_version: 2, │
│ agent_id: "waf-worker-3", │
│ capabilities: { │
│ handles_request_headers: true, │
│ handles_request_body: true, │
│ supports_cancellation: true, │
│ max_concurrent_requests: 100 │
│ }, │
│ auth_token: "secret-token", │
│ metadata: { "version": "1.2.0" } │
│ } │
│ ───────────────────────────────────────────────────────►│
│ │
│ 3. Validate │
│ - Auth │
│ - Allowlist │
│ │
│ 4. RegistrationResponse │
│ { │
│ accepted: true, │
│ assigned_id: "waf-worker-3-conn-7", │
│ config: { "rules_version": "3.4.0" } │
│ } │
│ ◄───────────────────────────────────────────────────────│
│ │
│ 5. Normal v2 protocol │
│ ◄──────────────────────────────────────────────────────►│
│ │
Listener Configuration
Basic Setup
use ;
use Duration;
let config = ReverseConnectionConfig ;
// UDS listener for local agents
let listener = bind_uds.await?;
// TCP listener for remote agents
let listener = bind_tcp.await?;
Configuration Options
| Option | Default | Description |
|---|---|---|
handshake_timeout | 10s | Time allowed for registration handshake |
max_connections_per_agent | 4 | Max connections from same agent_id |
require_auth | false | Require auth_token in registration |
allowed_agents | None | Allowlist of agent IDs (supports wildcards) |
Security Configuration
let config = ReverseConnectionConfig ;
Accepting Connections
Simple Accept Loop
let pool = new;
let listener = bind_uds.await?;
// Accept loop
loop
Production Accept Loop
use select;
use broadcast;
async
Agent-Side Implementation
Connecting to Proxy
use UnixStream;
use ;
async
Connection Pool on Agent Side
For high availability, agents should maintain multiple connections:
Error Handling
Registration Errors
| Error | Cause | Resolution |
|---|---|---|
| Version mismatch | Protocol version != 2 | Update agent to v2 |
| Auth failed | Invalid or missing token | Check auth configuration |
| Not allowed | Agent ID not in allowlist | Add to allowed_agents |
| Connection limit | Too many connections | Wait or reduce connections |
| Timeout | Handshake took too long | Check network/agent health |
Handling Disconnects
// Agent side: reconnect loop with exponential backoff
let mut backoff = from_secs;
loop
Best Practices
1. Use Multiple Connections Per Agent
// Agent side: maintain 4 connections for load distribution
let manager = new;
2. Include Useful Metadata
let request = RegistrationRequest ;
3. Handle Configuration Pushes
if let Some = response.config
4. Implement Health Monitoring
// Agent side: track connection health
let mut consecutive_errors = 0;
loop
KDL Configuration
Configure reverse connection listener in your Sentinel config:
reverse-listener {
path "/var/run/sentinel/agents.sock"
max-connections-per-agent 4
handshake-timeout "10s"
// Optional: TCP listener for remote agents
// tcp-address "0.0.0.0:9090"
// Security settings
require-auth true
allowed-agents "waf-*" "auth-agent"
}