语境
我正在尝试了解如何为用户和网络组设置最佳 VPN 访问。情况如下网络示意图:
Site A
代表主网络- 我可以控制这个网络中的所有设备
- 该网络通过 连接到互联网
Router A
,它具有静态公共 IP 和与之关联的域。
Site B
代表主网络用户可能携带其设备并连接到互联网的任何外部网络(公共、家庭、蜂窝热点……)。- 我无法控制此网络中的设备,但用户设备除外(例如
Endpoint B
) - 我们可以假设
Router B
配置了动态 IP、NAT 和防火墙,不允许任何未建立的传入连接
- 我无法控制此网络中的设备,但用户设备除外(例如
Site C
和Site D
代表包含我控制的一台或多台设备的第三方网络(Endpoints C1
、C2
和D1
、D2
)- 这些设备通过交换机相互连接
- 这些设备是无人值守的,应该可以全天候使用,无需本地干预
- 每个网络的其中一个设备(
Edpoint C1
用于Site C
和Endpoint D1
用于Site D
)通过路由器连接到互联网。 - 我们可以假设路由器配置了动态 IP、NAT 和防火墙,不允许任何未建立的传入连接。
- 不同辅助网络上的设备可以(并且将)配置为使用相同的子网(例如
Site C
和中的端点Site D
都使用192.168.254.0/24
),网络之间可能会发生 IP 冲突,因此需要将它们分开
端点主要是Linux(尤其是辅助网络中的端点),但也有一些Windows客户端。
目标
我想达到以下目标(希望通过单一解决方案,但如果不可能,也可以使用单独的解决方案):
连接主网络(
Endpoint B
)之外的授权客户端应该能够连接到它(例如与 进行通信NAS
)。授权客户端,无论是在
Endpoint A1
主网络内部()还是在主网络外部(Endpoint B
)都应该能够连接到辅助网络(Site C
或Site D
)- 每个用户都被授权连接到某些次要网络,而不必连接到所有网络(例如,
User 1
可以连接到Site C
和Site D
,而User 2
只能连接到Site D
)。 - 授权取决于用户(即设备),而不是设备的连接位置(例如,可以从或从
User 2
连接到)。Site D
Site A
Site B
- 单个用户可被授权访问一个或多个辅助网络,但每次只能连接到一个
- 多个用户必须能够同时连接到同一个辅助网络
- 授权(取消)用户连接到特定次级网络(例如
Site D
)不应该要求对次级网络本身的设备进行任何干预(Endpoints D1
例如D2
)
- 每个用户都被授权连接到某些次要网络,而不必连接到所有网络(例如,
解决方案思路
我认为使用任何允许点对站点连接的 VPN 可以轻松解决第 1 点:我正在努力设置 WireguardHost A
并进行端口转发Router A
,据我所知,这足以实现我的第一个目标。
相反,我对如何解决第 2 点有点困惑。我正在探索的想法是:
- 使用
Host A
公开的 viaRouter A
(或直接使用外部专用 VPS)作为中心辐射布局的中心。所有端点都能够连接到它,因为它有一个公共 IP。 - wireguard 的持久 keepalive 选项应该允许辅助网络中的端点穿过 NAT,保持与
Host A
Host A
将为每个辅助网络运行一个 wireguard NIC,每个NIC 映射到不同的端口,并将 IP 从物理 NIC 转发到每个 wireguard NIC- 必须为我想要授权的任何用户网络对生成不同的配置(以及为辅助网络中的端点生成不同的配置)
- 然后,每个用户都可以连接到特定的端口
Host A
,从而连接到特定的辅助网络
我不确定最后这些部分的正确性或细节:这是个好办法吗?还有更好的办法吗?切换到另一个软件(例如 openVPN)是否会更容易?
如果这是可行的方法,是否有任何软件可以简化多个接口和用户凭据的管理?
我主要在寻找免费解决方案,可能是开源/自托管的。
在此先向所有愿意参与讨论的人表示衷心的感谢,即使只是提出最微小的暗示!
答案1
我相信使用 WireGuard 是解决此问题的绝佳方法。
正如您所建议的,您可以使用主机 A 作为网络的中央集线器(或者在具有公共 IP 地址的其他主机上设置专用集线器);WireGuard 的持久保持活动选项将允许入站连接通过隧道传输到连接到它的其他客户端(例如 C1、D1 等)。
但是,您不一定需要在主机 A 上使用多个 NIC——您只需要一个物理 NIC(用于连接到 Internet 的 NIC,例如eth0
)和一个 WireGuard 虚拟网络接口(例如wg0
)。WireGuard 网络中的每个设备都将通过集线器的物理 NIC 将加密数据包发送到集线器,集线器将解密这些数据包并将其重新排队为其 WireGuard 接口的传入数据包。当每个数据包从 WireGuard 接口出现时,您将应用标准防火墙和路由规则来确定如何处理该数据包(通常是通过 WireGuard 接口将其发回,重新加密并发送到另一台设备)。
您可以执行以下操作:
想出一个或多个专用地址块,专门用于您的 WireGuard 网络。例如,假设您决定将地址块用于
10.100.0.0/24
用户设备,将地址块10.200.0.0/20
用于非用户设备。(如果您的所有设备及其需要访问的所有内容都完全支持 IPv6,您可能只想使用 IPv6 地址,以避免地址空间冲突。)从 #1 开始的适当地址块中为每个设备分配一个 IP 地址,并使用该 IP 地址作为
AllowedIPs
集线器的 WireGuard 配置中设备的设置。(对于非用户设备,还要在设置中包含可通过设备访问的其他虚拟地址空间AllowedIPs
。)在每个单独设备的 WireGuard 配置中,使用 #2 中分配的 IP 地址作为其
Address
设置(并指定全部您的 WireGuard 地址在设备AllowedIPs
设置中阻止指向集线器)。在集线器上设置一系列防火墙规则来实现用户授权业务逻辑,使用从 #2 分配的 IP 地址来唯一标识每个设备。(WireGuard 将确保对于接口的每个配置对等体,使用对等体的配置公钥解密的数据包必须具有与对等方的配置设置匹配的源地址
AllowedIPs
——否则数据包将被丢弃。因此,对于从 WireGuard 接口传入的数据包,使用任何防火墙规则,您都可以确保数据包来自具有与AllowedIPs
数据包源地址匹配的设置的特定设备。)为了提供对冲突地址空间的访问(例如,允许访问
192.168.254.0/24
站点 C 和站点 D 中的 LAN 子网),请让您的 WireGuard 设备针对每个此类冲突使用来自专用 WireGuard 地址空间的不同地址,并在充当冲突子网网关的 WireGuard 设备上使用 NAT,将您的 WireGuard 地址空间转换为实际的 LAN 地址。例如,您可以将用作站点 C 中子网
10.200.2.0/24
的虚拟地址空间,并将其用作站点 D 中子网的虚拟地址空间。在端点 C1(您的 WireGuard 网关到端点 C2)上,使用 NAT 转换为;并在集线器上路由到端点 C1。如果使用端点 B 的用户在 Web 浏览器中导航到 ,则该请求将通过您的 WireGuard 网络路由到端点 C1,端点 C1 可以适当地转换请求并将其路由到端点 C2。192.168.254.0/24
10.200.3.0/24
192.168.254.0/24
10.200.2.2
192.168.254.2
10.200.2.0/24
http://10.200.2.2/
举一个具体的例子,有两个设备——端点 B 作为用户 3 的用户设备,端点 C1 上运行着一个 SSH 服务器,并提供对虚拟10.200.2.0/24
网络的访问——集线器的 WireGuard 配置可能如下所示:
# /etc/wireguard/wg0.conf
# local settings for Host A
[Interface]
PrivateKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEE=
Address = 10.200.0.1
ListenPort = 51820
# remote settings for Endpoint B
[Peer]
PublicKey = fE/wdxzl0klVp/IR8UcaoGUMjqaWi3jAd7KzHKFS6Ds=
AllowedIPs = 10.100.1.3
# remote settings for Endpoint C1
[Peer]
PublicKey = jUd41n3XYa3yXBzyBvWqlLhYgRef5RiBD7jwo70U+Rw=
AllowedIPs = 10.200.1.1, 10.200.2.0/24
端点 B(用户 3 的设备)的 WireGuard 配置可能如下所示:
# /etc/wireguard/wg0.conf
# local settings for Endpoint B
[Interface]
PrivateKey = ABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBFA=
Address = 10.100.1.3
# remote settings for Host A
[Peer]
PublicKey = /TOE4TKtAqVsePRVR+5AA43HkAK5DSntkOCO7nYq5xU=
Endpoint = 5.5.5.5:51820
AllowedIPs = 10.100.0.0/24, 10.200.0.0/20
PersistentKeepalive = 25
端点 C1 的 WireGuard 配置可能如下所示:
# /etc/wireguard/wg0.conf
# local settings for Endpoint C1
[Interface]
PrivateKey = CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCGA=
Address = 10.200.1.1
# remote settings for Host A
[Peer]
PublicKey = /TOE4TKtAqVsePRVR+5AA43HkAK5DSntkOCO7nYq5xU=
Endpoint = 5.5.5.5:51820
AllowedIPs = 10.100.0.0/24, 10.200.0.0/20
PersistentKeepalive = 25
您可以在集线器上使用如下的 nftables 规则集来接受来自设备的 WireGuard 连接,并实现用户授权规则:
table inet filter {
# put all your user-authorization rules here
chain device-access-policies {
# allow User 3 to access SSH on Endpoint C1
ip saddr 10.100.1.3 ip daddr 10.200.1.1 tcp dport 22 accept
# allow User 3 to access webserver on Endpoint C2
ip saddr 10.100.1.3 ip daddr 10.200.2.2 tcp dport 80 accept
# deny everything else
reject with icmpx type admin-prohibited
}
chain input {
type filter hook input priority 0; policy drop;
iif "lo" accept
ct state vmap { invalid : drop, established : accept, related : accept }
iifname "eth0" udp dport 51820 accept
}
chain forward {
type filter hook forward priority 0; policy drop;
ct state vmap { invalid : drop, established : accept, related : accept }
iifname "wg0" goto device-access-policies
}
}
在端点 C1 上,您可能有一个如下所示的 nftables 规则集,以盲目接受和转发集线器发送给它的所有内容,并将虚拟10.200.2.0/24
地址空间 NAT 到其本地192.168.254.0/24
子网:
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
iif "lo" accept
ct state vmap { invalid : drop, established : accept, related : accept }
iifname "wg0" accept
}
chain forward {
type filter hook forward priority 0; policy drop;
ct state vmap { invalid : drop, established : accept, related : accept }
iifname "wg0" accept
}
}
table inet nat {
chain prerouting {
type nat hook prerouting priority -100; policy accept;
ip daddr 10.200.2.0/24 dnat ip prefix to 192.168.254.0/24
}
chain postrouting {
type nat hook postrouting priority 100; policy accept;
iifname "wg0" masquerade
}
}