首次启动、离线配置与认领设备
Mica OS 设备必须在零外部输入的情况下抵达完全可用状态——没有 DHCP 服务器、没有 DNS,甚至可能没有网线。这个性质是设计出来的,不是碰巧。本页讲首次启动自己 做了什么、完全没有网络的设备走哪条离线路径,以及设备如何从“未认领”变成 你的。
1. 设备自己做的事
Section titled “1. 设备自己做的事”从空 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
2. 找到设备
Section titled “2. 找到设备”- 在 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
3. 离线路径:配置文档
Section titled “3. 离线路径:配置文档”对于没有可控网络的设备,或必须开箱即配好的设备,配置手段是配置文档:
一个名为 mica-provisioning.toml 的 TOML 文件,放在介质文件系统的根目录,
在首次启动过程中被读取一次,并在其他一切之前应用。
**先读这一段,因为这里最常被误判为“功能坏了”:配置文档只在设备还没有
管理员凭据时才被采纳。**设备一旦被认领——通过 setup,或通过更早的一份
文档——介质上提供的文档就会以 already-claimed 被拒绝,上面的内容一样都
不会应用。**已经上线的设备不能用 U 盘重新配置。**正是这条规则让一个不带
签名的传输通道是安全的,它不是一个需要绕过去的缺陷:重新配置已认领的设备
走的是带认证的 API。往运行中的设备里插卡却什么都没发生的操作者,看到的是
这条规则,不是一次失败。
两条传输通道
Section titled “两条传输通道”| 通道 | 文件放哪 | 何时被读 |
|---|---|---|
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
4. 认领设备
Section titled “4. 认领设备”认领就是“未认领 → 已认领”的那次转变,判定设备在哪一侧的唯一事实是管理员 凭据是否存在。能创建第一个凭据的通道正好两条:
- Setup——第一次访问
/_ui/,API 客户端则是POST /api/v1/setup。 管理员密码由你选择;该路由建立浏览器会话,并为自动化铸出一枚一次性 bearer token。对已认领的设备再调一次 setup 会以already_configured被拒绝,且不写入任何东西。 - 配置文档——第 3 节。密码来自介质。
从认领开始,每一次管理读写都需要认证。会话与 token 模型见
api.md,接下来配置什么见
configuration.md。GET /api/v1/claim 向已认证的调用方
回答是哪条通道、在什么时候认领了这台设备。
轮换约束,以及它没有做的事
Section titled “轮换约束,以及它没有做的事”由配置文档认领的设备持有的是一个 bootstrap 秘密:它以明文躺在一份设备
故意不去擦除的介质上,而同一份文档可能被写进一整批卡。因此这类认领会置上
rotationRequired。在它被解除之前,设备服务所有读取,但对每一次已认证的
写操作返回 409 rotation_required——例外只有登录、读取原因,以及
POST /api/v1/actions/change-password 这一个能解除它的动作。通过 setup
认领则不会置这个标志:那个密码是调用方在认领当刻选定的,从未被写在设备
能够推理的任何地方。
这个约束是“首次登录”,不是经过的时间,也没有任何东西在倒计时。一台 已认领但从未被登录过的设备,其 bootstrap 凭据无限期有效——一台带着卡 下线、又在仓库里躺了一年的单元,开箱那天握着的仍是同一个可用密码。这是 故意的:这台设备不会拿自己的时钟去执行任何期限,因为未认领的设备恰恰就是 没有同步时钟的设备,而一个关闭时里面没人的窗口只会留下一台谁也进不去的 设备。**把“强制轮换”读成“凭据会自己失效”的读者,规划的是一个并不存在的 暴露窗口。**在首次登录之前限制这个暴露的,是对介质的物理保管,没有别的。
认领不是的两件事
Section titled “认领不是的两件事”- **它不是 SSH 凭据。**SSH 保持关闭,直到一位已认证的管理员启用它并装入 公钥——访问模型见 security.md。
- **它今天无法由设备本身恢复。**在现有的任何板卡上,丢失管理员凭据和全部 授权公钥就意味着没有软件路径能回到设备里。凭据恢复流程是建好的,而它在 已上线的设备上会被拒绝,原因见 recovery.md 第 5 节。 请据此保管凭据。
status: shipped — evidence:
mica-core:apid/openapi.json,docs/design/access.md