fix(firewall): RETURN last, Cloudflare-only 80/443 rule off (issue #233) #235

Merged
jfraeys merged 1 commit from jfraeys/fix/firewall-return-last-and-web-open into main 2026-10-16 16:31:28 -04:00
Owner

Recommended option E from #233.

  1. docker-user-firewall.sh.j2: removes every existing RETURN and re-adds one at the end, then exits non-zero if RETURN is not the last rule (IPv4 and IPv6). A chain with no RETURN returns to its caller at the end, so this changes nothing for traffic; it only stops later -A appends from landing behind Docker's RETURN. A failure fails docker-user-firewall.service and therefore the Ansible deploy.
  2. inventory/group_vars/all.yml: firewall_restrict_web_to_cloudflare: false for all hosts. A DOCKER-USER rule cannot match hostnames and git/vpn are DNS-only, so a working rule would cut off public git; on the old production node the rule was dead anyway. The script's existing else-branch removes the Cloudflare ACCEPTs and the 80/443 DROP where they exist. After the planned move to deSEC (no proxy) the role derives false from the cert resolver too.
  3. test-docker-user-firewall.sh: fake iptables gains -S; new cases start from Docker's RETURN first and from the old node's state (RETURN in the middle, dead Cloudflare rules behind it). Against the previous script 4 of the new checks fail; with the change all pass.
  4. FUTURE_IMPROVEMENTS.md: Authenticated Origin Pulls recorded for a possible return to Cloudflare proxying.

Effect when deployed: on the old node the dead 80/443 rules disappear and RETURN moves last; no reachability change (direct 443 already answers). The 22/25/17170 tailnet-only DROPs are untouched. On the new OVH node, direct 443 becomes open (it was blocked), which is what lets git work after cutover.

Not covered: real iptables behaviour (the simulation matches parsed options), and the molecule test (not run locally).

roles/ and inventory/ are staged paths: staging, promotion, ./infra deploy --tags firewall --limit services; for the OVH rehearsal node run the same tag with -i inventory/ovh_generated.yml --limit ovh-services.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Ge5tovcwdEUBtPwUktsZZZ

Recommended option E from #233. 1. docker-user-firewall.sh.j2: removes every existing RETURN and re-adds one at the end, then exits non-zero if RETURN is not the last rule (IPv4 and IPv6). A chain with no RETURN returns to its caller at the end, so this changes nothing for traffic; it only stops later -A appends from landing behind Docker's RETURN. A failure fails docker-user-firewall.service and therefore the Ansible deploy. 2. inventory/group_vars/all.yml: firewall_restrict_web_to_cloudflare: false for all hosts. A DOCKER-USER rule cannot match hostnames and git/vpn are DNS-only, so a working rule would cut off public git; on the old production node the rule was dead anyway. The script's existing else-branch removes the Cloudflare ACCEPTs and the 80/443 DROP where they exist. After the planned move to deSEC (no proxy) the role derives false from the cert resolver too. 3. test-docker-user-firewall.sh: fake iptables gains -S; new cases start from Docker's RETURN first and from the old node's state (RETURN in the middle, dead Cloudflare rules behind it). Against the previous script 4 of the new checks fail; with the change all pass. 4. FUTURE_IMPROVEMENTS.md: Authenticated Origin Pulls recorded for a possible return to Cloudflare proxying. Effect when deployed: on the old node the dead 80/443 rules disappear and RETURN moves last; no reachability change (direct 443 already answers). The 22/25/17170 tailnet-only DROPs are untouched. On the new OVH node, direct 443 becomes open (it was blocked), which is what lets git work after cutover. Not covered: real iptables behaviour (the simulation matches parsed options), and the molecule test (not run locally). roles/ and inventory/ are staged paths: staging, promotion, ./infra deploy --tags firewall --limit services; for the OVH rehearsal node run the same tag with -i inventory/ovh_generated.yml --limit ovh-services. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01Ge5tovcwdEUBtPwUktsZZZ
fix(firewall): RETURN last (fail loudly otherwise); Cloudflare-only 80/443 rule off for all hosts
All checks were successful
Lint / lint (pull_request) Successful in 2m43s
Secret scan / scan (pull_request) Successful in 16s
1549823345
The 80/443 DROP was behind Docker's RETURN on the old production node (never evaluated) and would cut off public git (DNS-only)
if it worked. The script now removes existing RETURNs and re-adds one last, then fails if it is not last. The rule is off in
group_vars (the role derives it from the cert resolver; the deSEC move makes it false anyway). The test seeds Docker's RETURN
first and the old node's state (RETURN in the middle, dead Cloudflare rules behind it); 4 of the new checks fail on the old
script. Authenticated Origin Pulls recorded in FUTURE_IMPROVEMENTS for a possible return to Cloudflare.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ge5tovcwdEUBtPwUktsZZZ
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jfraeys/infra!235
No description provided.