matrix-rtc: separate standalone publication from room creation

This commit is contained in:
heather 2026-11-07 21:55:21 +00:00
commit 2ff4caa788
5 changed files with 321 additions and 1 deletions

View file

@ -0,0 +1,97 @@
# MatrixRTC standalone publication policy (iscg policy1)
## Policy and boundary
This is a narrow fork of Element's lk-jwt-service v0.9.0, upstream commit
`0e176b1eca44e67b11484d0bdf56999807bf2b8e` (AGPL-3.0-only). It fixes both
standalone endpoints, `/sfu/get` and `/get_token`:
- Matrix OpenID verification still runs, including the subject's server name
and the claimed user ID where the protocol supplies one.
- Every successfully authenticated participant may publish audio/video in the
requested, room-scoped session, regardless of their homeserver.
- `LIVEKIT_FULL_ACCESS_HOMESERVERS=iscg.dev` still gates the server-side
`CreateRoom` call and delayed-leave delegation. It is NOT widened to `astr.to`
or `*`. No user's JWT gains room creation, list, recording or admin privileges.
- Existing application-service membership checks, when configured, are unchanged.
- The SFU MUST retain `room.auto_create: false`. Otherwise remote users can
create arbitrary SFU rooms by joining, regardless of JWT-service policy.
- A remote user may obtain a scoped token before a local user creates the room;
the SFU rejects joining a missing room. This is intentional upstream behaviour.
- Existing one-hour token TTL, SFU participant limits and container hardening
are preserved. No new appservice/admin credential is introduced.
**This is not Matrix room-membership authorization.** On Heather, Tuwunel
1.9.4 has no MSC4502/MSC4512 integration, and lk-jwt-service is standalone.
Someone with valid Matrix OpenID and knowledge of a room ID can request an SFU
token even if not a Matrix member, including for an unencrypted call. This
limitation existed for subscribing before the patch and now includes publishing.
Room IDs are not authorization secrets; E2EE, when enabled by clients, protects
media confidentiality, not resource abuse or forged room participation. Do not
advertise this deployment as membership-checked or suitable for anonymous guests.
The fuller migration is homeserver-backed MSC4195/MSC4502/MSC4512 integration
with scoped application-service membership checks. It requires a homeserver
that supports those APIs (or a separately reviewed Tuwunel implementation),
client compatibility checks and a backed-up migration. Adding `astr.to` or `*`
to the full-access list does not solve membership authorization. The newer
upstream `LIVEKIT_REMOTE_CAN_PUBLISH_HOMESERVERS` option applies to federated
application-service requests, not to these standalone endpoints.
## Source and tests
`standalone-publication.patch` changes two authorization arguments, adds a
startup policy banner, regression tests and updates the two HTTP integration
suites' remote publication expectations. Creation, delegation, OpenID and
membership-check implementations are not replaced.
The image build fails unless all root-library unit tests and both HTTP/OpenID
integration suites (`get_token`, `sfu_get`) pass. Regressions cover local users,
`astr.to`, an unrelated server, rejected OpenID, foreign/forged subject,
room-scoped JWTs and lack of creation/admin permissions. Existing membership
and delayed-event denial tests remain part of the unit suite.
The upstream archive, patch and Rust builder image are SHA256-pinned, and Cargo
uses `--locked`. Alpine build-tool packages are fetched from its package
repository, so this is a pinned-source build recipe, NOT a claim of bit-for-bit
reproducible output. Preserve the exported release image and its checksum too.
## Build (Linux amd64 / Docker)
From this directory:
```sh
# Run long work in tmux. No production secrets are needed by the build.
sudo bash build.sh
```
The resulting image is
`iscg/lk-jwt-service:0.9.0-policy1-6e21c58c02d6`.
The image is local-only and Compose uses `pull_policy: never`. On a replacement
host, rebuild it or load the preserved Docker image archive BEFORE starting
Arion. Do not replace it with an unreviewed latest tag. Tests and compiler run
in build containers; no Rust toolchain is installed on the NixOS host.
## Deployment and rollback
Deploy only `matrix-rtc-jwt` with the evaluated Arion composition, after staging
and health/token/media checks. No homeserver, SFU, Coturn or unrelated service
restart is required. Compare the Nix source baseline to `/run/current-system`
and inspect dry activation before switching so unrelated edits are not applied.
The deployment receipt records the exact image ID and new Nix generation.
Before deployment preserve the old generation, old composition, old image,
container start-time baseline and config source. Keep release archives outside
cache on Heather and Poppy.
For an emergency rollback, use the saved pre-policy Arion composition:
```sh
sudo arion --prebuilt-file /path/from/receipt/old-compose.yaml \
up -d --no-deps --pull never matrix-rtc-jwt
```
Then restore the pre-policy Nix generation/source selectively, retaining any
subsequent unrelated edits. Do not restart the whole `heather.service`, wipe
volumes, revert the homeserver database or disable TLS verification. Rejoin the
call to obtain a fresh JWT; previously issued tokens do not change retroactively.