使用 CGNAT 的站点到站点 VPN

使用 CGNAT 的站点到站点 VPN

如果我把这篇文章发错了地方,请见谅。如果我应该把这篇文章移到另一个 SE 网站,请告诉我。继续讲故事……

我家里的 ISP 有时(但不是经常)会强迫我们通过 CGNAT,但我需要以可靠的方式远程访问本地设备(只要首先有互联网连接;没有办法避免这个要求 :) )。在切换 ISP 之前(旧 ISP 总是给我相同的公共 IPv4 地址),我可以使用 OpenVPN 来完成这件事。

既然 CGNAT 已经成为现实,OpenVPN 就不再是远程连接我的 LAN 资源的可靠方式了。因此,我正在寻找另一种足够可靠的解决方案(它将使我能够实现一些既需要远程访问安全摄像头,又有用的功能——反向 SSH 服务器到我的工作场所)。

现在进行设置:

  • 在家里,我有一台 Raspberry Pi。如果有必要的话,我会选择 Model 3 B+(我会感到惊讶,但为了完整性,我会提供它)。它位于我自己的路由器后面,该路由器连接到 ISP(PPPoE)。它可以完全访问 LAN 资源。我有一个私有的固定 IPv4(虽然现在有 CGNAT 问题,我考虑删除“固定”要求;无论如何,修复它可能没有以前那么有用)和一个自动(SLAAC,没有隐私扩展)公共路由 IPv6 地址。不能保证每次重新连接时我都会获得相同的 /64(因此 IP 地址会随时间而变化)。
  • 在场外,我有一个 AWS EC2 主机(最小的那个,虽然“免费”,但我认为它不是真正免费的)。我在主机上配置了弹性 IPv4 和 IPv6,并配置了正确的网关(浪费了很多时间,但最终还是成功了)。所以从技术上讲,我可以通过 IPv6 从这里连接到 Pi(假设 Pi 可以使用适当的动态 DNS 服务进行 IPv6 连接),或者通过 IPv4 和 IPv6 从 Pi 连接到 AWS 主机。
  • 在工作中,我有一个高度戒备的网络,我只想对其进行反向 SSH。我可能只需将 AWS 实例用作跳转主机,即可快速解决问题。我的意思是,我无论如何都可以在端口 443 上的 AWS 实例上运行 SSH 服务器。所以这不是什么大问题(端口 22 被工作防火墙阻止了 :( )

我需要两方面的帮助:

  1. 首先,如何设置从我的 Raspberry Pi 到 AWS 主机的直接连接,以便 AWS 主机可以直接访问我的所有 LAN 资源(最终可通过 Raspberry Pi 上的防火墙规则进行自定义)
  2. 其次,如何确保每次重启 Pi 时此支持都会自动启动(我倾向于经常重启它,断电也会导致意外重启)。

请注意,我确实有一个解决方法,但它真的很糟糕。每次我获得 CGNAT IP 地址时,都需要通过 TP-Link 云服务多次重新启动我的路由器,直到我获得一个公共 IP 地址。然后我的 ISP 就可以提供适当的动态 DNS 服务,这样我就可以解析到我的公共地址(或者我的私人地址,如果我确实获得了 CGNAT;但这没什么用)。我真的希望能够忘记这样的解决方法。

答案1

我最终还是自己弄明白了。我遵循了通常的教程:

  • 首先,在服务器(EC2 实例)和客户端(CGNAT 后面的 Raspberry Pi)上安装 OpenVPN,并且仅在服务器上安装 Easy-RSA。
  • 然后,使用 Easy-RSA 生成一些东西(信息直接取自 OpenVPN 社区页面上的教程):
    • 首先,在文件“vars”中配置变量。默认设置很好用,但还是建议更改它们。
    • 将 openssl-1.0.0.cnf 复制到 openssl.cnf(其他版本也可能有效)。
    • 运行 ./clean-all(这将删除任何预先存在的密钥和额外的配置,以便从一张白纸开始)。
    • 运行 ./build-ca(这将生成 keys/ca.crt 和 keys/ca.key;后者必须受到保护——一旦您确定不需要更新配置来添加更多客户端,您就可以将其粉碎。前者是必须保留的证书)
    • 运行 ./build-key-server 生成服务器密钥对。只有服务器需要这个。
    • 运行 ./build-key 为客户端生成密钥。每个客户端运行一次。我总共只为我的客户端“raspberrypi”运行了一次。生成的文件需要在客户端上复制。
    • 将文件复制到其所属的位置:
      • 服务器和客户端都需要keys/ca.crt。
      • 如果您想添加其他客户端,则需要 keys/ca.key,这是您要保护的主要内容。如果您不需要额外的灵活性,建议您在其上运行“shred”命令或将其移动到已知安全的系统(可以使用气隙)
      • keys/raspberrypi.{crt,key} 属于客户端(在我的情况下,客户端是 raspberrypi,您可以为客户端输入自己的特定名称)并且应该相应地复制到客户端。
      • keys/server.{crt,key} 保留在服务器上。但是,.crt 文件会在每次连接尝试时自动发送,因此无需手动将其复制到客户端。
    • Easy-RSA 部分现已完成。
  • 在服务器端设置 OpenVPN
    • 默认服务器配置很好,只需保存一些更改:
      • 必须更新 ca、cert 和 key 选项以分别指向 ca.crt、server.crt 和 server.key 文件。server.key 文件应该受到保护(0400 权限),尽管我不确定是否真的检查了这一点。
      • 我已经设置了“拓扑子网”。这不是绝对必要的,但却是一件好事。
      • 我已将“服务器”指令更改为另一个私有 IPv4 范围,以确保我不会与另一个 OpenVPN 服务器(来自我的路由器的服务器)发生冲突。毕竟我稍后会进行一些静态路由,因此范围一定不能重叠。
      • client-config-dir client(将“客户端”子文件夹设置为特殊并包含客户端特定的配置;这对于路由很重要)
      • 客户端到客户端我继续,再次以便路由正常工作。
      • 我在两种情况下都注释掉了“tls-auth ta.key 0”选项;这确实会产生警告,但我不需要额外的安全性。一旦我弄清楚了它的工作原理,我可能会在将来取消注释它。然而,为了安全起见,强烈建议使用此选项。
      • 我添加了一条声明push "route 172.31.0.0 255.255.240.0",将路由推送到 AWS 的私有网络并指向我的 Raspberry Pi。
    • 此外,对于客户端,您需要有一个文件客户端/raspberrypi(再次基于客户端名称),其中包含iroute 192.168.1.0 255.255.255.0(以便路由从 AWS 实例到 Pi 和家庭网络工作。
  • 客户端也需要设置
    • 设置远程地址。我只是将我的弹性 IP 地址放在我的 AWS 实例上,因为除非我弄乱它,否则它不会改变。
    • 设置 ca、cert、key(ca 到 ca.crt、cert 到 raspberrypi.crt、key 到 raspberrypi.key)指令。
    • 注释掉 tls-auth 指令,就像在服务器上一样。这必须与服务器匹配。
  • 启用 SystemD 服务(这负责在启动时启用隧道)。在服务器上,您systemctl enable openvpn@server; systemctl start openvpn@server假设您的配置文件是 /etc/openvpn/server.conf。您不能将其用于子文件夹。在客户端上,情况相同,只是因为它是您输入的文件名的 client.conf openvpn@client

现在我剩下要做的就是进行一些端口转发,但这不是这个问题的主题。

相关内容