跳转到内容

首次启动、离线配置与认领设备

Mica OS 设备必须在零外部输入的情况下抵达完全可用状态——没有 DHCP 服务器、没有 DNS,甚至可能没有网线。这个性质是设计出来的,不是碰巧。本页讲首次启动自己 做了什么、完全没有网络的设备走哪条离线路径,以及设备如何从“未认领”变成 你的。

从空 DATA/state 的首次启动,管理守护进程会在任何东西消费它之前,一次性、原子地 播下设备配置:

  • 设备 id——从系统 CSPRNG 抽取的 32 个十六进制字符;
  • 主机名——mica- 加设备 id 的前八个十六进制字符。它派生自身份而不是 网络,因此跨子网、跨租约续期、换网卡都稳定,也短到可以印在标签上;
  • 每设备密钥,在设备上生成——绝不烤进镜像,镜像在同一发布版的每台设备 上是逐字节相同的;
  • SSH 关闭,两个镜像 profile 都是;
  • 没有网络配置——这是故意的。镜像自带一条针对有线 eth* 接口的静态 DHCP 匹配,因此新设备能在任何 DHCP 网络上拿到地址,而 micad 不必去猜接口 名字。

持久化回滚记录覆盖 DATA 上的配置文档与 DATA/state 上的身份记录;未完成的恢复必须在 下一次启动读取设置前完成(provisioning.md)。 播种失败会大声中止,下一次启动从头重试;一台看起来配置好了、其实只配了 一半的设备正是这个设计要拒绝的失败。SSH 主机密钥在设备上于首次启动时生成, DATA 也在此时扩展到占满磁盘(见 install.md)。

status: shipped — evidence: docs/design/provisioning.md, mica-system:overlay/usr/lib/mica/mica-seed-state

所有当前目标均由原生 init 在服务启动前将 machine id 建立并保存在 DATA/state, 再只读绑定到 /etc/machine-id。它跨重启和组件更新保持稳定;格式错误或不可用的 身份会被拒绝,不会静默生成临时替代身份。

status: shipped — evidence: mica-deploy:src/bin/mica-init.rs, mica-build:verify/src/checks-file-root.ts

  • 在 DHCP 网络上:设备在有线接口上请求地址,并把 mica-xxxxxxxx 主机名 通告给 DHCP 服务器。不论 DNS 如何,这个名字在设备本地总能解析。
  • 管理接口是设备地址上的 apid over HTTPS(443 端口,80 端口重定向)。 TLS 证书是每设备生成的,因此第一次访问会看到自签名证书警告——这是预期 行为,值得向操作者解释清楚,而不是训练他们对所有警告视而不见。

status: shipped — evidence: mica-core:apid/, docs/design/remote-management.md

在 cx3576 上,两个以太网口都没有硬件 MAC 地址,因此设备会用 eMMC 芯片标识 与该网口在板上的挂接位置为每个口推导一个地址。这样得到的地址在重启、重新 烧录和镜像升级之后都保持不变。

地址依据 eMMC CID 和物理拓扑计算,不依赖接口探测顺序。当前开发验收全部使用 完整最新版系统;请记录实际读到的板卡接口及地址。

status: board-dependent — evidence: mica-boards:boards/cx3576/package/hwinit/hwinit-mac, mica-boards:boards/cx3576/package/init/mac.conf, mica-build:make os-mac-test

对于没有可控网络的设备,或必须开箱即配好的设备,配置手段是配置文档: 一个名为 mica-provisioning.toml 的 TOML 文件,放在介质文件系统的根目录, 在首次启动过程中被读取一次,并在其他一切之前应用。

**先读这一段,因为这里最常被误判为“功能坏了”:配置文档只在设备还没有 管理员凭据时才被采纳。**设备一旦被认领——通过 setup,或通过更早的一份 文档——介质上提供的文档就会以 already-claimed 被拒绝,上面的内容一样都 不会应用。**已经上线的设备不能用 U 盘重新配置。**正是这条规则让一个不带 签名的传输通道是安全的,它不是一个需要绕过去的缺陷:重新配置已认领的设备 走的是带认证的 API。往运行中的设备里插卡却什么都没发生的操作者,看到的是 这条规则,不是一次失败。

通道 文件放哪 何时被读
boot 当前 UEFI ESP,GPT 标签为 esp;cx3576 没有 ESP,使用可移动介质 优先;可以把介质取出后用任意读卡器写入
media 已连接的可移动块设备——先看它的各个分区,再看裸盘 仅当引导分区上什么都没有时

两者都只在启动时读一次,在任何东西开始监听之前。这里故意没有 udev 触发,也没有任何 HTTP 路由能应用一份文档:之后才插上的 U 盘是下一次启动的 文档,永远不是重新配置运行中设备的途径。设备启动所用的内置 eMMC 或 NVMe 永远不会成为 media 的候选。挂载不上的介质根本不会变成一份文档,因此 journalctl -u mica-provisioning-import 才是“插了 U 盘却没反应”时第一个要 看的地方——而不是状态路由。

status: board-dependent — evidence: mica-system:overlay/usr/lib/mica/mica-provisioning-import, mica-boards:boards/cx3576/board.env, mica-boards:boards/x64/board.env

它能带什么,以及它点名拒绝什么

Section titled “它能带什么,以及它点名拒绝什么”

一份文档可以设置设备身份、第一个管理员密码和授权 SSH 公钥、有线网络设置、 WiFi 客户端网络,以及时间设置。每个键都映射到一个已经存在的设置,并且经过 与 API 写入完全相同的校验器。

有两样东西是被点名拒绝的,要求它们是错误而不是遗漏证书段和 主机名。两者都没有对应的设置路径——设备上唯一的证书是 apid 自己的 自签名 TLS 密钥对,那是 DATA/state 上的文件而不是设置;而设备的名字是从文档 注入的身份派生出来的。携带其中任何一项的文档都会被拒绝,并点出违规的键。

还有两条操作者必须据以规划的性质:

  • 整份文档在应用任何一部分之前先被完整校验。一个字段有问题,就一个字段 都不应用;拒绝信息给出键路径而绝不给出取值——所以格式错误的文件不会 把它携带的密码泄进日志,也不会留下一台配了一半的设备。被拒绝不等于变砖: 设备会以未认领、可配置的状态启动。
  • **两条通道都不校验签名。**这句话要直说,因为靠推断的读者可能推错:文档 不会被拿去和任何密钥比对。它唯一的授权就是对介质的物理占有,边界是上面 那条“已认领即拒绝”的规则。

文件会原样留在介质上——不删除、不改写。请把配置介质当作凭据材料对待, 因为一份文档可能携带管理员密码和 WPA2 预共享密钥,而同一份文档可能被写进 一整批卡。

GET /api/v1/provisioning/status 向已认证的调用方报告最后应用的文档版本与 摘要,以及最后一次导入尝试做了什么。它不返回文档携带的任何取值。

status: shipped — evidence: mica-core:micad/src/provisioning_doc.rs, mica-core:apid/src/provisioning_api.rs, docs/design/provisioning.md

**哪些从未在硬件上执行过。**文档解析器、它的校验器和状态路由都有测试覆盖。 传输通道没有:没有任何测试、没有任何台架运行把真实的引导分区或真实的 U 盘送进一次真实启动,其中引导分区通道尤其从未在物理板卡上跑过。机制发布 了;流程没有被证明,而记录一次真实运行的地方是板卡档案 (../../boards/qualification.md)。

status: shipped — evidence: mica-system:overlay/usr/lib/mica/mica-provisioning-import, docs/design/provisioning.md

认领就是“未认领 → 已认领”的那次转变,判定设备在哪一侧的唯一事实是管理员 凭据是否存在。能创建第一个凭据的通道正好两条:

  1. Setup——第一次访问 /_ui/,API 客户端则是 POST /api/v1/setup。 管理员密码由你选择;该路由建立浏览器会话,并为自动化铸出一枚一次性 bearer token。对已认领的设备再调一次 setup 会以 already_configured 被拒绝,且不写入任何东西。
  2. 配置文档——第 3 节。密码来自介质。

从认领开始,每一次管理读写都需要认证。会话与 token 模型见 api.md,接下来配置什么见 configuration.mdGET /api/v1/claim 向已认证的调用方 回答是哪条通道、在什么时候认领了这台设备。

由配置文档认领的设备持有的是一个 bootstrap 秘密:它以明文躺在一份设备 故意不去擦除的介质上,而同一份文档可能被写进一整批卡。因此这类认领会置上 rotationRequired。在它被解除之前,设备服务所有读取,但对每一次已认证的 写操作返回 409 rotation_required——例外只有登录、读取原因,以及 POST /api/v1/actions/change-password 这一个能解除它的动作。通过 setup 认领则不会置这个标志:那个密码是调用方在认领当刻选定的,从未被写在设备 能够推理的任何地方。

这个约束是“首次登录”,不是经过的时间,也没有任何东西在倒计时。一台 已认领但从未被登录过的设备,其 bootstrap 凭据无限期有效——一台带着卡 下线、又在仓库里躺了一年的单元,开箱那天握着的仍是同一个可用密码。这是 故意的:这台设备不会拿自己的时钟去执行任何期限,因为未认领的设备恰恰就是 没有同步时钟的设备,而一个关闭时里面没人的窗口只会留下一台谁也进不去的 设备。**把“强制轮换”读成“凭据会自己失效”的读者,规划的是一个并不存在的 暴露窗口。**在首次登录之前限制这个暴露的,是对介质的物理保管,没有别的。

  • **它不是 SSH 凭据。**SSH 保持关闭,直到一位已认证的管理员启用它并装入 公钥——访问模型见 security.md
  • **它今天无法由设备本身恢复。**在现有的任何板卡上,丢失管理员凭据和全部 授权公钥就意味着没有软件路径能回到设备里。凭据恢复流程是建好的,而它在 已上线的设备上会被拒绝,原因见 recovery.md 第 5 节。 请据此保管凭据。

status: shipped — evidence: mica-core:apid/openapi.json, docs/design/access.md