feat(firecracker): route agent VMs to the gateway VM (Stage B, 3/n)
Agent VMs must reach the shared gateway that now runs in the infra VM (egress:9099 / supervise:9100 / git-http:9420 at the orchestrator link's guest IP). Add a PREROUTING DNAT: agents keep addressing their own host-side TAP IP on the gateway ports, and the rule redirects that to the infra VM. The isolation table's existing `ct status dnat accept` forward rule lets the DNAT'd traffic through; every other agent egress stays dropped, so a bottle still reaches only the gateway and nothing else. Source IP is deliberately NOT masqueraded: the gateway attributes each request to the originating bottle by its guest IP, which the /31 TAP + the bot_bottle_fc nft table make unspoofable. Keeping the agent addressed at its own host TAP IP means no per-bottle config change vs the docker-DNAT path it replaces. - scripts/firecracker-netpool.sh: `_install_gateway_route` adds `table ip <table>_gw` (prerouting dstnat -> orch_guest on the gateway ports); wired into up/down/status. The nix module needs no change — it runs this script, and the ports are baked in. Verified on a KVM host: an agent VM's `curl -x http://<its-host-tap>:9099` reaches mitmproxy in the infra VM and gets a 403 (correct policy denial for an unregistered bottle) — i.e. the route lands end-to-end. Persist with a nixos-rebuild; the imperative rule holds until then. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WBMWTEtQdJ4W5UrWuLHCck
This commit is contained in:
@@ -146,6 +146,8 @@ cmd_up() {
|
||||
echo "nftables table inet $TABLE installed (fail-closed boundary)"
|
||||
_install_orch_egress
|
||||
echo "orchestrator egress installed ($ORCH_IFACE -> NAT out)"
|
||||
_install_gateway_route
|
||||
echo "agent->gateway route installed (${PREFIX}* :$GATEWAY_PORTS -> $(orch_guest))"
|
||||
echo "done."
|
||||
}
|
||||
|
||||
@@ -228,9 +230,29 @@ _docker_user_orch() {
|
||||
done
|
||||
}
|
||||
|
||||
# Agent -> gateway VM routing. The shared gateway (egress / supervise /
|
||||
# git-http) runs in the orchestrator/infra VM at $(orch_guest). Agents keep
|
||||
# addressing their own host-side TAP IP on the gateway ports; a PREROUTING
|
||||
# DNAT redirects that to the infra VM, and the isolation table's
|
||||
# `ct status dnat accept` forward rule lets it through — every other agent
|
||||
# egress stays dropped. Source IP is deliberately NOT masqueraded: the
|
||||
# gateway attributes each request to the originating bottle by its (nft +
|
||||
# /31 unspoofable) guest IP.
|
||||
_install_gateway_route() {
|
||||
nft -f - <<EOF
|
||||
table ip ${TABLE}_gw {
|
||||
chain prerouting {
|
||||
type nat hook prerouting priority -100; policy accept;
|
||||
iifname "${PREFIX}*" tcp dport { $GATEWAY_PORTS } dnat to $(orch_guest)
|
||||
}
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
cmd_down() {
|
||||
require_root down
|
||||
_docker_user_orch del
|
||||
nft delete table ip "${TABLE}_gw" 2>/dev/null || true
|
||||
nft delete table inet "${TABLE}_nat" 2>/dev/null || true
|
||||
if ip link show "$ORCH_IFACE" >/dev/null 2>&1; then
|
||||
ip link set "$ORCH_IFACE" down 2>/dev/null || true
|
||||
@@ -254,6 +276,8 @@ cmd_status() {
|
||||
nft list table inet "$TABLE" 2>/dev/null || echo " (absent)"
|
||||
echo "table inet ${TABLE}_nat (orchestrator egress):"
|
||||
nft list table inet "${TABLE}_nat" 2>/dev/null || echo " (absent)"
|
||||
echo "table ip ${TABLE}_gw (agent->gateway route):"
|
||||
nft list table ip "${TABLE}_gw" 2>/dev/null || echo " (absent)"
|
||||
echo "taps:"
|
||||
for i in $(seq 0 $((POOL_SIZE-1))); do
|
||||
local dev ; dev="$(iface "$i")"
|
||||
|
||||
Reference in New Issue
Block a user