US08-01 — Make the Trust Boundary Configurable and Authenticated #87

Closed
opened 2026-08-17 21:11:34 +02:00 by domverse · 3 comments
Owner

Source specification: delivery_backlog/stories/US08-01-trusted-hosts-auth.md

US08-01 — Make the Trust Boundary Configurable and Authenticated

Epic: E08

As an operator, I want to reach the application through my own hostname without
weakening it, so a container behind a reverse proxy is as safe as the loopback
deployment it replaces.

Context

photo_pipeline/api/security.py refuses any request whose Host or Origin is not
loopback. That check is the current stand-in for authentication: whoever can reach
127.0.0.1:8000 is the owner. Behind a proxy the hostname is no longer loopback, so
relaxing the check without adding an authentication gate would publish the library.

Acceptance criteria

  • Allowed hosts and origins come from configuration (PHOTO_PIPELINE_*), default to
    the current loopback set, and an unset configuration behaves exactly as today.
  • Whenever a non-loopback host is configured, startup requires an access secret and
    refuses to serve without one; loopback-only deployments keep working with no secret.
  • The secret is exchanged for the existing session cookie and CSRF token through the
    bootstrap endpoint; every protected route keeps its current session and CSRF
    requirements unchanged.
  • Forwarded headers (X-Forwarded-Proto, X-Forwarded-Host) are honored only from a
    configured trusted proxy and ignored otherwise, so a client cannot forge its origin.
  • Cookies are marked Secure when the effective external scheme is HTTPS.
  • Failed authentication is rate-limited and logged without the secret, the session id,
    or any request body.
  • Health endpoints stay reachable without the secret; nothing else does.

Automated tests

  • Unit tests for host/origin evaluation across loopback default, configured host,
    unconfigured host, forged forwarded headers, and trusted-proxy forwarded headers.
  • Integration tests: startup refusal without a secret, successful exchange, wrong
    secret, replay of an old session, cross-site request, and unauthenticated access to
    every route class.

Dependencies

  • US07-02
Source specification: [delivery_backlog/stories/US08-01-trusted-hosts-auth.md](https://git.domverse-berlin.eu/domverse/photoanalyzer/src/branch/main/delivery_backlog/stories/US08-01-trusted-hosts-auth.md) # US08-01 — Make the Trust Boundary Configurable and Authenticated Epic: [E08](https://git.domverse-berlin.eu/domverse/photoanalyzer/src/branch/main/delivery_backlog/E08-container-deployment.md) As an operator, I want to reach the application through my own hostname without weakening it, so a container behind a reverse proxy is as safe as the loopback deployment it replaces. ## Context `photo_pipeline/api/security.py` refuses any request whose `Host` or `Origin` is not loopback. That check is the current stand-in for authentication: whoever can reach `127.0.0.1:8000` is the owner. Behind a proxy the hostname is no longer loopback, so relaxing the check without adding an authentication gate would publish the library. ## Acceptance criteria - Allowed hosts and origins come from configuration (`PHOTO_PIPELINE_*`), default to the current loopback set, and an unset configuration behaves exactly as today. - Whenever a non-loopback host is configured, startup requires an access secret and refuses to serve without one; loopback-only deployments keep working with no secret. - The secret is exchanged for the existing session cookie and CSRF token through the bootstrap endpoint; every protected route keeps its current session and CSRF requirements unchanged. - Forwarded headers (`X-Forwarded-Proto`, `X-Forwarded-Host`) are honored only from a configured trusted proxy and ignored otherwise, so a client cannot forge its origin. - Cookies are marked `Secure` when the effective external scheme is HTTPS. - Failed authentication is rate-limited and logged without the secret, the session id, or any request body. - Health endpoints stay reachable without the secret; nothing else does. ## Automated tests - Unit tests for host/origin evaluation across loopback default, configured host, unconfigured host, forged forwarded headers, and trusted-proxy forwarded headers. - Integration tests: startup refusal without a secret, successful exchange, wrong secret, replay of an old session, cross-site request, and unauthenticated access to every route class. ## Dependencies - US07-02
domverse added the area/backendpriority/criticaltype/hardeningstatus/backlog labels 2026-08-17 21:11:34 +02:00
domverse added a new dependency 2026-08-17 21:12:03 +02:00
domverse added a new dependency 2026-08-17 21:12:18 +02:00
domverse added a new dependency 2026-08-17 21:12:20 +02:00
domverse added this to the Photo Analyzer Delivery project 2026-08-17 21:15:07 +02:00
domverse added this to the E08 — Container Deployment milestone 2026-08-17 21:17:41 +02:00
domverse added status/in-progress and removed status/backlog labels 2026-08-18 20:39:14 +02:00
domverse self-assigned this 2026-08-18 20:39:14 +02:00
Author
Owner

Claimed for implementation on branch us/US08-01-make-the-trust-boundary-configurable-and-authent.

Claimed for implementation on branch `us/US08-01-make-the-trust-boundary-configurable-and-authent`.
domverse added status/review and removed status/in-progress labels 2026-08-18 21:59:46 +02:00
Author
Owner

Submitted for review: #96

Tests passed:

  • work_item/scripts/python -m unittest discover -s work_item/tests -v
  • work_item/scripts/python -m pytest tests -q
  • work_item/scripts/python -m pytest tests/unit/test_security_policy.py tests/integration/test_trusted_hosts.py -q
Submitted for review: https://git.domverse-berlin.eu/domverse/photoanalyzer/pulls/96 Tests passed: - `work_item/scripts/python -m unittest discover -s work_item/tests -v` - `work_item/scripts/python -m pytest tests -q` - `work_item/scripts/python -m pytest tests/unit/test_security_policy.py tests/integration/test_trusted_hosts.py -q`
domverse added status/done and removed status/review labels 2026-08-18 22:00:14 +02:00
Author
Owner

Completed and merged via PR #96.

Completed and merged via PR #96.
domverse moved this to Done in Photo Analyzer Delivery on 2026-08-18 23:30:07 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Reference: domverse/photoanalyzer#87