4.1 KiB
NekoNest Cloud 状态模型
账号、租户与席位
- 一个 Cloud 账号拥有一个
tenant_instances记录。 - 一个
active且slot_state=active的主机占一个席位,在线与否不改变计数。 - 未过期的 waiting pairing 只预留容量;取消、过期或成功 claim 后释放预留。
- pairing 创建与 claim 都在写入 SQL 内复核容量。第 N+1 台返回
device_capacity_exceeded。 - 账户所有者可以轮询自己创建的配对状态,但不能读取其他账户的请求。
- 等待中的请求可由所有者取消;若 daemon 已先认领,则取消失败,不能撤销已提交的设备凭据。
- 主机撤销将主机标记为 deactivated、撤销所有设备凭证、释放席位,并推进 authorization revision。
- 同一身份恢复复用原 host ID;不能因复制公开指纹而获得第二个身份。
席位允许设备成为租户成员,不自动授权任何手机读取该设备。
Placement
tenant_placements 是共享 Relay 的部署权威:
home_region_id固定租户主区域;relay_node_id指向当前唯一可写节点;generation只能单调增加;state首版使用provisioning|active|quiescing|copying|switching|draining|failed。
客户端只看到稳定 Connect origin。provisioning 时在同一地址重试,不得到后端节点 URL。
授权 revision
每个租户有一条 tenant_authorization_state:
status=active|suspended;revision在成功 claim、主机撤销、手机撤销或租户暂停时单调增加;- 变更只有在相应设备/主机写入已经成功时才推进,避免未提交操作造成虚假撤销。
Relay 获取最长 5 分钟的签名快照,每 60 秒完整刷新、默认每 5 秒检查 revision(delta 与随后的完整刷新各限制为 3 秒)。控制面不可达时不建立新 principal;现有连接最多存活到快照到期。
节点与签名密钥
节点状态为 provisioning|active|draining|offline|retired。heartbeat 只接受非回退 generation。节点以 D1 中未撤销、未过期的 SPIFFE ID 与证书 SHA-256 指纹记录为身份。所有内部调用必须先通过受信 mTLS 终止层注入绑定 method/path 的短时 HMAC assertion;控制面不要求共享 bearer。
Ed25519 私钥不进入 D1。relay_signing_keys 只保存 public JWK、private_key_ref、kid、有效期与状态。签名密钥必须至少有效到新快照的 expires_at;轮换重叠必须长于 5 分钟最大快照 TTL,旧 public JWK 也必须保留超过最后一份旧 key 快照的 TTL,保证验证窗口不断裂。
Phone handoff
phone_handoff_tickets 生命周期:issued → consumed 或 issued → expired。ticket:
- 随机 256 bit;
- D1 只保存 SHA-256 摘要;
- 绑定账号、租户、精确 PWA origin;
- 60 秒有效;
- 条件 UPDATE 原子消费一次。
控制面只允许目标 placement 节点原子消费 ticket,并向该节点返回 tenant 与手机公钥。目标 Relay Engine 创建独立 phone principal/token 后,把 routing-only handle 摘要登记回来。控制面不生成或保存 phone token。该流程不创建 device grant;route handle 只负责解析 tenant placement,不能替代 phone token。
每次 phone WS/REST 入口都必须同时校验 route handle 摘要与 phone token 摘要,并要求两者绑定同一未撤销 phone principal 和 tenant;单独持有 route handle 不构成授权。已消费或已过期 ticket 只短暂保留摘要和公开身份字段用于防重放诊断,24 小时后由维护任务删除;D1 从未保存明文 ticket。
数据边界
D1 保存账号、权益、主机身份元数据、凭证摘要、placement、授权 revision、公钥、ticket/route 摘要和审计。新增表不得出现 prompt、session、attachment 明文或私钥。
控制面 last_used_at 只证明设备凭证最近成功通过授权,不证明租户 relay、WebSocket、Relay Engine 或本地 Agent 在线。
遗留 grace_days 不参与资格、设备认证或页面判断。
加载、离线和页面失败是客户端展示状态,不得改写控制面 placement、授权或主机身份事实。