Tailescale工作原理
译者序
有的地方按个人理解,将一些带有外国腔的句子,翻译成了更适合中国人阅读的形式。
正文
人们经常问我们 Tailscale 的工作原理是什么。我们一直没回答这个问题,因为我们一直在改动它!但现在情况已经稳定下来了。
让我们从下到上逐一了解整个 Tailscale 系统,就像我们当初构建它时一样(但会略过一些过程中遇到的曲折)。有了这些信息,你应该能够构建自己的 Tailscale 替代方案……不过你其实不必这么做,因为我们的 节点软件是开源的 ,而且我们还提供 灵活的免费方案 。
数据平面:WireGuard
我们的基础层是日益流行且优秀的开源 WireGuard 软件包(具体来说是用户空间 Go 版本 wireguard-go )。WireGuard 会在您的计算机、虚拟机或容器(WireGuard 称之为“端点”,我们称之为“节点”)与网络中的任何其他节点之间创建一组极其轻量级的加密隧道。
让我们理一下:大多数情况下,VPN 用户(包括 WireGuard 用户)会构建“星型”架构,其中每个客户端设备(例如您的笔记本电脑)都连接到中央“集中器”或 VPN 网关。
星型网络 / 中心辐射网络(hub-and-spoke networks)
这是配置 WireGuard 最简单的方法,因为网络中的每个节点都需要知道它想要直接连接的其他节点的公钥、公网 IP 地址和端口号。如果要完全连接 10 个节点,那么每个节点都需要知道 9 个对等节点,或者说 90 个独立的隧道端点。在星型网络中,你只需要一个中心枢纽节点(hub)和 9 个外围节点(通过“辐条”(spoke)连接它们),这要简单得多。枢纽节点通常具有静态 IP 地址,并在其防火墙上打开一个端口,以便所有人都能轻松找到它。然后,它可以接受来自其他 IP 地址节点的传入连接,即使这些节点本身位于防火墙之后,就像客户端-服务器互联网协议通常做的那样。
星型网络架构虽然效果不错,但也存在一些缺点。首先,大多数现代企业并没有一个固定的中心节点。它们通常拥有多个办公室、多个云数据中心、区域或虚拟专用网络 (VPC) 等等。在传统的 VPN 设置中,企业配置一个 VPN 集中器,然后在不同位置之间建立二级隧道(通常使用 IPsec)。因此,远程用户首先会到达 VPN 集中器,然后他们的流量会被转发到位于另一个位置的最终目的地。
这种传统方案难以扩展。首先,远程用户可能离 VPN 集中器很远,也可能很远;如果距离较远,连接延迟就会很高。其次,他们想要访问的数据中心可能也离 VPN 集中器很远;如果距离较远,同样会面临高延迟。想象一下这种情况:一位纽约的员工试图通过公司位于旧金山总部的 VPN hub 或 BeyondCorp 代理(Google 的零信任网络)连接到位于纽约的服务器。
幸运的是,WireGuard 有所不同。还记得我们之前说过它会创建“一组极其轻便的隧道”吗?这些隧道非常轻,我们可以轻松地构建 multi-hub:
现在唯一的问题是,每个数据中心都需要一个静态 IP 地址、一个开放的防火墙端口和一组 WireGuard 密钥。当我们添加新用户时,我们需要将他的公钥分发给所有 5 个服务器。当我们添加新服务器时,我们需要将其公钥分发给每个用户。但我们能做到,对吧?这工作量大约只有单个中心节点的五倍,不算太大。
网状网络(mesh networks)
综上,我们上面讨论的就是星型网络,在 WireGuard 的帮助下搭建这么一个网络并不难,虽然有点繁琐,而且我们还没有真正讨论过密钥管理的安全实践(见下文)。
然而,星型网络架构存在一个根本性的缺陷:它不允许各个节点之间直接通信。如果你和我一样年纪大了,你 肯定还记得以前电脑可以直接交换文件,无需先上传到云端再下载 。信不信由你,互联网以前就是这样运作的!可惜的是,开发者们已经不再开发点对点应用了,因为现代互联网的架构几乎是偶然地演变成了这种星型设计:大型云服务提供商位于中心位置,并收取一定服务费用。
还记得那些“极其轻量级”的 WireGuard 隧道吗?如果能将所有节点直接连接到所有其他节点,岂不是很棒?这就是网状网络:
这样就非常优雅——至少,它能让你设计出优雅的 P2P 应用——但实现起来却很棘手。如上所述,一个 10 节点的网络需要 10 x 9 = 90 个 WireGuard 隧道端点配置;每个节点都需要知道自身的密钥以及另外 9 个密钥,而且每次密钥轮换或添加/删除用户时,每个节点都必须更新这些配置。
而且,所有节点都必须以某种方式找到彼此——用户设备很少有静态 IP 地址——并且每当其中一个节点移动时,都需要重新连接。
此外,你不可能轻易地为每个节点打开一个防火墙端口,以允许在咖啡馆、酒店或机场等场所进行传入连接。
然后,在你完成所有这些操作之后,如果你的公司有合规性要求,(你作为企业安全主管的角色)你需要能够以某种方式阻止和审计所有节点之间的流量,即使这些流量不再全部通过你可以控制的中心位置(即这个网络看起来已经去中心化了,流量不再受你管控)。
在这种 P2P 通信场景下,Tailscale 也能实现像“中心化网关”一样的管控能力!我们来聊聊它是如何做到的。这部分内容有点复杂。
控制平面:秘钥交换与协调
OK,假设我们已经让 WireGuard 连接成功了,而且可以同时连接多个设备。它无与伦比的可靠性和效率让我们惊叹不已。现在我们想构建一个网状网络——让所有设备彼此连接。
防火墙和动态 IP 地址都很复杂,所以我们暂时先忽略它们(下文会讨论)。现在,假设全世界都使用静态 IP 地址(我们甚至可以说……IPv6?),并且防火墙不存在,或者端口开放非常容易。那么如何将所有 WireGuard 加密密钥(一种简化且更安全的“证书”)传输到每个设备上?
为此,我们使用 开源的 Tailscale 节点软件 。它与我们称之为“协调服务器”(在我们的例子中是 login.tailscale.com)的服务器通信——本质上,这是一个用于存放公钥的共享仓库。
慢着,我们这不是又回到星型拓扑结构了吗?不完全是。所谓的“控制平面”确实是星型拓扑结构,但这并不重要,因为它几乎不承载任何流量。它只负责交换一些很小的加密密钥并设置策略。而数据平面则是一个网状网络。
(我们喜欢这种集中式与分布式相结合的混合模型:公司和团队通常希望拥有集中控制权,但又不希望数据出现集中瓶颈。传统的 VPN 集中器将两者都集中化,从而限制了性能,尤其是在压力较大的情况下。相反,Tailscale 的数据处理能力会随着节点数量的增加而扩展。)
原理步骤大概是这样的:
- 每个节点都会为自己生成一个随机的公钥/私钥对,并将公钥与其身份关联起来(详情参见下文的 "登录")
- 节点联系协调服务器,发送其公钥给服务器,以及一些元数据(比如该节点当前位置、所在的域等)
- 该节点下载其域内的其他节点的公钥和地址列表
- 节点使用这些公钥集配置其 WireGuard 实例
注意,节点私钥永远只有节点自己知道,不能泄露给其它节点(包括协调服务器)。这一点至关重要,因为在协商 WireGuard 会话时,私钥是唯一可能被用来冒充该节点的信息。因此,只有相互通信的两个节点才能对该 WireGuard 会话的数据包进行加密或解密。务必牢记这一点:Tailscale 节点连接采用端到端加密(这属于一种“ 零信任网络 ”)。
因此,与星型网络不同,明文数据包不会在线路上传输,中间人节点无法看到你们这条连接上传输的是什么内容(除了 子网路由 外。子网路由是 Tailscale 提供的功能,感兴趣可以点开链接了解)。
登录与身份认证(2FA)
但我们忽略了一个细节。协调服务器如何知道应该将哪些公钥发送给哪些节点?公钥顾名思义是公开的,因此即使泄露给任何人,甚至发布到公共网站上,也不会造成任何危害。这与带有 authorized_keys 文件的 SSH 服务器的情况完全相同;你无需对你的 SSH 公钥保密,但仍然需要谨慎选择要放入 authorized_keys 文件中的公钥。
身份验证方式有很多种。一种显而易见的方法是构建用户名+密码系统,也称为预共享密钥 (PSK)。要设置节点,请连接到服务器,输入您的用户名和密码,然后上传您的公钥,并下载您的帐户或域内其他帐户发布的公钥。如果您想更进一步,可以添加双因素身份验证 (2FA,也称为 MFA),例如短信验证码、Google Authenticator、Microsoft Authenticator 等。
系统管理员还可以为您的机器设置“ 机器证书 ”——一种永久(或半永久)属于设备而非用户帐户的密钥。这样,即使拥有正确的用户名和密码,不受信任的设备也无法向协调服务器发布新密钥。
Tailscale 运营着一个基于这些概念的协调服务器。但是,我们并不自行处理用户身份验证。相反,我们始终将身份验证外包给 OAuth2、OIDC(OpenID Connect)或 SAML 提供商 。常用的提供商包括 Gmail、G Suite 和 Office 365:
身份提供商会维护您域中的用户列表、密码、双因素身份验证 (2FA) 设置等信息。这样就避免了为 VPN 再单独维护一份用户帐户或证书——您可以继续使用之前已经在 Google Docs、Office 365 和其他 Web 应用设置的身份验证。此外,由于您所有的私有用户帐户和登录数据都托管在其他服务上,Tailscale 能够在提供高度可靠的中央协调服务的同时,最大限度地减少用户个人身份信息 (PII) 的持有量(即使 Tailscale 被黑了,你的账号密码依然是安全的)。
正因如此,Tailscale 域名可以在您登录后立即激活。例如,如果您从 App Store 下载我们的 macOS 或 iOS 应用并登录您的帐户,系统会立即为您的域名创建一个安全的密钥存储箱,并允许您与该帐户或域名中的其他设备(例如 Windows 或 Linux 服务器)交换公钥。
然后,正如我们刚才看到的,公钥被下载到每个节点,每个节点配置 WireGuard 与其他节点建立超轻量级隧道,瞧!两分钟内就构建了一个网状网络!
译者对上面内容的总结:
- WireGuard 负责底层的“干活”(加密传输)。
- 身份提供商(Google/Office) 负责“认证”(你是谁)。
- Tailscale 负责中间的“调度”(把公钥和 IP 准确发给对的人)。
NAT 穿透
……但我们还没完全结束。回想一下,前面我们假设每个节点都有一个静态 IP 地址,并且防火墙端口已打开,允许 WireGuard 流量通过。但在现实生活中,这种情况不太可能发生。总之,最坏的情况大概是这样的:
这是两个 NAT,没有开放端口。过去,人们会建议你在防火墙上启用 UPnP,但这很少奏效,即使有效,通常也会过于 强大而危险,直到管理员将其关闭。
总而言之,目前我们只需要知道 Tailscale 使用基于互联网 STUN 和 ICE 标准的多种先进技术,但无需用户去动防火墙或者 NAT 路由器的配置,也能让这些连接正常工作,即使您认为这根本不可能。
这块内容是最硬核的部分,正是因为实现了强大的 NAT 穿透,Tailscale 才能这么好用。篇幅有限,具体参考另一篇:NAT 穿透的工作原理。
加密 TCP 中继(DERP)
还有一点!有些网络会彻底屏蔽 UDP,或者设置极其严格,以至于根本无法使用 STUN 和 ICE 协议进行通信。针对这种情况,Tailscale 提供了一个由 DERP (Designated Encrypted Relay for Packets) 服务器组成的网络。这些服务器的作用与 ICE 标准中的 TURN 服务器 相同,但它们使用 HTTPS 流和 WireGuard 密钥,而不是过时的 TURN。
通过 DERP 进行中继的流程如下:
(尽管上图看起来可能并非如此,但我们确实拥有一个全球分布式的中继服务器网络。它不仅仅局限于美国)
请记住,Tailscale 私钥永远不会离开生成它们的节点;这意味着 DERP 服务器永远无法解密您的流量。它只是盲目地将已加密的流量从一个节点转发到另一个节点。这与互联网上的任何其他路由器类似,只不过使用了稍微复杂一些的协议来防止滥用。
许多互联网用户都好奇 WireGuard 是否像 OpenVPN 一样支持 TCP。目前 WireGuard 本身并未内置 TCP 功能,但开源的 Tailscale 节点软件包含 DERP 支持,从而实现了这一功能。未来,WireGuard 可能会重构代码,将此功能集成到自身。(Tailscale 已经为 WireGuard-Go 贡献了多项修复和改进。)我们还开源了 (非常简单的)DERP 中继服务器代码 ,方便您了解其工作原理。
番外篇:访问控制列表和安全策略
TODO

浙公网安备 33010602011771号