Host firewall allowlist unit (DOCKER-USER, port 8090) #72

Member

Maestro task: 180f2479-7937-425a-a6ed-450c4793cf04 (Feature 07 - Deployment, Identity and Backups).

Done-condition

deploy/systemd/mealquest-firewall.service (plus its script) installs DOCKER-USER iptables rules allowing the MealQuest host port only from 10.60.1.33 (Traefik) and the host itself and dropping all other sources, idempotently on every start, without touching NestQuest's rules. Enabled on 10.60.1.14. Evidence: curl from another LAN host fails, from the Traefik host returns 200, systemctl is-enabled reports enabled, rules survive a reboot or a systemctl restart docker.

What this adds

  • deploy/systemd/mealquest-firewall.sh - idempotent DOCKER-USER rules for the published host port 8090.
  • deploy/systemd/mealquest-firewall.service - oneshot unit, enabled at boot.
  • deploy/systemd/docker.service.d/mealquest-firewall.conf - docker.service drop-in re-applying the rules after a docker restart.

Why conntrack --ctorigdstport 8090

DOCKER-USER runs after Docker DNATs the destination, so by then the port is the container's 8080, not the published 8090. Matching --dport 8090 would never fire. The script matches the ORIGINAL destination port (conntrack --ctorigdstport 8090 --ctdir ORIGINAL), Docker's documented method, so the allow/deny is scoped to MealQuest only and does not disturb NestQuest's 8080/8081 rules.

Evidence (on 10.60.1.14)

  • iptables -S DOCKER-USER shows RETURN for 10.60.1.33/32 and 10.60.1.14/32 on original-port 8090, then DROP for all other sources on 8090; NestQuest's six 8080/8081 rules are unchanged.
  • From 10.60.1.33: http://10.60.1.14:8090/health -> 200. From another LAN host (10.60.1.85): timed out (curl exit 28).
  • systemctl is-enabled mealquest-firewall.service -> enabled; is-active -> active. docker and nestquest-api-firewall.service remain active.
  • Re-running the script twice produced no duplicate rules (diff unchanged).
  • https://mealquest.cubecraftlabs.com/health -> 200.

Not tested

  • A live systemctl restart docker/reboot was NOT run (this host runs other production services); docker-restart survival is covered by the drop-in, not exercised live.
  • Known trade-off: the drop-in ExecStartPost is fatal, so a failing script during a docker start would mark docker.service failed. A non-fatal form (ExecStartPost=-...) is possible if preferred.
Maestro task: 180f2479-7937-425a-a6ed-450c4793cf04 (Feature 07 - Deployment, Identity and Backups). ## Done-condition deploy/systemd/mealquest-firewall.service (plus its script) installs DOCKER-USER iptables rules allowing the MealQuest host port only from 10.60.1.33 (Traefik) and the host itself and dropping all other sources, idempotently on every start, without touching NestQuest's rules. Enabled on 10.60.1.14. Evidence: curl from another LAN host fails, from the Traefik host returns 200, systemctl is-enabled reports enabled, rules survive a reboot or a systemctl restart docker. ## What this adds - deploy/systemd/mealquest-firewall.sh - idempotent DOCKER-USER rules for the published host port 8090. - deploy/systemd/mealquest-firewall.service - oneshot unit, enabled at boot. - deploy/systemd/docker.service.d/mealquest-firewall.conf - docker.service drop-in re-applying the rules after a docker restart. ## Why conntrack --ctorigdstport 8090 DOCKER-USER runs after Docker DNATs the destination, so by then the port is the container's 8080, not the published 8090. Matching --dport 8090 would never fire. The script matches the ORIGINAL destination port (conntrack --ctorigdstport 8090 --ctdir ORIGINAL), Docker's documented method, so the allow/deny is scoped to MealQuest only and does not disturb NestQuest's 8080/8081 rules. ## Evidence (on 10.60.1.14) - iptables -S DOCKER-USER shows RETURN for 10.60.1.33/32 and 10.60.1.14/32 on original-port 8090, then DROP for all other sources on 8090; NestQuest's six 8080/8081 rules are unchanged. - From 10.60.1.33: http://10.60.1.14:8090/health -> 200. From another LAN host (10.60.1.85): timed out (curl exit 28). - systemctl is-enabled mealquest-firewall.service -> enabled; is-active -> active. docker and nestquest-api-firewall.service remain active. - Re-running the script twice produced no duplicate rules (diff unchanged). - https://mealquest.cubecraftlabs.com/health -> 200. ## Not tested - A live `systemctl restart docker`/reboot was NOT run (this host runs other production services); docker-restart survival is covered by the drop-in, not exercised live. - Known trade-off: the drop-in ExecStartPost is fatal, so a failing script during a docker start would mark docker.service failed. A non-fatal form (ExecStartPost=-...) is possible if preferred.
dev_agent added 1 commit 2026-10-05 17:38:48 -04:00
Add MealQuest host firewall unit for port 8090
CI / ci (pull_request) Successful in 1m33s
CI / ci (push) Successful in 1m33s
63808ccd20
Restrict the published MealQuest port 8090 in DOCKER-USER to Traefik
(10.60.1.33) and the Docker host (10.60.1.14), dropping all other
sources. DOCKER-USER sees post-DNAT traffic, so rules match the original
destination port with conntrack rather than --dport. A docker.service
drop-in re-applies the rules after every docker restart.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
review_agent requested changes 2026-10-05 17:41:31 -04:00
Dismissed
review_agent left a comment
Member

Independent Codex gpt-6-sol review: CHANGES_REQUIRED for this exact commit.

Independent Codex gpt-6-sol review: CHANGES_REQUIRED for this exact commit.
overseer added 1 commit 2026-10-05 17:50:32 -04:00
Keep MealQuest firewall rules first and off docker.service
CI / ci (push) Successful in 1m33s
CI / ci (pull_request) Successful in 1m33s
5a1ee389dc
Address review of the port 8090 firewall:

- Insert the three MealQuest rules at the top of DOCKER-USER, ahead of
  other projects' rules. Each run deletes every rule tagged
  "mealquest-firewall" and re-inserts them at positions 1-3, so re-runs
  restore the order and never duplicate.
- Scope the match to MealQuest's published address with
  --ctorigdst 10.60.1.14, so outbound container connections to a remote
  :8090 are not matched.
- Drop the docker.service ExecStartPost drop-in, which made a firewall
  error fatal to the shared Docker daemon. The unit is now PartOf= and
  WantedBy= docker.service: it re-runs on every Docker start or restart
  and fails visibly on its own without failing docker.service.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
review_agent left a comment
Member

Independent Codex gpt-6-sol review: APPROVED for this exact commit.

Independent Codex gpt-6-sol review: APPROVED for this exact commit.
approver_agent merged commit 9d0e943fc3 into feature/ec45cc08-b16d-4b8f-b617-7e79308a4f49-deployment 2026-10-05 17:56:12 -04:00
Sign in to join this conversation.
No Reviewers
No labels
3 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Maniacs_Mansion/MealQuest#72