Sentinel agents communicate with the proxy over two transport mechanisms: Unix domain sockets (UDS) and gRPC. Both transports use the same logical protocol—only the wire encoding differs.
Transport Comparison
| Feature | Unix Socket | gRPC |
|---|---|---|
| Encoding | Length-prefixed JSON | Protocol Buffers |
| Location | Local only | Local or remote |
| Latency | ~50-100µs | ~100-500µs |
| Throughput | High | Very high |
| Streaming | Manual chunking | Native support |
| Tooling | Any JSON library | Protobuf + gRPC toolchain |
| Language Support | Universal | Most languages |
Unix Domain Sockets
Unix sockets provide the lowest-latency option for agents running on the same host as Sentinel.
Wire Format
Messages are length-prefixed JSON:
┌──────────────────┬─────────────────────────────────────┐
│ Length (4 bytes) │ JSON Message (variable length) │
│ Big-endian u32 │ UTF-8 encoded │
└──────────────────┴─────────────────────────────────────┘
Example:
00 00 00 1A {"event_type":"request_headers"...}
└─────────┘ └──────────────────────────────────┘
26 bytes JSON payload
Configuration
agent "my-agent" type="custom" {
unix-socket "/var/run/sentinel/my-agent.sock"
events "request_headers"
timeout-ms 100
}
Message Flow
Sentinel Proxy Agent Process
│ │
│ ──── [4 bytes: length] ────────────────▶ │
│ ──── [N bytes: JSON request] ──────────▶ │
│ │
│ (process)
│ │
│ ◀──── [4 bytes: length] ─────────────── │
│ ◀──── [N bytes: JSON response] ──────── │
│ │
Rust Implementation
Server Side (Agent):
use UnixListener;
use ;
async
Client Side (Proxy):
use UnixStream;
async
JSON Message Format
Request:
Response:
Socket Path Conventions
| Pattern | Use Case |
|---|---|
/var/run/sentinel/<agent>.sock | Production (systemd) |
/tmp/<agent>.sock | Development/testing |
~/.sentinel/<agent>.sock | User-space development |
Message Size Limits
The protocol enforces a maximum message size of 16 MB (16,777,216 bytes). Messages exceeding this limit are rejected:
const MAX_MESSAGE_SIZE: usize = 16 * 1024 * 1024;
gRPC Transport
gRPC provides higher throughput and native streaming support, ideal for remote agents or high-volume scenarios.
Configuration
agent "waf-agent" type="waf" {
grpc "http://localhost:50051"
events "request_headers" "request_body"
timeout-ms 200
}
// Remote agent (Kubernetes sidecar, etc.)
agent "ml-scorer" type="custom" {
grpc "http://ml-service.default.svc.cluster.local:50051"
timeout-ms 500
}
Service Definition
Agents implement the AgentProcessor service:
service AgentProcessor {
// Process a single event
rpc ProcessEvent(AgentRequest) returns (AgentResponse);
// Stream body chunks for inspection
rpc ProcessEventStream(stream AgentRequest) returns (AgentResponse);
}
Rust Implementation (Server)
Using the sentinel-agent-protocol crate:
use ;
;
async
Go Implementation (Server)
package main
import (
"context"
"net"
pb "github.com/raskell-io/sentinel-proto/go"
"google.golang.org/grpc"
)
type myAgent struct
func (
ctx context.Context,
req *pb.AgentRequest,
) (*pb.AgentResponse, error)
func main()
Python Implementation (Server)
=
# Your logic here
return
=
Testing with grpcurl
# List available services
# Test request headers event
Streaming for Body Inspection
For large request/response bodies, use the streaming RPC:
// Client-side (proxy sending body chunks)
let mut stream = client.process_event_stream.await?;
// Send headers first
stream.send.await?;
// Stream body chunks
for chunk in body_chunks
// Get final response
let response = stream.finish.await?;
Choosing a Transport
Use Unix Sockets When:
- Agent runs on the same host as Sentinel
- Latency is critical (< 100µs per call)
- Simplicity is preferred (no protobuf toolchain)
- Deploying as systemd services
Use gRPC When:
- Agent runs on a different host
- Building agents in languages with strong gRPC support
- Need streaming for large body inspection
- Deploying in Kubernetes (service mesh integration)
- Higher throughput requirements
Connection Management
Unix Socket Considerations
agent "local-auth" type="auth" {
unix-socket "/var/run/sentinel/auth.sock"
// Connection pool settings
pool {
min-connections 2
max-connections 10
idle-timeout-ms 30000
}
}
gRPC Considerations
agent "remote-waf" type="waf" {
grpc "http://waf-service:50051"
// HTTP/2 connection settings
http2 {
keep-alive-interval-ms 10000
keep-alive-timeout-ms 5000
max-concurrent-streams 100
}
}
Security
Unix Socket Security
Unix sockets rely on filesystem permissions:
# Restrict socket access
gRPC Security
For production gRPC agents, use TLS:
agent "secure-agent" type="custom" {
grpc "https://agent.internal:50051"
tls {
ca-cert "/etc/sentinel/ca.crt"
client-cert "/etc/sentinel/client.crt"
client-key "/etc/sentinel/client.key"
}
}
Failure Handling
Both transports support the same failure policies:
agent "auth" type="auth" {
unix-socket "/var/run/sentinel/auth.sock"
timeout-ms 100
// What to do when agent fails
failure-mode "closed" // Block requests (secure default)
// failure-mode "open" // Allow requests (availability)
// Circuit breaker
circuit-breaker {
failure-threshold 5 // Open after 5 failures
success-threshold 3 // Close after 3 successes
timeout-seconds 30 // Half-open after 30s
}
}