diff --git a/home/pass.nix b/home/pass.nix index 859580b..bdd5b62 100644 --- a/home/pass.nix +++ b/home/pass.nix @@ -16,7 +16,8 @@ # GPG agent settings (only for GPG/pass, NOT for SSH) services.gpg-agent = { enable = true; - defaultCacheTtl = 600; - maxCacheTtl = 600; + # Never cache GPG passphrases: pass asks every time. + defaultCacheTtl = 0; + maxCacheTtl = 0; }; } diff --git a/hosts/heather/astrnet.nix b/hosts/heather/astrnet.nix index 1113df1..bc1a805 100644 --- a/hosts/heather/astrnet.nix +++ b/hosts/heather/astrnet.nix @@ -33,6 +33,10 @@ let # to reach their own endpoints through the mesh default). wanTable = "100"; wgMark = "0x4d49"; + # Mark only WAN connections forwarded to published Docker ports. Their + # replies originate from a container, so the `from wanIp4` rule cannot + # select the WAN until after routing/NAT. Restore wgMark on the reply. + dockerInboundMark = "0x4d4a"; wanRules = [ { fam = "-4"; sel = "fwmark ${wgMark}"; } { fam = "-4"; sel = "from ${wanIp4}"; } @@ -93,6 +97,12 @@ in { nft list table inet astrnet_guard >/dev/null 2>&1 && nft delete table inet astrnet_guard nft -f - <<'RULES' table inet astrnet_guard { + chain prerouting { + type filter hook prerouting priority -150; policy accept; + # Reply packets from Docker inherit the connection mark before the + # routing decision; only public-WAN inbound connections get this mark. + iifname "br-*" ct mark ${dockerInboundMark} meta mark set ${wgMark} + } chain input { type filter hook input priority -150; policy accept; # Full inbound access from AstrNet to Heather, IPv4 and IPv6. @@ -102,7 +112,12 @@ in { } chain forward { type filter hook forward priority -150; policy accept; - # Only replies to Docker-initiated connections, never new mesh transit. + # A public connection DNATed by Docker must return via the public WAN, + # not the AstrNet default. This does not affect Docker-originated egress. + iifname "enp7s0" oifname "br-*" ct status dnat ct mark set ${dockerInboundMark} + # Allow mesh peers to reach only Docker-published ports (DNAT), not + # arbitrary forwarded destinations. Host services use the input chain. + iifname { "wg-mic-der", "wg-mic-bd8" } oifname "br-*" ct status dnat accept iifname { "wg-mic-der", "wg-mic-bd8" } ct state established,related accept iifname { "wg-mic-der", "wg-mic-bd8" } drop }