Agents

Agents are external processes that extend Sentinel’s functionality. They handle security policies, authentication, rate limiting, and custom business logic. The agents block configures how Sentinel connects to and communicates with these agents.

Basic Configuration

agents {
    agent "waf-agent" type="waf" {
        unix-socket "/var/run/sentinel/waf.sock"
        events "request_headers" "request_body"
        timeout-ms 200
        failure-mode "closed"
    }

    agent "auth-agent" type="auth" {
        grpc "http://localhost:50051"
        events "request_headers"
        timeout-ms 100
        failure-mode "closed"
        circuit-breaker {
            failure-threshold 5
            timeout-seconds 30
        }
    }
}

Agent Types

TypeDescription
wafWeb Application Firewall
authAuthentication and authorization
rate_limitRate limiting decisions
customCustom agent type (specify name)

Transports

Unix Socket

Low-latency local communication:

agent "local-agent" type="auth" {
    unix-socket "/var/run/sentinel/agent.sock"
    events "request_headers"
    timeout-ms 100
}

gRPC

Remote agent over HTTP/2:

agent "remote-agent" type="waf" {
    grpc "http://waf-service:50051"
    events "request_headers" "request_body"
    timeout-ms 200
}

With TLS:

agent "secure-agent" type="auth" {
    grpc "https://auth-service:50051" {
        ca-cert "/etc/sentinel/ca.crt"
        client-cert "/etc/sentinel/client.crt"
        client-key "/etc/sentinel/client.key"
    }
    events "request_headers"
}

HTTP

REST API agent using JSON over HTTP. This is the simplest transport option, making it easy to build agents in any language with HTTP support.

Basic HTTP

agent "http-agent" type="custom" {
    http "http://policy-service:8080/agent"
    events "request_headers"
    timeout-ms 150
}

HTTPS with TLS

agent "secure-http-agent" type="auth" {
    http "https://auth-service:8443/agent" {
        ca-cert "/etc/sentinel/certs/ca.crt"
    }
    events "request_headers"
    timeout-ms 100
}

HTTPS with mTLS

agent "mtls-agent" type="waf" {
    http "https://waf-service:8443/agent" {
        ca-cert "/etc/sentinel/certs/ca.crt"
        client-cert "/etc/sentinel/certs/client.crt"
        client-key "/etc/sentinel/certs/client.key"
    }
    events "request_headers" "request_body"
    timeout-ms 200
}

HTTP Protocol

Sentinel sends events as JSON POST requests:

POST /agent HTTP/1.1
Host: policy-service:8080
Content-Type: application/json
X-Sentinel-Protocol-Version: 1

{
  "version": 1,
  "event_type": "request_headers",
  "payload": {
    "metadata": {
      "correlation_id": "abc123",
      "request_id": "req-456",
      "client_ip": "192.168.1.100",
      "route_id": "api-route"
    },
    "method": "POST",
    "uri": "/api/users",
    "headers": {
      "content-type": ["application/json"],
      "authorization": ["Bearer token..."]
    }
  }
}

Agents respond with JSON:

{
  "version": 1,
  "decision": "allow",
  "request_headers": [
    {"set": {"name": "X-User-ID", "value": "user-123"}}
  ],
  "audit": {
    "tags": ["authenticated"],
    "rule_ids": ["auth-001"]
  }
}

When to Use HTTP

Use CaseRecommended Transport
Simple agents in any languageHTTP
High-throughput, low-latencyUnix Socket
Binary protocol, streaminggRPC
Cross-network, load-balancedHTTP or gRPC
Development/prototypingHTTP

HTTP advantages:

  • Works with any language/framework that handles HTTP
  • Easy to debug with curl or browser tools
  • Simple JSON payloads
  • Standard load balancers and proxies work out of the box

HTTP trade-offs:

  • Higher overhead than Unix sockets
  • No streaming (full request/response per call)
  • JSON parsing overhead vs binary protocols

Events

Specify which lifecycle events the agent handles:

agent "waf-agent" type="waf" {
    unix-socket "/var/run/sentinel/waf.sock"
    events "request_headers" "request_body" "response_headers"
}
EventDescription
request_headersHTTP request headers received
request_bodyRequest body chunks
response_headersUpstream response headers received
response_bodyResponse body chunks
logRequest complete (for logging)
websocket_frameWebSocket frames (after upgrade)

Failure Handling

Failure Mode

Configure behavior when the agent is unavailable:

agent "auth-agent" type="auth" {
    failure-mode "closed"   // Block requests if agent fails
}

agent "analytics-agent" type="custom" {
    failure-mode "open"     // Allow requests if agent fails
}
ModeBehavior
closedBlock requests when agent unavailable (security-first)
openAllow requests through when agent unavailable (availability-first)

Circuit Breaker

Prevent cascading failures with circuit breakers:

agent "waf-agent" type="waf" {
    circuit-breaker {
        failure-threshold 5         // Open after 5 failures
        success-threshold 2         // Close after 2 successes
        timeout-seconds 30          // Wait before half-open
        half-open-max-requests 1    // Requests in half-open state
    }
}
OptionDefaultDescription
failure-threshold5Failures to open circuit
success-threshold2Successes to close circuit
timeout-seconds30Seconds before half-open
half-open-max-requests1Test requests in half-open

Circuit breaker states:

  • Closed: Normal operation
  • Open: Agent bypassed (fails immediately)
  • Half-Open: Testing if agent recovered

Timeouts

agent "waf-agent" type="waf" {
    timeout-ms 200         // Total call timeout
    chunk-timeout-ms 5000  // Per-chunk timeout (streaming)
}

Body Processing

Body Size Limits

agent "waf-agent" type="waf" {
    max-request-body-bytes 10485760   // 10MB
    max-response-body-bytes 5242880   // 5MB
}

Body Streaming Modes

Control how bodies are sent to agents:

// Buffer entire body (default)
agent "waf-agent" type="waf" {
    request-body-mode "buffer"
    response-body-mode "buffer"
}

// Stream chunks as they arrive
agent "streaming-agent" type="custom" {
    request-body-mode "stream"
    chunk-timeout-ms 5000
}

// Hybrid: buffer small, stream large
agent "hybrid-agent" type="custom" {
    request-body-mode "hybrid:65536"   // Buffer up to 64KB
}
ModeDescription
bufferCollect entire body before sending (default)
streamSend chunks as they arrive
hybrid:<bytes>Buffer up to threshold, then stream

WAF Body Inspection

For WAF agents that need to inspect request bodies, Sentinel provides a dedicated body inspection pipeline with security controls.

WAF Configuration Block

Configure body inspection globally via the waf block:

waf {
    body-inspection {
        inspect-request-body #true
        inspect-response-body #false
        max-body-inspection-bytes 1048576   // 1MB
        content-types "application/json" "application/x-www-form-urlencoded" "text/xml"
        decompress #true
        max-decompression-ratio 100.0
    }
}

Body Inspection Options

OptionDefaultDescription
inspect-request-bodyfalseEnable request body inspection
inspect-response-bodyfalseEnable response body inspection
max-body-inspection-bytes1048576Max bytes to buffer for inspection
content-typesSee belowContent types eligible for inspection
decompressfalseDecompress bodies before inspection
max-decompression-ratio100.0Max compression ratio (zip bomb protection)

Default content types for inspection:

  • application/json
  • application/x-www-form-urlencoded
  • text/xml
  • application/xml
  • text/plain

Body Decompression

When decompress is enabled, Sentinel automatically decompresses request bodies before sending them to WAF agents. This allows WAF rules to inspect the actual content of compressed payloads.

Supported encodings:

  • gzip - Most common compression
  • deflate - Raw deflate compression
  • br - Brotli compression

Security protections:

ProtectionDefaultDescription
Max ratio100xPrevents zip bombs (rejects if decompressed/compressed > ratio)
Max output size10MBHard limit on decompressed size
Fail modeRoute settingUses route’s failure-mode for decompression errors
waf {
    body-inspection {
        decompress #true
        max-decompression-ratio 50.0    // Stricter limit for sensitive routes
    }
}

Decompression Behavior

Scenariofail-openfail-closed
Decompression succeedsInspect decompressed bodyInspect decompressed body
Ratio exceededInspect compressed bodyBlock with 400
Size exceededInspect compressed bodyBlock with 400
Invalid dataInspect compressed bodyBlock with 400

Metrics

Decompression operations are tracked via Prometheus metrics:

MetricLabelsDescription
sentinel_decompression_totalencoding, resultTotal decompression operations
sentinel_decompression_ratioencodingHistogram of compression ratios

Result labels: success, ratio_exceeded, size_exceeded, invalid_data, io_error

Complete WAF Example

waf {
    body-inspection {
        inspect-request-body #true
        max-body-inspection-bytes 1048576
        content-types "application/json" "application/xml" "text/plain"
        decompress #true
        max-decompression-ratio 100.0
    }
}

agents {
    agent "modsecurity" type="waf" {
        unix-socket "/var/run/sentinel/modsec.sock"
        events "request_headers" "request_body"
        timeout-ms 200
        failure-mode "closed"
        request-body-mode "buffer"
        circuit-breaker {
            failure-threshold 10
            timeout-seconds 60
        }
        config {
            rules-path "/etc/modsecurity/crs"
            paranoia-level 2
        }
    }
}

routes {
    route "api" {
        matches { path-prefix "/api/" }
        upstream "backend"
        policies {
            failure-mode "closed"   // Used for decompression errors
        }
        filters "waf-filter"
    }
}

filters {
    filter "waf-filter" {
        type "agent"
        agent "modsecurity"
        phase "request"
        failure-mode "closed"
    }
}

Agent-Specific Configuration

Pass configuration to agents via the config block:

agent "waf-agent" type="waf" {
    unix-socket "/var/run/sentinel/waf.sock"
    config {
        rules-path "/etc/sentinel/waf-rules"
        paranoia-level 2
        block-suspicious #true
    }
}

The configuration is passed to the agent when it connects.

Attaching Agents to Routes

Reference agents in route configuration:

routes {
    // Via filters
    route "api" {
        filters "waf-filter"   // Filter referencing agent
    }
}

filters {
    filter "waf-filter" {
        type "agent"
        agent "waf-agent"
        phase "request"
        timeout-ms 200
        failure-mode "closed"
    }
}

Complete Examples

WAF Agent

agents {
    agent "modsecurity" type="waf" {
        unix-socket "/var/run/sentinel/modsec.sock"
        events "request_headers" "request_body"
        timeout-ms 200
        failure-mode "closed"
        max-request-body-bytes 1048576    // 1MB for inspection
        request-body-mode "buffer"
        circuit-breaker {
            failure-threshold 10
            timeout-seconds 60
        }
        config {
            rules-path "/etc/modsecurity/crs"
            paranoia-level 1
        }
    }
}

Authentication Agent

agents {
    agent "jwt-auth" type="auth" {
        grpc "http://auth-service:50051"
        events "request_headers"
        timeout-ms 50
        failure-mode "closed"
        circuit-breaker {
            failure-threshold 5
            timeout-seconds 30
        }
        config {
            issuer "https://auth.example.com"
            audience "api.example.com"
        }
    }
}

Rate Limiting Agent

agents {
    agent "rate-limiter" type="rate_limit" {
        grpc "http://ratelimit-service:50051"
        events "request_headers"
        timeout-ms 20
        failure-mode "open"    // Allow through if service down
        circuit-breaker {
            failure-threshold 3
            timeout-seconds 15
        }
    }
}

Logging/Analytics Agent

agents {
    agent "analytics" type="custom" {
        http "http://analytics:8080/log"
        events "log"           // Only receive completion events
        timeout-ms 1000
        failure-mode "open"    // Don't block requests for logging
    }
}

TLS Configuration

Secure gRPC connections to agents with TLS and mutual TLS (mTLS).

TLS Options

OptionDescription
ca-certPath to CA certificate for verifying the agent’s server certificate
client-certPath to client certificate for mTLS authentication
client-keyPath to client private key for mTLS authentication
insecure-skip-verifySkip certificate verification (development only)

Server TLS (One-Way)

Verify the agent’s identity using TLS:

agent "secure-agent" type="auth" {
    grpc "https://auth-service.internal:50051" {
        ca-cert "/etc/sentinel/certs/ca.crt"
    }
    events "request_headers"
    timeout-ms 100
}

This configuration:

  • Encrypts traffic between Sentinel and the agent
  • Verifies the agent’s certificate against the provided CA
  • Automatically extracts domain name for SNI from the address

Mutual TLS (mTLS)

For bidirectional authentication where both Sentinel and the agent verify each other:

agent "secure-waf" type="waf" {
    grpc "https://waf-service.internal:50051" {
        ca-cert "/etc/sentinel/certs/ca.crt"
        client-cert "/etc/sentinel/certs/sentinel-client.crt"
        client-key "/etc/sentinel/certs/sentinel-client.key"
    }
    events "request_headers" "request_body"
    timeout-ms 200
    failure-mode "closed"
}

This configuration:

  • Encrypts traffic with TLS
  • Verifies the agent’s certificate against the CA
  • Presents Sentinel’s client certificate to the agent for verification
  • Provides strong mutual authentication for security-sensitive agents

Using System CA Store

When no ca-cert is specified, Sentinel uses the system’s native certificate store for server verification:

agent "public-agent" type="custom" {
    grpc "https://agent.example.com:50051"
    events "request_headers"
}

This works well for agents using certificates from public CAs (Let’s Encrypt, DigiCert, etc.).

Skip Verification (Development Only)

Warning: Only use this for local development. Never use in production.

agent "dev-agent" type="custom" {
    grpc "https://localhost:50051" {
        insecure-skip-verify
    }
    events "request_headers"
}

When enabled, Sentinel logs a security warning:

WARN: TLS certificate verification disabled for agent connection

Certificate Setup

Generate CA and Certificates

# Create CA
openssl genrsa -out ca.key 4096
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt \
    -subj "/CN=Sentinel Agent CA"

# Create agent server certificate
openssl genrsa -out agent.key 2048
openssl req -new -key agent.key -out agent.csr \
    -subj "/CN=waf-service.internal"
openssl x509 -req -days 365 -in agent.csr -CA ca.crt -CAkey ca.key \
    -CAcreateserial -out agent.crt

# Create Sentinel client certificate (for mTLS)
openssl genrsa -out sentinel-client.key 2048
openssl req -new -key sentinel-client.key -out sentinel-client.csr \
    -subj "/CN=sentinel-proxy"
openssl x509 -req -days 365 -in sentinel-client.csr -CA ca.crt -CAkey ca.key \
    -CAcreateserial -out sentinel-client.crt

File Permissions

# Secure the private keys
chmod 600 /etc/sentinel/certs/*.key
chown sentinel:sentinel /etc/sentinel/certs/*

Complete Secure Agent Example

agents {
    // WAF with mTLS - highest security
    agent "modsecurity" type="waf" {
        grpc "https://waf.internal:50051" {
            ca-cert "/etc/sentinel/certs/ca.crt"
            client-cert "/etc/sentinel/certs/sentinel-client.crt"
            client-key "/etc/sentinel/certs/sentinel-client.key"
        }
        events "request_headers" "request_body"
        timeout-ms 200
        failure-mode "closed"
        circuit-breaker {
            failure-threshold 10
            timeout-seconds 60
        }
    }

    // Auth with server-only TLS
    agent "jwt-auth" type="auth" {
        grpc "https://auth.internal:50051" {
            ca-cert "/etc/sentinel/certs/ca.crt"
        }
        events "request_headers"
        timeout-ms 50
        failure-mode "closed"
    }

    // Rate limiter - internal network, no TLS
    agent "rate-limiter" type="rate_limit" {
        grpc "http://ratelimit.internal:50051"
        events "request_headers"
        timeout-ms 20
        failure-mode "open"
    }
}

Troubleshooting TLS

ErrorCauseSolution
certificate verify failedCA doesn’t match agent certVerify CA certificate is correct
certificate has expiredAgent cert expiredRenew agent certificate
handshake failureTLS version mismatchCheck both ends support TLS 1.2+
unknown caMissing CA certAdd ca-cert option
bad certificateClient cert rejectedVerify client cert signed by agent’s CA

Default Values

SettingDefault
timeout-ms1000 (1 second)
failure-modeopen
chunk-timeout-ms5000 (5 seconds)
request-body-modebuffer
response-body-modebuffer
circuit-breaker.failure-threshold5
circuit-breaker.success-threshold2
circuit-breaker.timeout-seconds30
circuit-breaker.half-open-max-requests1

Metrics

Agent-related metrics:

MetricDescription
sentinel_agent_requests_totalAgent calls by agent and status
sentinel_agent_duration_secondsAgent call latency
sentinel_agent_errors_totalAgent errors
sentinel_agent_timeouts_totalAgent timeouts
sentinel_agent_circuit_breaker_stateCircuit breaker state

Configuration Validation

Sentinel validates agent configuration at startup:

Transport Validation

TransportValidation
Unix SocketPath exists and is a socket file
gRPCValid URL format (http/https with host)
HTTPValid URL format

Example validation errors:

Error: Agent 'auth' socket path '/var/run/sentinel/auth.sock' does not exist
Error: Agent 'waf' path '/tmp/not-a-socket' exists but is not a socket
Error: Agent 'remote' gRPC address 'invalid-url' is not a valid URL

Pre-flight Checks

Run validation before deployment:

sentinel --config sentinel.kdl --validate

This checks:

  • All referenced agents exist
  • Transport paths/URLs are valid
  • Timeout values are within bounds
  • Circuit breaker thresholds are valid

Next Steps