docs(route): define pragmatic LiveKit trust boundary
This commit is contained in:
1 parent
6b0b1a37e3
commit
1fc89b51ae
4 files changed
+42
-6
No files matched your search
@@ -227,11 +227,19 @@ do not prove target-network latency, quality, capacity, or interoperability.
|
||||
|
||||
## Security and privacy
|
||||
|
||||
Media authority is room-, role-, session-, share-, revision-, and
|
||||
connection-bound. Server-assisted credentials are short-lived, scoped,
|
||||
memory-only, and never placed in URLs, logs, browser persistence, or SQLite.
|
||||
Route and signaling authority is room-, role-, session-, share-, revision-, and
|
||||
connection-bound. LiveKit media credentials are short-lived and bound to the
|
||||
room, role, share, and publication generation so healthy media may survive a
|
||||
signaling reconnect. Server-assisted credentials remain memory-only and never
|
||||
appear in application page URLs, browser persistence, or SQLite. LiveKit places
|
||||
its short-lived JWT in the WebSocket transport request target, which must not be
|
||||
logged; no credential may enter application or proxy logs.
|
||||
Ordinary SFU transport terminates DTLS-SRTP at the SFU; the product must not
|
||||
claim application E2EE unless key distribution and real media evidence exist.
|
||||
Authenticated Hosts and shipped clients are trusted media participants in the
|
||||
current private-room threat model. Stale route-control sessions remain
|
||||
unauthorized; a retired media generation remains charged during bounded drain
|
||||
until deletion of its exact room prevents re-entry.
|
||||
|
||||
## Consequences
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ Last updated: 2026-08-23
|
||||
## Current Product Truth
|
||||
|
||||
- Build private, low-latency game screen sharing for one broadcaster and a small group of trusted friends. Public or large broadcasts belong on OBS/Twitch-class services.
|
||||
- Authenticated Hosts and shipped clients are trusted media participants in these private rooms; route authority, generation fencing, and server admission remain fail-closed.
|
||||
- Web is the current delivery target. Viewers join from desktop or mobile browsers; a packaged or native sender is a later optimization.
|
||||
- Keep routing automatic and media distributed. Direct/peer UDP is preferred; centralized media is fallback infrastructure, not the default topology.
|
||||
- Every non-server endpoint uses one server-authoritative steady outbound media-copy capacity: default `2`, statically configurable as `1`, `2`, or `3`. A peer child or the Host publication consumes one slot; upstream receive is free, selected TURN replaces the same copy's transport, and SFU subscriber egress is accounted at the server. Browser role/UA/visibility does not create a separate tier, and clients cannot raise the deployment value.
|
||||
|
||||
@@ -533,6 +533,28 @@ the server must. Redundancy can improve recovery but costs traffic and
|
||||
coordination; removing redundancy leaves a recovery interval after a relay is
|
||||
lost.
|
||||
|
||||
## Self-Hosted LiveKit Trust Boundary
|
||||
|
||||
Pinned LiveKit 1.13.5 treats `canPublishSources` as a source allowlist, not a
|
||||
per-participant or per-source publication-count limit. `limit.num_tracks` gates
|
||||
node-wide `NumTracksIn + NumTracksOut` admission, while
|
||||
`subscription_limit_video/audio` caps each participant's concurrent subscribed
|
||||
tracks by kind and leaves excess requests pending; neither is an SFU bandwidth
|
||||
budget.
|
||||
|
||||
Self-hosted `RemoveParticipant` closes the current participant but does not
|
||||
invalidate a still-valid join token. With `room.auto_create: false`, such a
|
||||
token cannot recreate an absent room. Screener's exact-generation room names
|
||||
include an unguessable publication generation and are never reused, so room
|
||||
deletion plus absence proof fences an old media generation rather than revoking
|
||||
every token immediately.
|
||||
|
||||
Screener sizes ingress and egress for its shipped clients in private rooms where
|
||||
authenticated Hosts are trusted media participants. Exact-generation room
|
||||
lifecycle, short-lived scoped tokens, source grants, selective subscription,
|
||||
and deployment isolation remain required. The pinned upstream LiveKit release
|
||||
is sufficient for that boundary.
|
||||
|
||||
## Route Screening
|
||||
|
||||
| Route | Where copies are emitted | Endpoint cost | Evidence status |
|
||||
@@ -608,7 +630,7 @@ The measurable gates and exact staged experiments are in
|
||||
|
||||
## Sources And License Boundary
|
||||
|
||||
Primary sources accessed on 2026-08-19, 2026-08-21, and 2026-08-22:
|
||||
Primary sources accessed on 2026-08-19, 2026-08-21, 2026-08-22, and 2026-08-23:
|
||||
|
||||
- [Pion WebRTC](https://github.com/pion/webrtc) - MIT; no code copied.
|
||||
- [Pion WebRTC v4 API](https://pkg.go.dev/github.com/pion/webrtc/v4) - API
|
||||
@@ -672,6 +694,11 @@ Primary sources accessed on 2026-08-19, 2026-08-21, and 2026-08-22:
|
||||
reference, with no code copied into this research change.
|
||||
- [LiveKit 1.13.5 configuration sample](https://github.com/livekit/livekit/blob/v1.13.5/config-sample.yaml),
|
||||
[pinned configuration source](https://github.com/livekit/livekit/blob/v1.13.5/pkg/config/config.go),
|
||||
[node track-limit selection](https://github.com/livekit/livekit/blob/v1.13.5/pkg/routing/selector/utils.go),
|
||||
[participant publication checks](https://github.com/livekit/livekit/blob/v1.13.5/pkg/rtc/participant.go),
|
||||
[subscription-limit handling](https://github.com/livekit/livekit/blob/v1.13.5/pkg/rtc/subscriptionmanager.go),
|
||||
[room allocation](https://github.com/livekit/livekit/blob/v1.13.5/pkg/service/roomallocator.go),
|
||||
[room-service lifecycle](https://github.com/livekit/livekit/blob/v1.13.5/pkg/service/roomservice.go),
|
||||
[ports/firewall](https://docs.livekit.io/transport/self-hosting/ports-firewall/),
|
||||
[deployment/embedded TURN](https://docs.livekit.io/transport/self-hosting/deployment/),
|
||||
and [benchmark guidance](https://docs.livekit.io/transport/self-hosting/benchmark/)
|
||||
|
||||
+2
-2
@@ -26,7 +26,7 @@ SFU/TURN 的 publication、subscription、transport、server-resource accounting
|
||||
- 一对多观看:房间 admission 与端点下游容量分别配置,超额加入必须明确拒绝。Production 当前默认 8、显式接受 1 至 16;未来默认值和上限是独立产品决策,必须经过相应资源、质量、深度和恢复验收,不能从端点 cap 或一次短跑推导。
|
||||
- 端点发送容量:所有非服务器端点使用同一个服务端权威稳态 outbound media-copy capacity,由唯一部署项 `ENDPOINT_MEDIA_COPY_CAPACITY` 配置,默认 `2` 且只接受 `1`、`2` 或 `3`;不读取旧键或保留第二套 tier。peer child 或 Host 的唯一 SFU publication 各消耗一份,上游接收不消耗该预算,committed selected TURN 只替换同一份 logical edge 的 transport。客户端只能声明不高于部署值的可用容量,角色、浏览器、UA、设备类型和页面可见性不产生不同上限。服务端在每次 `authenticated` 权威快照中返回最终 `endpointMediaCopyCapacity`;普通非 peer-assisted 模式也只授权稳定加入顺序中的至多 `C` 个 Host child,超额 Viewer 保持入房等待并在槽位释放后提升,信令不能绕过该集合。Web 与 Native 严格校验该值,Native Host 的普通 Viewer admission、peer-assisted child assignment 和实际发送槽位都使用同一值,且不得从独立的房间 `maxViewers` 推导。并行产生媒体的 candidate 必须持有唯一的 `TransitionOverlapSlot`,并在 commit 后回到稳态上限;SFU subscriber egress 与 TURN allocation 由独立 server admission 记账。该不兼容能力变化与单一 signaling wire 原子升级;缺失或非法 cap 与旧客户端都在取得房间或 route authority 前 fail closed。
|
||||
- P2P 优先:每条普通逻辑媒体边先尝试 direct/peer UDP,服务器不得默认中转可直连媒体。更多观看者优先沿满足统一端点容量的无环 peer 图分布;每名 Viewer 同时至多一个 active upstream,失败时只影响需要重选的分支。
|
||||
- NAT 与传输边界:STUN 必须可用,所有 ordinary peer `RTCPeerConnection` 只接收 STUN ICE servers,普通边不得预发 TURN candidate。所有恢复和候选授权必须绑定 exact room/share generation、endpoint session、route/assignment generation 与 connection identity;成功即停止,失败、超时或绑定失效即撤销,全部可用路径耗尽后明确等待或失败。已接受的顺序是保持既有 logical edge,必要时 direct/STUN 后使用 exact selected TURN;只有 logical ingress 不可用时才使用当前 Host publication 的 SFU subscription。Host 无 direct first-level path 时优先一条可经 TURN 的 Host-SFU publication,而不是逐 Viewer 建 Host-TURN peer 边。凭据不得进入 URL、日志、浏览器持久化或 SQLite;HTTPS/WSS 继续独立使用 TLS/TCP。
|
||||
- NAT 与传输边界:STUN 必须可用,所有 ordinary peer `RTCPeerConnection` 只接收 STUN ICE servers,普通边不得预发 TURN candidate。所有恢复和候选授权必须绑定 exact room/share generation、endpoint session、route/assignment generation 与 connection identity;成功即停止,失败、超时或绑定失效即撤销,全部可用路径耗尽后明确等待或失败。已接受的顺序是保持既有 logical edge,必要时 direct/STUN 后使用 exact selected TURN;只有 logical ingress 不可用时才使用当前 Host publication 的 SFU subscription。Host 无 direct first-level path 时优先一条可经 TURN 的 Host-SFU publication,而不是逐 Viewer 建 Host-TURN peer 边。凭据不得进入应用页面 URL、日志、浏览器持久化或 SQLite;TURN 凭据和 Screener route grant 不进入任何 URL,LiveKit join JWT 仅按协议进入不得记录的 WebSocket request target。HTTPS/WSS 继续独立使用 TLS/TCP。
|
||||
- 质量控制:保留 1080p60(8 Mbps)、1080p30(5 Mbps)、720p30(3 Mbps)三档推荐上限,三档与高级设置初始值统一采用 `balanced`(平衡)与 `automatic`(自动编码),`maintain-resolution`(清晰优先)、`maintain-framerate`(流畅优先)和 H.264/VP8 保留为显式选择。分享期间可直接换视频档位和 64/128/256 kbps 音频 sender ceiling,不重新选择来源或重建健康连接;视频 codec 首个可交付切换边界是在分享已显式暂停时执行有界重协商,未暂停热切换是后续复用同一事务的扩展。Peer-assisted relay 与已配置的 SFU 必须接收同一个严格校验的房间级权威设置,覆盖当前和以后建立的 sender;普通 P2P 信令结构保持不变。任何设置都只是浏览器上限和偏好,具体降级由浏览器决定;必须读回实际 sender 参数并通过 stats 观测结果、显示参数拒绝、改写和持续受限原因。不做自定义动态 FPS、综合评分或周期性全房间调档。
|
||||
- 路径隔离双表示:direct/peer 继续使用每条 PeerConnection 独立的 stock WebRTC GCC,不把任何 viewer 反馈合成全房目标。每条 SFU path 从 `HIGH` ceiling 开始;优先用 pinned LiveKit 2.22.0/1.13.5 的标准两层 screen-share simulcast,在 Dynacast off 下常驻 exactly `HIGH+LOW`,让内建 per-subscriber BWE 独立降层和恢复。若该 gate 通过,Screener 不实现媒体层 selector。首 gate 使用 zero-descendant SFU leaf;root-with-children 的自动 downshift 与有界迁移是 default-on 前独立硬门。只有内建选择不满足门槛时才用标准 subscriber quality 显式限制,常驻成本不合格时再测标准 sender 手动启停。`LOW` 停编只是资源优化;active representation/layer 硬上限为二,禁止按 viewer 增长。必须实测实际接收层、硬件编码证据、游戏 FPS/p1 low、CPU/GPU、区间 encode cost、上传和分层 bytes。当前 Web P2P simulcast 缺少 receiver 选 RID 和跨 PeerConnection shared-encode 契约;当前 Web/LiveKit SVC 也缺少 direct/peer 独立选层与可移植硬件保证,且 pinned screen share 强制三层 temporal-only `L1T3`,二者按现契约静态 no-go。全部标准路径失败后才考虑 custom/native dual encode。没有合格 hardware/power-efficient 路径或额外表示破坏游戏/上传预算时 fail closed:保护健康路径并明确显示弱路径降级或不可用。
|
||||
- 路径级质量状态:应用的 `HIGH`/`FALLBACK` 非对称窗口只决定拓扑资格和诊断,不命令正常的媒体层切换,也不计算综合分数。`EdgeHealth(parent, child)` 只控制该 child 的换父;`RelayEligibility(parent)` 仅适用于 relay parent,按 `eligible -> suspect -> draining -> ineligible` 控制其是否接收新 child 以及是否排空现有 children。质量 owner 根据不同 downstream edges 的当前可观察证据和端点容量要求足够的独立关联;同一 edge 的 C+B 只处理该 child。relay parent 自身 ingress 失败先触发本地修复并进入 `suspect`,只有修复失败、明确 sender/resource failure 或独立 downstream edges 确认转发仍失效时才 drain,不等待不存在的第二个 child;Host source 走 publication repair/child migration,不走 parent reparent。退位时仍健康的 ingress 保留,失效 ingress 在同一 bounded target 中替换或移除;无目标 child 进入有界等待或失败,更长的稳定证明和 cooldown 后才恢复 `eligible`。Viewer 请求必须鉴权、限频、去重,并由 sender 的 GCC/Transport-CC、实际码率、RTT、丢包、重传、编码限制、协商 codec/profile/parameters 与 viewer 解码、丢帧、冻结证据交叉验证;不能仅凭自报生效,也不得上传 raw SDP、candidate 地址或原始设备/网络标识。
|
||||
@@ -71,7 +71,7 @@ SFU/TURN 的 publication、subscription、transport、server-resource accounting
|
||||
- 启播:观看者请求观看后,除用户授权耗时外,3 秒内出现首帧;从请求开始到首帧期间持续显示真实、稳定且可访问的连接阶段,不用黑屏、`playing` 事件或 ICE `connected` 冒充已播放。
|
||||
- 流畅性:选择 60 fps 档位时,不能在没有降档或提示的情况下连续 5 秒低于 50 个解码帧每秒。
|
||||
- 成本:direct/peer UDP 不经过应用服务器。SFU/TURN 的 ingress、egress、allocation 和并发上限由整体路由模型明确配置;验收逐 hop 记录 Host、peer、SFU、TURN 和供应商计费的真实 bytes,不得用普通端点 child 数或有效载荷近似代替中央资源准入。
|
||||
- 安全:应用控制面全程 HTTPS/WSS;site access、Host token 与 room-scoped Viewer grant 权限正交,任何一个 Viewer grant 只授予一个房间的观看角色。P2P/TURN 边在 WebRTC 端点间使用 DTLS-SRTP,普通 SFU 是逐跳 DTLS-SRTP;只有另行实现并验收应用层 E2EE 才能对 SFU operator 保持媒体端到端机密。仓库、数据库、日志和错误不得包含明文密码或 grant。
|
||||
- 安全:应用控制面全程 HTTPS/WSS;site access、Host token 与 room-scoped Viewer grant 权限正交,任何一个 Viewer grant 只授予一个房间的观看角色。P2P/TURN 边在 WebRTC 端点间使用 DTLS-SRTP,普通 SFU 是逐跳 DTLS-SRTP;只有另行实现并验收应用层 E2EE 才能对 SFU operator 保持媒体端到端机密。仓库、数据库、日志和错误不得包含明文密码或 grant。已鉴权 Host 与 shipped clients 是当前私密房间中的可信媒体参与者;越权房间、角色和未授权 subscription 必须拒绝。旧 generation 不得重新取得 route authority,并在有界 drain 后由 exact-room 删除阻止再次加入。
|
||||
- 隐私:P2P 会向房间内好友暴露网络地址,首版威胁模型仅覆盖可信熟人;若要求隐藏 IP,必须切换为服务器转发。
|
||||
- 可维护性:代码、需求、调研、项目记忆、`AGENTS.md` 和 `.codex/` 均在 Git 中跟踪;开发配置不得依赖单一操作系统的绝对路径。
|
||||
- 迁移完整性:同一 release 的客户端、服务端和部署配置原子迁移;canary 结束后删除被替代的配置、wire、parser、双写与测试,不为无当前消费者的旧版本保留兼容层或第二套架构。Git 历史承担旧实现追溯。
|
||||
|
||||
Reference in new issue
Block a user