-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathkvm-jailbox.conf
More file actions
71 lines (62 loc) · 3.62 KB
/
Copy pathkvm-jailbox.conf
File metadata and controls
71 lines (62 loc) · 3.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#!/usr/sbin/nft -f
# Sandbox containment rules
#
# Modular by design: rules are self-contained in their own tables, every chain
# uses `policy accept` and every rule matches only sandbox traffic (identified
# by the bridge interface). Therefore, loading this file does not change how the
# host treats any other traffic.
# Remove our tables only (declare first so the delete never fails)
table inet kvm_jailbox
table ip kvm_jailbox
table bridge kvm_jailbox
delete table inet kvm_jailbox
delete table ip kvm_jailbox
delete table bridge kvm_jailbox
define BRIDGE_DEV = "br-kvm-jailbox"
define BRIDGE_NET = 10.248.0.0/24
# RFC1918, loopback, link-local, and CGNAT (Tailscale); add any other overlay/VPN range you run
define PRIVATE_NET = { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8, 169.254.0.0/16, 100.64.0.0/10 }
table inet kvm_jailbox {
# Private services a specific VM is allowed to reach, as source VM . destination IP . protocol . port.
set private_allow {
type ipv4_addr . ipv4_addr . inet_proto . inet_service
flags interval
# elements = {
# 10.248.0.5 . 10.248.0.254 . tcp . 5432, # jailbox5 → PostgreSQL on the host
# 10.248.0.5 . 10.248.0.254 . udp . 53, # jailbox5 → DNS resolver on the host
# 10.248.0.5 . 192.168.1.50 . tcp . 8000-8090, # jailbox5 → a range of TCP ports on one host
# 10.248.0.5 . 192.168.1.20-192.168.1.30 . udp . 9000, # jailbox5 → a UDP service across an IP range
# 10.248.0.5 . 192.168.2.0/24 . tcp . 6379, # jailbox5 → Redis across a whole subnet
# }
}
chain input {
type filter hook input priority filter; policy accept; # Non-sandbox traffic falls through untouched
iifname $BRIDGE_DEV meta nfproto ipv6 drop # Bridge is IPv4-only
iifname $BRIDGE_DEV ip saddr != $BRIDGE_NET drop # Anti-spoofing: drop bridge packets not sourced from a sandbox address
iifname $BRIDGE_DEV ct state vmap { established: accept, related: accept, invalid: drop } # Replies to host-initiated connections
iifname $BRIDGE_DEV ip saddr . ip daddr . meta l4proto . th dport @private_allow accept # Allowlisted private services on the host
iifname $BRIDGE_DEV drop # Bridge cannot otherwise reach the host
}
chain forward {
type filter hook forward priority filter; policy accept; # Non-sandbox traffic falls through untouched
iifname $BRIDGE_DEV meta nfproto ipv6 drop # Bridge is IPv4-only
iifname $BRIDGE_DEV ip saddr != $BRIDGE_NET drop # Anti-spoofing: drop bridge packets not sourced from a sandbox address
iifname $BRIDGE_DEV ct state vmap { established: accept, related: accept, invalid: drop } # Replies to inbound connections
iifname $BRIDGE_DEV ip saddr . ip daddr . meta l4proto . th dport @private_allow accept # Allowlisted private services elsewhere
iifname $BRIDGE_DEV ip daddr $PRIVATE_NET drop # Bridge cannot access private networks
iifname $BRIDGE_DEV ip ttl set 64 # Reset TTL to hide upstream hops from traceroute
iifname $BRIDGE_DEV accept # Bridge is allowed internet access
}
}
table ip kvm_jailbox {
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
iifname $BRIDGE_DEV oifname != $BRIDGE_DEV masquerade # NAT sandbox traffic
}
}
table bridge kvm_jailbox {
chain forward {
type filter hook forward priority filter; policy accept; # Other bridges (e.g. virbr0, docker0) are untouched
meta ibrname $BRIDGE_DEV drop # Isolate sandboxes from each other
}
}