diff --git a/ROADMAP.md b/ROADMAP.md index 6200c0f..e001393 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -240,11 +240,18 @@ records the same name for everyone. The meeting asked for traceability, and the `kanban/main.py` explicitly designed separation of duties (Mayana classifies, Thales/Alexandre authorise). Needs real per-person accounts with roles. -### `[ ]` 2.9 — No TLS in the stack `(F13)` +### `[~]` 2.9 — TLS is terminated outside the repository `(F13)` -Ports publish plain HTTP on 18080/18081 while `COOKIE_SECURE: "true"` — cookies are -silently dropped unless something external terminates TLS. Nothing in the repo -provisions certificates; `TAREFAS.md` A2 still lists it as pending. +Downgraded 2026-09-21. The stack publishes plain HTTP on 18080/18081 while +`COOKIE_SECURE: "true"`, and nothing in the repo provisions certificates — but +`nginx-proxy-manager` on the host owns 80/443 and terminates TLS in front of it, +so cookies are not being dropped in practice. This is undocumented operational +knowledge rather than a live defect. + +What remains: record the proxy in `PORTAINER.md` as part of the deployment +contract, so nobody moves the stack to a host without one and silently breaks +every session cookie. `TAREFAS.md` A2 still lists the certificate as pending; +confirm it is actually issued for the DTF subdomain. ### `[ ]` 2.10 — No email verification, no password recovery `(F14)` @@ -463,6 +470,17 @@ charges. Fix as part of 1.1. nginx 1.31.6. With both images at zero CRITICAL, the image scan now **gates on CRITICAL** and reports HIGH. +### 2026-09-21 — from the runner host inventory + +- `[x]` Fixed a regression in 2.1: the production gateway sits behind + `nginx-proxy-manager`, so `$remote_addr` there is the proxy, not the customer. + Overwriting `X-Forwarded-For` with it would have recorded the proxy's address for + every request in production — the same bug 2.1 set out to fix. The gateway now + uses `real_ip` to recover the customer's address from the proxy's header, trusting + only private networks, so a request arriving directly at the published port + cannot spoof it. Validated with `nginx -t` against the rendered config. +- `[~]` 2.9 downgraded: TLS is terminated by that proxy, not missing. + ### Reporting - `[x]` Week-1 client report (`Relatorio-Semana-1-DTF.docx`), corrected 2026-09-18 to diff --git a/deploy/nginx.conf.template b/deploy/nginx.conf.template index 0611a76..3a53bb3 100644 --- a/deploy/nginx.conf.template +++ b/deploy/nginx.conf.template @@ -8,6 +8,17 @@ server { # unavailable or still creating its database schema. resolver 127.0.0.11 ipv6=off valid=10s; set $api_upstream api:8000; + + # This gateway sits behind the host's reverse proxy, so $remote_addr is that + # proxy, not the customer. Recover the real address from the header it sets, + # and only when the connection comes from a private network: a request that + # reaches the published port directly from the internet is not trusted, so + # its X-Forwarded-For is ignored and $remote_addr stays the actual peer. + set_real_ip_from 10.0.0.0/8; + set_real_ip_from 172.16.0.0/12; + set_real_ip_from 192.168.0.0/16; + real_ip_header X-Forwarded-For; + real_ip_recursive on; root /usr/share/nginx/html; index ${WEB_INDEX}; @@ -29,6 +40,7 @@ server { proxy_set_header X-Forwarded-Proto https; # Overwrite, never append: $proxy_add_x_forwarded_for keeps any header the # client sent, and the leftmost value would then be attacker-controlled. + # After real_ip above, $remote_addr is the customer even behind the proxy. proxy_set_header X-Forwarded-For $remote_addr; proxy_connect_timeout 5s; proxy_read_timeout 30s;