Feature 17 review remediation: commit firewall unit, pin image and deps

F17-001: commit the API box's nestquest-api-firewall.service verbatim
as deploy/systemd/nestquest-api-firewall.service (DOCKER-USER RETURN
for 10.60.1.33 and 10.60.1.14, then DROP tcp/8080) and make the
runbook install it from the repository before exposing the API.

F17-002: pin the python:3.12-slim base image by digest in both build
stages, pin api/requirements.txt to the exact versions installed in
the deployed image (direct deps plus transitive closure), and pin the
litestream image by digest in deploy/compose.yaml.

Task: e4a7b18b-5dad-4387-90ac-33588c280824

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-24 09:44:12 -04:00
co-authored by Claude Opus 5.5
parent 71a9ae8dd1
commit 21a8365c6a
5 changed files with 64 additions and 15 deletions
+16 -6
View File
@@ -266,8 +266,16 @@ committed `deploy/litestream.yml` (`host-key`, the NAS's ECDSA key), so no
-A DOCKER-USER -p tcp --dport 8080 -j DROP # every other source
The rules are persisted by the systemd oneshot unit
**`nestquest-api-firewall.service`** on the API box (enabled; ordered
after `docker.service`, it applies the three rules at every boot).
**`nestquest-api-firewall.service`**, committed as
`deploy/systemd/nestquest-api-firewall.service` (ordered after
`docker.service`, it idempotently applies the three rules at every
boot). Install and enable it on the API box, from the repository
checkout, **before** exposing the API:
sudo cp deploy/systemd/nestquest-api-firewall.service /etc/systemd/system/ \
&& sudo systemctl daemon-reload \
&& sudo systemctl enable --now nestquest-api-firewall.service
The HA box and every other client must use the Traefik hostname,
never `:8080` directly. Check it:
@@ -282,10 +290,12 @@ committed `deploy/litestream.yml` (`host-key`, the NAS's ECDSA key), so no
# public path still works:
curl -s -o /dev/null -w '%{http_code}\n' https://nestquest.cubecraftlabs.com/health # 200
On a rebuilt API box, recreate and enable the unit before exposing the
API (`sudo systemctl enable --now nestquest-api-firewall.service`); the
deployed unit is the authoritative copy
(`systemctl cat nestquest-api-firewall.service`).
On a rebuilt API box, install the unit with the commands above before
exposing the API. The committed file is the authoritative copy; the
deployed unit must match it:
diff deploy/systemd/nestquest-api-firewall.service \
/etc/systemd/system/nestquest-api-firewall.service # no output
## 7. Backup (Litestream to the Synology NAS)
+1 -1
View File
@@ -56,7 +56,7 @@ services:
# (uid/gid 999, owner of the volume) with a read-only root filesystem,
# no privilege escalation and no Linux capabilities.
litestream:
image: litestream/litestream:0.5.17
image: litestream/litestream:0.5.17@sha256:4b02b9859a6b6b4087d8b8944e15f7e984bd7957cba322bbeee38b0e27b9656a
restart: unless-stopped
command: ["replicate", "-config", "/etc/litestream.yml"]
user: "999:999"
@@ -0,0 +1,12 @@
[Unit]
Description=Restrict NestQuest API port 8080 to Traefik (DOCKER-USER)
After=docker.service
Requires=docker.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/sh -c "iptables -C DOCKER-USER -s 10.60.1.33/32 -p tcp --dport 8080 -j RETURN 2>/dev/null || iptables -I DOCKER-USER 1 -s 10.60.1.33 -p tcp --dport 8080 -j RETURN; iptables -C DOCKER-USER -s 10.60.1.14/32 -p tcp --dport 8080 -j RETURN 2>/dev/null || iptables -I DOCKER-USER 2 -s 10.60.1.14 -p tcp --dport 8080 -j RETURN; iptables -C DOCKER-USER -p tcp --dport 8080 -j DROP 2>/dev/null || iptables -A DOCKER-USER -p tcp --dport 8080 -j DROP"
[Install]
WantedBy=multi-user.target