HTTP Proxy
AgentVisor™'s HTTP proxy transparently intercepts all outbound HTTP requests from agents, enabling policy enforcement without code changes.
How It Works
1. Agent code makes HTTP request
│ response = requests.get("https://api.openai.com/v1/models")
│
▼
2. Request intercepted by HTTPS_PROXY
│ → http://localhost:<dynamic-port>
│ → CONNECT api.openai.com:443
│
▼
3. Guest proxy terminates TLS
│ • Ephemeral CA signs per-host certificate
│ • TLS handshake with agent's HTTP client
│ • Decrypted request headers and body now visible
│
▼
4. Guest Runtime securely forwards decrypted request to Host
│ Over the private host channel (gRPC over UDS or TCP+mTLS)
│
▼
5. Host Runtime processes request
│
├─▶ 5a. Policy Check (MPE)
│ • Resource: mrn:agentvisor:http:api.openai.com/v1/models
│ • Operation: GET
│ • Principal: from context
│ │
│ ├─ ALLOWED → continue
│ └─ DENIED → return 403
│
├─▶ 5b. Audit Log
│ • Record request details
│ • Include policy decision
│
├─▶ 5c. Credential Substitution
│ • Replace symbolic tokens (mav-tok-...) with real credentials
│
└─▶ 5d. Execute Request
• Make actual HTTPS request to upstream
• Return response to guest
Transparent Proxying
The proxy is transparent - no code changes required:
# These all work automatically:
import requests
response = requests.get("https://api.openai.com/v1/models")
import httpx
async with httpx.AsyncClient() as client:
response = await client.get("https://api.anthropic.com/v1/complete")
from langchain_anthropic import ChatAnthropic
llm = ChatAnthropic(model="claude-sonnet-4-20250514")
response = llm.invoke("Hello!")
How Transparency Works
The guest runtime sets environment variables:
HTTP_PROXY=http://localhost:12345
HTTPS_PROXY=http://localhost:12345
NO_PROXY=localhost,127.0.0.1
Python's requests, httpx, urllib3, and aiohttp all honor these variables automatically.
HTTPS and TLS Termination
For HTTPS requests, the guest proxy terminates TLS using an ephemeral Certificate Authority. This enables the proxy to inspect request headers and bodies, which is required for credential brokering and full policy enforcement.
1. Client sends CONNECT api.openai.com:443
2. Proxy accepts the CONNECT tunnel
3. Proxy performs TLS handshake with the client
• Uses ephemeral CA to sign a certificate for api.openai.com
• Client trusts this cert via SSL_CERT_FILE CA bundle
4. Decrypted HTTP request is read from the TLS connection
5. Request securely forwarded to host over the hostlink session (gRPC over UDS or TCP+mTLS, depending on sandbox mode)
6. Host performs policy check, credential substitution, and upstream HTTPS request
This means:
- The proxy can inspect all request headers and body content
- Symbolic credential tokens are visible for credential brokering
- Full request details are available for policy enforcement and audit logging
- Agent HTTP libraries trust the proxy CA transparently via
SSL_CERT_FILE
Per-host certificates are generated on demand and cached (1-hour validity). The ephemeral CA is regenerated on each guest restart (30-day validity, configurable via AGENTVISOR_GUEST_CA_VALIDITY). No code changes are needed in the agent.
Streaming Support
The proxy supports SSE (Server-Sent Events) for LLM streaming:
from langchain_anthropic import ChatAnthropic
llm = ChatAnthropic(model="claude-sonnet-4-20250514", streaming=True)
for chunk in llm.stream("Tell me a story"):
print(chunk.content, end="", flush=True)
How Streaming Works
1. LLM request with stream=true
│
▼
2. Guest Runtime forwards the streaming request to Host
│
▼
3. Host makes request, receives SSE stream
│
▼
4. Host streams chunks back over the private host channel
│ Each chunk carries response data plus a done flag (and an
│ optional error if the upstream stream fails mid-flight)
│
▼
5. Guest Runtime converts to HTTP chunked response
│
▼
6. Python receives streaming response
Policy Integration
Every request is evaluated against the policy:
MRN Format
HTTP requests are converted to MRNs:
mrn:agentvisor:http:<host><path>
Examples:
• https://api.openai.com/v1/chat/completions
→ mrn:agentvisor:http:api.openai.com/v1/chat/completions
• http://httpbin.org/get?foo=bar
→ mrn:agentvisor:http:httpbin.org/get
Policy Example
resources:
# Allow OpenAI API
- name: openai
selector:
- "mrn:agentvisor:http:api\\.openai\\.com.*"
group: "mrn:iam:resource-group:allowed"
# Block internal networks
- name: internal
selector:
- "mrn:agentvisor:http:10\\..*"
- "mrn:agentvisor:http:192\\.168\\..*"
- "mrn:agentvisor:http:172\\.(1[6-9]|2[0-9]|3[0-1])\\..*"
group: "mrn:iam:resource-group:denied"
# Default deny
- name: default-http
selector:
- "mrn:agentvisor:http:.*"
group: "mrn:iam:resource-group:denied"
Configuration
Timeouts
# Request timeout (default 5m)
export AGENTVISOR_PROXY_REQUEST_TIMEOUT=30s
# Max body size (default 10MB)
export AGENTVISOR_PROXY_MAX_BODY_SIZE=10485760
Troubleshooting
Request Blocked
If a request is denied, check:
- Policy configuration: Does the resource match an allow rule?
- MRN format: Is the selector pattern correct?
- Policy order: Deny rules may match before allow rules
Enable debug logging:
AGENTVISOR_LOG_LEVEL=debug agentvisor serve ...
Timeouts
For long-running LLM requests:
export AGENTVISOR_PROXY_REQUEST_TIMEOUT=120s
SSL/TLS Errors
SSL errors in the sandbox typically indicate a CA bundle issue:
SSL_CERT_FILEnot set correctly: The guest runtime automatically setsSSL_CERT_FILEto a combined CA bundle containing both system CAs and the ephemeral proxy CA. If this variable is overridden, Python libraries won't trust the proxy.- Custom CA requirements: If your agent explicitly sets certificate paths, ensure the combined CA bundle is used instead.
- CA regeneration: The ephemeral CA regenerates on each restart. Agents pick this up automatically through the CA bundle file.
Enable debug logging to see TLS-related issues:
AGENTVISOR_LOG_LEVEL=debug agentvisor serve ...
Bypassing the Proxy
Bypassing the proxy removes all policy protection and credential brokering!
Only when running with --sandbox=none, you can set NO_PROXY to bypass specific hosts:
import os
os.environ["NO_PROXY"] = "localhost,127.0.0.1,internal.example.com"
In gVisor and Docker (container) modes, the proxy cannot be bypassed: either there is no network interface at all (gVisor, Docker on Linux), or outbound traffic is restricted by in-guest nftables to the hostlink address only (Docker on macOS/Windows). Either way, the proxy is the only route out.