Skip to content

Commit 3a5f362

Browse files
congwang-mkclaude
andcommitted
docs: add HTTP ACL documentation to READMEs
Add HTTP ACL feature documentation: - CLI examples (--http-allow, --http-deny, --https-ca/--https-key) - Python API example with http_allow/http_deny - Rust API example with http_allow/http_deny - Feature comparison table entry - Policy reference with all HTTP ACL fields - Python SDK README: new HTTP ACL section with parameter table, rule format docs, and code example Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 6044935 commit 3a5f362

2 files changed

Lines changed: 69 additions & 1 deletion

File tree

README.md

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ protects your working directory automatically.
2323
| Kernel | Shared | Shared | Separate guest |
2424
| Filesystem isolation | Landlock + seccomp COW | Overlay | Block-level |
2525
| Network isolation | Landlock + seccomp notif | Network namespace | TAP device |
26+
| HTTP-level ACL | Method + host + path rules | N/A | N/A |
2627
| Syscall filtering | seccomp-bpf | seccomp | N/A |
2728
| Resource limits | seccomp notif + SIGSTOP | cgroup v2 | VM config |
2829

@@ -102,6 +103,19 @@ sandlock run -m 512M -P 20 -t 30 -- ./compute.sh
102103
# Domain-based network isolation
103104
sandlock run --net-allow-host api.openai.com -r /usr -r /lib -r /etc -- python3 agent.py
104105

106+
# HTTP-level ACL (method + host + path rules via transparent proxy)
107+
sandlock run \
108+
--http-allow "GET docs.python.org/*" \
109+
--http-allow "POST api.openai.com/v1/chat/completions" \
110+
--http-deny "* */admin/*" \
111+
-r /usr -r /lib -r /etc -- python3 agent.py
112+
113+
# HTTPS MITM with user-provided CA (enables ACL on port 443)
114+
sandlock run \
115+
--http-allow "POST api.openai.com/v1/*" \
116+
--https-ca ca.pem --https-key ca-key.pem \
117+
-r /usr -r /lib -r /etc -- python3 agent.py
118+
105119
# TCP port restrictions (Landlock)
106120
sandlock run --net-bind 8080 --net-connect 443 -r /usr -r /lib -r /etc -- python3 server.py
107121

@@ -151,6 +165,14 @@ result = Sandbox(policy).run(["python3", "-c", "print('hello')"])
151165
assert result.success
152166
assert b"hello" in result.stdout
153167

168+
# HTTP ACL: only allow specific API calls
169+
agent_policy = Policy(
170+
fs_readable=["/usr", "/lib", "/etc"],
171+
http_allow=["POST api.openai.com/v1/chat/completions"],
172+
http_deny=["* */admin/*"],
173+
)
174+
result = Sandbox(agent_policy).run(["python3", "agent.py"])
175+
154176
# Confine the current process (Landlock filesystem only, irreversible)
155177
confine(Policy(fs_readable=["/usr", "/lib"], fs_writable=["/tmp"]))
156178

@@ -259,6 +281,14 @@ let policy = Policy::builder()
259281
let result = Sandbox::run(&policy, &["echo", "hello"]).await?;
260282
assert!(result.success());
261283

284+
// HTTP ACL: restrict API access at the HTTP level
285+
let policy = Policy::builder()
286+
.fs_read("/usr").fs_read("/lib").fs_read("/etc")
287+
.http_allow("POST api.openai.com/v1/chat/completions")
288+
.http_deny("* */admin/*")
289+
.build()?;
290+
let result = Sandbox::run(&policy, &["python3", "agent.py"]).await?;
291+
262292
// Confine the current process (Landlock filesystem only, irreversible)
263293
let policy = Policy::builder()
264294
.fs_read("/usr").fs_read("/lib")
@@ -342,7 +372,7 @@ The async notification supervisor (tokio) handles intercepted syscalls:
342372
|---|---|
343373
| `clone/fork/vfork` | Process count enforcement |
344374
| `mmap/munmap/brk/mremap` | Memory limit tracking |
345-
| `connect/sendto/sendmsg` | IP allowlist + on-behalf execution |
375+
| `connect/sendto/sendmsg` | IP allowlist + on-behalf execution + HTTP ACL redirect |
346376
| `bind` | On-behalf bind + port remapping |
347377
| `openat` | /proc virtualization, COW interception |
348378
| `unlinkat/mkdirat/renameat2` | COW write interception |
@@ -469,6 +499,13 @@ Policy(
469499
net_bind=[8080], # TCP bind ports (Landlock ABI v4+)
470500
net_connect=[443], # TCP connect ports
471501

502+
# HTTP ACL (transparent proxy)
503+
http_allow=["POST api.openai.com/v1/*"], # Allow rules (METHOD host/path)
504+
http_deny=["* */admin/*"], # Deny rules (checked first)
505+
http_ports=[80], # Ports to intercept (default: [80])
506+
https_ca="ca.pem", # CA cert for HTTPS MITM (adds port 443)
507+
https_key="ca-key.pem", # CA key for HTTPS MITM
508+
472509
# Socket restrictions
473510
no_raw_sockets=True, # Block SOCK_RAW (default)
474511
no_udp=False, # Block SOCK_DGRAM

python/README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,37 @@ Unset fields mean "no restriction" unless noted otherwise.
6767
| `no_raw_sockets` | `bool` | `True` | Block raw IP sockets |
6868
| `no_udp` | `bool` | `False` | Block UDP sockets |
6969

70+
#### HTTP ACL
71+
72+
Enforce method + host + path rules on HTTP traffic via a transparent
73+
MITM proxy. When `http_allow` is set, all non-matching HTTP requests are
74+
denied by default. Deny rules are checked first and take precedence.
75+
76+
| Parameter | Type | Default | Description |
77+
|-----------|------|---------|-------------|
78+
| `http_allow` | `list[str]` | `[]` | Allow rules in `"METHOD host/path"` format |
79+
| `http_deny` | `list[str]` | `[]` | Deny rules in `"METHOD host/path"` format |
80+
| `http_ports` | `list[int]` | `[80]` | TCP ports to intercept (443 added when `https_ca` is set) |
81+
| `https_ca` | `str \| None` | `None` | CA certificate for HTTPS MITM |
82+
| `https_key` | `str \| None` | `None` | CA private key for HTTPS MITM |
83+
84+
Rule format: `"METHOD host/path"` where method and host can be `*` for
85+
wildcard, and path supports trailing `*` for prefix matching. Paths are
86+
normalized (percent-decoding, `..` resolution, `//` collapsing) before
87+
matching to prevent bypasses.
88+
89+
```python
90+
policy = Policy(
91+
fs_readable=["/usr", "/lib", "/etc"],
92+
http_allow=[
93+
"GET docs.python.org/*",
94+
"POST api.openai.com/v1/chat/completions",
95+
],
96+
http_deny=["* */admin/*"],
97+
)
98+
result = Sandbox(policy).run(["python3", "agent.py"])
99+
```
100+
70101
#### IPC and process isolation
71102

72103
| Parameter | Type | Default | Description |

0 commit comments

Comments
 (0)