diff --git a/.agent/decisions/index.json b/.agent/decisions/index.json index 42f61c9..dd76e86 100644 --- a/.agent/decisions/index.json +++ b/.agent/decisions/index.json @@ -27,15 +27,16 @@ { "id": "T3-A", "title": "nftables fix для otreca (R1.6: явная policy drop, убрать firewall/nftables конфликт, SSH только на tailscale0)", - "status": "accepted", - "date": "2026-10-10", + "status": "proposed", + "date": "2026-10-09", "files": [ - ".agent/decisions/proposals/vds-nftables-fix.md", - "configurations/vds.nix" + ".agent/decisions/proposals/vds-nftables-fix.md" ], "tags": ["nftables", "vds", "otrecа", "security", "R1.6", "T3"], "task": "T3", - "notes": "Applied 2026-10-10 via nixos-rebuild switch on otreca. Verified live: nft list ruleset = policy drop + 5 accepts, iptables empty, SSH via Tailscale works, Xray REALITY on 443 listening." + "blocked_by": [ + "user: SSH-доступ на otreca должен быть восстановлен до apply" + ] } ] } diff --git a/.agent/tasks/manifest.json b/.agent/tasks/manifest.json index b33f091..e1ec791 100644 --- a/.agent/tasks/manifest.json +++ b/.agent/tasks/manifest.json @@ -50,7 +50,7 @@ "id": "T3", "title": "A3: явная финальная политика nftables на VDS", "type": "fix", - "status": "completed", + "status": "pending", "origin": "user:direct", "depends_on": [], "acceptance_criteria": [ @@ -60,7 +60,7 @@ ], "files": ["configurations/vds.nix"], "blocks": ["T11", "T12"], - "notes": "Applied 2026-10-10. 3 коммита: 5796786 (initial fix) + 3deaa75 (fix allowPing) + 4dc4849 (CORRECTION: removed iifname \"tailscale0\" restriction on SSH — owner said 'не помню, чтобы просил ограничивать 22 порт'. SSH now on all interfaces). Final ruleset: policy drop + 6 accepts (lo, established/related, ICMP, traceroute 33434-33534, SSH 22 on all interfaces, Xray REALITY 443) + log+drop. firewall.enable = false (R1.6 conflict resolved). lib.mkForce on allowedTCPPorts/interfaces prevents shadow rules. Verified live 2026-10-10: nft list shows policy drop + all 6 accepts, public SSH (109.248.161.5:22) works, Tailscale SSH (100.64.1.0:22) works, Xray 443 listening." + "notes": "REVERTED 2026-10-10: owner requested revert of all T3 firewall changes. 'по прежнему ничего не работает, сайт не открывается, reality не работает. это требует обсуждения.' Original vds.nix restored (commit 61b3724 baseline). 5 T3 commits reverted: 5796786, 3deaa75, 4dc4849, 2649e2f, 51ea19a + docs 677d39e, fafd3e2. Requires discussion before re-applying." }, { "id": "T4", diff --git a/configurations/vds.nix b/configurations/vds.nix index 06abf45..dd0a2a8 100644 --- a/configurations/vds.nix +++ b/configurations/vds.nix @@ -2,23 +2,6 @@ # # The host record lives in configurations/default.nix; this file is only the # module body. `xlib` (identity, dirs, helpers) arrives as a module argument. -# -# T3 FIX (minimal, R1.6 only) 2026-10-10: -# - Explicit `policy drop` on chain input (R1.6 fix — original ruleset -# had no policy, so it was implicit accept) -# - Removed `firewall.enable = true` to eliminate the -# `firewall.*` + `nftables.*` conflict (R1.6) -# - SSH (22) open on ALL interfaces (no iifname restriction) -# - Xray REALITY (443) open -# - ICMP + traceroute (33434-33534) for diagnostics -# - 80/HTTP closed by default -# - Log + drop at the end (nft-drop: prefix) for diagnostics -# -# CORRECTED 2026-10-10: removed `iifname "tailscale0"` restriction on -# SSH — owner did not ask for that. SSH is open on ens3 too. -# -# On otreca: management via Tailscale OR public SSH. Public attack -# surface is SSH (22) + Xray REALITY (443). { lib, modulesPath, @@ -59,21 +42,17 @@ }; host.ssh.enable = true; - # SSH is reachable on all interfaces (public + Tailscale). The - # nftables ruleset below opens 22 explicitly. `openFirewall = false` - # because we manage the firewall via nftables, not the NixOS - # firewall module (see `firewall.enable = false` further down). + # SSH is reachable only over Tailscale (not on the public internet). + # This otreca VDS is reached by deploy-rs and by oqyude over the + # tailnet, so exposing 22 to ens3 is pure attack surface. services.openssh.openFirewall = false; services.tailscale = { enable = true; openFirewall = true; }; - # REMOVED 2026-10-10: networking.firewall.interfaces.tailscale0.allowedTCPPorts = [ 22 ]. - # SSH is now opened on ALL interfaces via the nftables ruleset below - # (`tcp dport 22 accept` — no iifname restriction). - # Owner corrected: "не помню, чтобы просил ограничивать 22 порт". - + # Open port 22 only on the tailscale interface. + networking.firewall.interfaces.tailscale0.allowedTCPPorts = [ 22 ]; networking = { nameservers = [ "1.1.1.1" @@ -85,24 +64,16 @@ enable = true; IPv6rs = false; }; - # T3 (R1.6 fix): `firewall.enable = false` eliminates the - # `firewall.*` + `nftables.*` conflict. The `lib.mkForce` on - # `allowedTCPPorts` and `interfaces` prevents the NixOS firewall - # module from silently injecting rules that would shadow our - # nftables ruleset. All filtering is now done by the ruleset below. - firewall.enable = false; - firewall.allowedTCPPorts = lib.mkForce [ ]; - firewall.interfaces = lib.mkForce { }; - # `networking.allowPing` was removed because with firewall.enable = false - # it no longer exists as a top-level option. ICMP accept is handled - # by the nftables ruleset below (`ip protocol icmp accept`). + firewall = { + enable = true; + allowPing = true; + }; nftables = { enable = true; ruleset = '' table inet filter { chain input { type filter hook input priority 0; - policy drop; # loopback iif lo accept @@ -110,33 +81,11 @@ # уже установленные ct state established,related accept - # ICMP (path MTU discovery + diagnostics) - ip protocol icmp accept + # РЕЖЕМ SYN СРАЗУ + tcp flags syn tcp dport {80,443} limit rate 20/second burst 40 packets accept + tcp flags syn tcp dport {80,443} drop - # traceroute - udp dport 33434-33534 accept - - # SSH (22) — open on all interfaces (owner: no iifname restriction) - tcp dport 22 accept - - # HTTP (80) — needed for ACME HTTP-01 challenge (LE cert renewal) - # and for HTTP → HTTPS redirect if nginx vhost is configured. - # ADDED 2026-10-10: previous T3 fix accidentally dropped port 80, - # breaking pubray1.zeroq.su cert renewal. - tcp dport 80 accept - - # Xray REALITY inbound (treca acts as relay from sapphira via XHTTP) - tcp dport 443 accept - - # 3x-ui Xray REALITY inbound on container (0.0.0.0:8443:8443 in - # modules/containers/3x-ui.nix). Direct public mapping — NOT - # proxied through nginx (that was `reality443Forwarding`, - # погашен в T10). ADDED 2026-10-10: previous T3 fix missed - # this port, Xray was unreachable from outside. - tcp dport 8443 accept - - # log for diagnostics (journalctl -k | grep nft-drop) - log prefix "nft-drop: " flags all counter drop + # остальное по необходимости } } '';