Tailscale 如何在不同操作系统上加密节点状态

Tailscale 如何在不同操作系统上加密节点状态

状态文件包含节点身份与私钥。Tailscale 用对称加密保护落盘内容,再借助 TPM、Keychain 和系统存储保护加密密钥;它能提高节点克隆门槛,但无法消除已被控制进程的风险。

Tailscale 通过对称加密保护状态文件,并用平台能力保护密钥;图中区分仅磁盘读取与运行时控制的威胁边界。
加密磁盘状态,与运行时信任分开考虑。未完纪编辑整理、Codex 绘制;原创示意,非运行结果。

状态文件为什么值得单独加密

Andrew Lytvynov 在 2025 年 8 月介绍了 Tailscale 1.86 的节点状态加密。它的目的,是让攻击者更难把一台设备的身份复制到另一台机器,也更难篡改客户端的持久设置。

客户端需要保存的状态不只有偏好选项,还包括用于与协调服务器建立 Noise 连接的机器私钥、各 tailnet 的 WireGuard 节点私钥、Tailnet Lock 私钥,以及出口节点、自动更新等设置。私钥关系到“这台设备是谁”,一旦被复制,攻击者可能在别处冒充原节点。

先区分窃取磁盘与控制进程

网络传输本身已经由协议加密保护,给磁盘状态加密并不是为了再次解决同一类被动监听问题。它针对的是另一条路径:攻击者取得了读取本地文件的能力。

这些状态文件原本就只允许 root 读取;Windows 上相应权限属于 Administrators。若攻击者拿到明文状态文件,再把它放到另一台机器,协调服务器可能把这看成原设备换了网络、取得了新 IP。这就是文中所说的“节点克隆”。

只要攻击者仍持续控制原机器并能以 root 执行代码,就可以借原节点发起请求。状态加密更直接的收益,是在入侵已经被清除之后,让此前窃走的文件更难继续作为独立身份使用。

原文明确列出两类可降低风险的情形:只能以高权限读取磁盘、不能任意执行代码的漏洞;以及扫描文件寻找凭据,却没有专门解密 Tailscale 状态逻辑的简单窃密程序。它不防御读取进程内存的攻击,因为解密后的密钥在运行时仍需使用;也不防御能以 root 调用解密逻辑的攻击者。

共同方案:加密状态,再保护加密密钥

Tailscale 使用对称密钥加密状态内容,随后让操作系统与硬件保护这把密钥。困难在于,操作系统之间没有一个通用接口,所以同一安全目标要分别实现。

Windows 与 Linux:借 TPM 封存密钥

TPM 是保护密码材料的硬件或固件组件。作者比较了三种办法:

  • 直接用 TPM2_Create 封存状态数据,但该路径容纳的数据量约为 128 字节,状态文件通常更大。
  • 使用 TPM 的 TPM2_EncryptDecrypt2 对称加密能力,但该功能并非所有实现都具备。
  • 在 TPM 外生成对称密钥,用它加密状态文件,再让 TPM 封存这把较小的密钥。

Tailscale 选择第三种,以取得较广的兼容性。原文使用 secretbox,需要 32 字节密钥和 24 字节 nonce。每次加密生成新的 nonce,封存材料、nonce 和密文被一起组织为 JSON。文件里的 Private 字段是 TPM 输出的封存材料,不是可直接使用的明文私钥。

Linux 上优先访问 /dev/tpmrm0,不可用时才尝试 /dev/tpm0。前者由内核为多个进程复用 TPM 资源;后者通常只能同时供一个进程访问。能用资源管理器接口时,优先使用它更合适。

Apple:把状态字段放进 Keychain

在 macOS、iOS 和 tvOS 上,Tailscale 把各状态字段作为 Keychain 的密码条目存储,名称以 tailscale- 开头。系统负责相应的加密与访问控制。

作者特别区分了传统的文件式 Keychain 和与用户登录会话关联的 Keychain。多数 Apple 客户端可使用后者,并通过 kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly 约束可用性和迁移范围。

编辑说明:这个常量表达的是设备首次解锁之后可访问、且限本机的存储类别,不能简化成“只在每次屏幕解锁期间可读”。原文也强调不把这些身份状态随 iCloud 备份迁移。

macOS 独立发行版使用系统扩展接入网络栈。系统扩展不能使用用户 Keychain,因此改用文件式的 System Keychain,并需要不同于其他 Apple 客户端的处理逻辑。

Android:系统加密存储与备份排除

原文描述 Android 使用 EncryptedSharedPreferences 加密状态,借助系统能力保护密钥。备份同样需要处理:Tailscale 将整个应用排除在备份之外,以避免不合适的身份迁移。这里说明的是该文记录的客户端实现,不是建议所有新 Android 项目无条件选择同一个 API。

1.86 以前如何保存

Android 和 Apple App Store 发行的客户端早已默认加密状态。macOS 独立发行版曾因系统扩展不能访问用户 Keychain,将 root 拥有的状态文件保存在磁盘;1.86 引入 System Keychain 路径,迁移在 1.86.0 出现过问题,作者记载其在 1.86.2 得到修正。

Windows 与 Linux 过去主要依赖严格文件权限。作者承认,取得这些权限的攻击者通常已经能造成许多其他破坏,但加密仍能提高“拿到文件就走”的攻击成本。

为什么不让硬件一直持有所有协议私钥

TPM、Secure Enclave 和 Android Keystore 可以通过不透明句柄提供某些密码操作,让应用不必看到原始密钥。但其支持的算法及操作不能随意替代现有协议要求,广泛支持的 RSA、ECDSA 也不是 WireGuard 密钥的直接替换品。

这里需要纠正原文的一处概括:原文把这些密钥统称为 Ed25519。WireGuard 的官方协议说明明确列出 Curve25519 ECDH;不应把它与 Ed25519 签名算法混为一谈。本文因此保留“硬件算法支持与协议要求存在约束”的结论,而不照搬“全部是 Ed25519”的表述。

启用入口与版本变化

在 1.86 发布时,新机制尚属 Alpha,Windows、Linux 和 macOS 独立版没有一律默认启用。作者担心状态迁移错误会让节点像新安装一样丢失身份,也提到有人把已批准的状态烘焙进虚拟机或容器镜像,实际依赖节点克隆。

这段是历史背景。当前官方配置文档给出了更具体的版本区分:1.90.2 至 1.92.4 在所有支持的平台默认启用;1.92.5 及以后,Windows、Linux 需要选择启用,其他受支持平台默认启用。Linux 与 Windows 还要求可正常工作的 TPM 2.0。

原文的入口如下,实际配置应结合安装版本:

平台 配置方式
Android、Apple App Store 版本 默认加密,无需额外操作
Linux 给 tailscaled 增加 --encrypt-state;原文通常在 /etc/default/tailscaled 的 FLAGS 中设置
Windows 使用 EncryptState 系统策略
macOS 独立版 使用 EncryptState 系统策略;原文还给出了下面的本地命令
defaults write ~/Library/Preferences/io.tailscale.ipn.macsys.plist EncryptState true

重启 Tailscale 后,客户端会迁移现有状态。管理控制台中节点的 node:tsStateEncrypted 属性可用于确认状态,也可用于设备姿态条件。关闭该保护会把状态迁回原先明文形式,不能把“可以撤回设置”理解为没有安全代价。

把恢复路径也纳入部署

当前官方文档还说明,解密需要同一个 TPM。固件故障、TPM 复位或设备变化可能导致 failed to unseal state file,从而使客户端无法启动。配置前应确认独立管理通道,避免把唯一的远程连接寄托于正在改变存储方式的节点。

本文没有执行配置、重启客户端或读取任何密钥。原作者在结尾提出未来逐步默认启用的计划,本文以上述当前文档补注替代对未来的推测;安全边界仍然是保护落盘身份,而非保证已被完全控制的主机可信。

来源、署名与版本说明

原作者:Andrew Lytvynov;来源:Tailscale Blog,2025 年 8 月 12 日。Tailscale 原文页面未标明开放内容许可证;本文保留作者、来源与编辑修正说明。

原文发表于 Tailscale Blog,2025-08-12;© Tailscale Inc.。原页面未标明开放内容许可证。

核对日期:2026-10-08。主文回顾 Tailscale 1.86 的设计;补核当前官方文档:1.90.2—1.92.4 所有受支持平台默认启用,1.92.5 及以后 Windows/Linux 改为选择启用。不要把 2025 年 Alpha 状态当作当前默认值。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容