C6 Web UI security & binding policy
- Area
- C — Trust & correctness
- Audience
- operator
- Kind
- feature
- Status
- accepted
- Maturity
- building
- Labels
- security, web
The feature in the specification · Read at
Requirements
Admin services MUST bind to loopback by default.
- locked by
- 0.9.0 met
- recorded done
- lemonfibercrates/lemonfiber/tests/integration/publishing.rs
- recorded partial
- lemonfiber-media-stackstack.tomlscripts/manifest_rules.py::bind must be one of
- cited by
- lemonfiber@ebab0d89be
Household-facing services MUST bind to the LAN by default.
No admin service MAY bind to all interfaces by default.
- locked by
- 0.9.0 met
- recorded done
- lemonfibercrates/lemonfiber/tests/integration/publishing.rs
- cited by
- lemonfiber@ebab0d89be
LAN binding of lemonfiber's UI MUST be refused unless authentication is configured.
- locked by
- 0.10.0 met
- recorded done
- lemonfibercrates/lemonfiber-core/src/admission.rscrates/lemonfiber/tests/architecture/where_the_outside_world_is_reached.rscrates/lemonfiber/src/ui/password.rscrates/lemonfiber/src/ui/reach.rscrates/lemonfiber/src/ui.rscrates/lemonfiber-api/src/admission/sessions.rs
- cited by
- lemonfiber@a8028cccbb
Removing authentication while LAN-bound MUST immediately revert to loopback.
- locked by
- 0.10.0 met
- recorded done
- lemonfibercrates/lemonfiber/src/ui/reach.rs
- cited by
- lemonfiber@3dbd0d3966lemonfiber@8088b55d4a
lemonfiber MUST state plainly when it is serving unencrypted HTTP.
Self-signed TLS MUST NOT be enabled by default.
Stored authentication credentials MUST use a modern password-hashing function and MUST NOT be recoverable.
- locked by
- 0.10.0 met
- recorded done
- lemonfibercrates/lemonfiber-core/src/admission.rscrates/lemonfiber/tests/architecture/where_the_outside_world_is_reached.rscrates/lemonfiber/src/ui/password.rscrates/lemonfiber/src/ui/reach.rscrates/lemonfiber/src/ui.rscrates/lemonfiber-api/src/admission/sessions.rs
- cited by
- lemonfiber@4eea2ac994lemonfiber@a8028cccbb
Sessions MUST expire, and MUST be invalidated on credential change.
State-changing requests MUST be protected against cross-site request forgery.
Failed authentication attempts MUST be rate-limited.
- locked by
- 0.10.0 met
- recorded done
- lemonfibercrates/lemonfiber-api/src/admission/attempts.rscrates/lemonfiber/src/ui/answering.rsspec:10-functional/features/d-content/d6-household-identity.mdcrates/lemonfiber/src/render/invitation.rscrates/lemonfiber-core/src/invitation.rs
- cited by
- lemonfiber@951e9ec617lemonfiber@aba9f8a468lemonfiber@3dbd0d3966lemonfiber@3c595bb599lemonfiber-web@328cf29f61
lemonfiber's UI MUST NOT proxy or tunnel to admin service interfaces.
- locked by
- 0.9.0 met
- recorded done
- lemonfibercrates/lemonfiber-api/tests/integration/nothing_is_carried_through.rs
- cited by
- lemonfiber@6276921665
Actual listening bindings MUST be verified against policy by a diagnostic check.
- locked by
- 0.10.0 met
- recorded done
- lemonfibercrates/lemonfiber-core/src/doctor/bindings.rscrates/lemonfiber-ports/src/docker.rscrates/lemonfiber/tests/architecture/where_it_listens.rscrates/lemonfiber/src/ui/reach.rscrates/lemonfiber/src/ui.rscrates/lemonfiber-api/src/admission/sessions.rs
- cited by
- lemonfiber@a8028cccbb
Binding policy MUST apply equally to IPv4 and IPv6.
- locked by
- 0.10.0 uncited
- recorded done
- lemonfibercrates/lemonfiber/tests/architecture/where_it_listens.rs
Deliberate exposure of an admin service MUST require explicit acknowledgement and MUST be recorded.
Where Docker port publishing bypasses the host firewall, lemonfiber MUST warn.
- locked by
- 0.10.0 met
- recorded done
- lemonfibercrates/lemonfiber-core/src/doctor/bindings.rs
- cited by
- lemonfiber@f423064a03lemonfiber@aa93ced828
The interface household services publish on MUST be operator-configurable through a single documented setting, and where it defaults to all interfaces that MUST be stated plainly alongside its consequences.
- locked by
- 0.10.0 met
- recorded done
- lemonfibercrates/lemonfiber/tests/integration/publishing.rs
- recorded partial
- lemonfiber-media-stack.env.example::LAN_BIND
- cited by
- lemonfiber@d852edd086lemonfiber-media-stack@e019b4e3e4
A service an installed plugin adds MUST be bound by the tier lemonfiber assigns from the classification the plugin declared, and a plugin MUST NOT be able to declare an address, an interface or a published port mapping.
Replacing a certificate a companion may have pinned MUST be announced before it is replaced, naming re-pairing as the consequence; where renewal is performed by something lemonfiber does not control, that MUST be stated when the pairing material is produced rather than discovered at the next renewal (ADR-0025).
A household-tier service MAY hold a credential that is administrative on another service only where one operation must be answerable at household reach at any hour. It MUST then hold that credential alone, MUST perform only that operation through a fixed set of calls, and MUST be confined: no data mount, a read-only root, no kernel capabilities, and no network reach beyond the service it acts on and the port it publishes. No other household-tier service MAY hold such a credential or an administrator's session on another service, and one that acts on another service's API MUST do so only through the request gate (ADR-0032).
- locked by
- 0.17.0 met
- recorded done
- lemonfibercrates/lemonfiber-core/src/seed/run/decline.rscrates/lemonfiber-core/src/seed/run/taken_back.rs
- recorded partial
- lemonfiber-media-stackservices/decline.toml::confinedscripts/check_configs.py::the dashboard holds no credential
- recorded partial
- lemonfiber-request-gatesrc/arr.rssrc/jellyfin.rssrc/arr/tests/forwarding.rs::a_call_off_the_list_or_on_the_other_arrs_route_is_refused
- cited by
- lemonfiber@07b0fd1c77lemonfiber@d089bab2cblemonfiber@7008624f60lemonfiber-request-gate@f6b801c7e4lemonfiber-media-stack@4c7bc56170lemonfiber-media-stack@bd94d60204lemonfiber-media-stack@ca0baba8f8
Jellyfin's cross-origin allow-list MUST name the household front door's origin and nothing else, MUST follow a change of that address, and MUST NOT be written empty or as a wildcard.
The request gate MUST publish no port and MUST be reachable only from the request service, which MUST have no other network path to Sonarr, Radarr or Jellyfin. It MUST be confined: no data mount, no engine socket, a read-only root, no kernel capabilities, no egress, and network reach only to the services it acts on (ADR-0032).
- locked by
- 0.17.0 unmarked
- recorded partial
- lemonfiber-media-stackservices/request-gate.toml::confinedscripts/test_service_model.py::ARCH-R233 a confined service its image runs as
- recorded partial
- lemonfiber-request-gateDockerfilesrc/main.rs
- cited by
- lemonfiber@07b0fd1c77lemonfiber@d089bab2cblemonfiber-request-gate@9b57dbd1f3lemonfiber-request-gate@750de41e1clemonfiber-media-stack@4c7bc56170
The request gate MUST answer only the calls ADR-0032 lists, by method and path, MUST build every upstream request itself from the parameters and body fields that list names, checking each write's body against what the upstream holds, MUST refuse every other call without forwarding it, and MUST NOT pass an upstream administrator's session to the request service.
- locked by
- 0.17.0 met
- recorded done
- lemonfiber-request-gatesrc/arr.rssrc/arr/written.rssrc/jellyfin.rssrc/arr/tests/forwarding.rs::a_call_off_the_list_or_on_the_other_arrs_route_is_refusedsrc/arr/tests/changes.rs::a_removal_carries_the_id_and_its_two_flags_and_nothing_elsesrc/jellyfin/tests.rs::a_sign_in_on_a_device_the_request_service_does_not_assign_is_refused
- cited by
- lemonfiber@07b0fd1c77lemonfiber@6577d8c68dlemonfiber@e9dfd9f2fblemonfiber-request-gate@996fb32958lemonfiber-request-gate@f15b05f39elemonfiber-request-gate@5be17e061clemonfiber-request-gate@9b57dbd1f3lemonfiber-request-gate@750de41e1c
The request gate MUST hold the upstream credentials itself and MUST give the request service only tokens lemonfiber minted, one per upstream, kept by the gate only as hashes and by lemonfiber nowhere; each token MUST be rotatable, proven before the one it replaces is revoked, and revocable alone.
- locked by
- 0.17.0 met
- recorded done
- lemonfibercrates/lemonfiber-core/src/seed/run/decline.rscrates/lemonfiber-core/src/seed/run/taken_back.rscrates/lemonfiber-core/src/seed/run/gate.rscrates/lemonfiber-core/src/seed/run/tokens.rscrates/lemonfiber-core/src/app/credentials/gating.rscrates/lemonfiber-core/src/app/credentials/tokening.rs
- recorded partial
- lemonfiber-request-gatesrc/files.rssrc/files/tests.rs::a_route_accepts_its_token_and_no_call_without_one
- cited by
- lemonfiber@3b589bfe9dlemonfiber@8ac2026c35lemonfiber@6577d8c68dlemonfiber@e9dfd9f2fblemonfiber-request-gate@996fb32958lemonfiber-request-gate@5be17e061clemonfiber-request-gate@9b57dbd1f3
The request gate MUST record every call it refuses and every removal it forwards, with its time, route, method and path and never a token, a query string or a body, and a diagnostic check MUST report each since it last read the record.
- locked by
- 0.17.0 met
- recorded done
- lemonfibercrates/lemonfiber-core/src/doctor/gating.rs
- recorded partial
- lemonfiber-request-gatesrc/files.rssrc/files/tests.rs::each_entry_is_added_after_the_last
- cited by
- lemonfiber@3b65063ccelemonfiber@e9dfd9f2fblemonfiber-request-gate@996fb32958lemonfiber-request-gate@9b57dbd1f3