如果您想自己管理 SSH 密钥,可以使用 Cloudflare Tunnel 从服务器到 Cloudflare 的全球网络创建安全的、仅出站的连接。这需要在服务器(或私有网络内的任何其他主机)上运行 cloudflared 守护进程。拥有被 SSH 服务器信任的 SSH 密钥的用户,可以通过在其设备上安装 Cloudflare One Client 并加入您的 Zero Trust 组织来访问该服务器。用户可以直接 SSH 到服务器的私有主机名(例如,ssh.internal.local)。您可以使用网络级 Gateway 策略来控制对服务器的访问,而不是使用应用级的 Access 策略。
- 一个 Cloudflare Zero Trust 组织
- 在用户设备上安装了 Cloudflare One Client
- 设备已注册到您的 Zero Trust 组织中
本示例将逐步介绍如何在 Google Cloud Platform (GCP) 虚拟机 (VM) 上设置 SSH 服务器,但您可以使用任何支持 SSH 连接的机器。如果您已经配置了 SSH 服务器,可以跳到步骤 2。
在创建 VM 实例之前,您需要创建一个 SSH 密钥对。
-
打开终端并输入以下命令:
ssh-keygen -t rsa -f ~/.ssh/gcp_ssh -C <username in GCP> -
出现提示时输入您的密码短语。需要输入两次。
将生成两个文件:包含私钥的
gcp_ssh和包含公钥的gcp_ssh.pub。 -
在命令行中输入:
cat ~/.ssh/gcp_ssh.pub -
复制输出。在 GCP 中创建 VM 实例时将使用此内容。
既然已创建 SSH 密钥对,您就可以创建 VM 实例了。
- 在您的 Google Cloud 控制台 ↗中,创建一个新项目 ↗。
- 转到 Compute Engine(计算引擎)> VM instances(VM 实例)。
- 选择 Create instance(创建实例)。
- 命名您的 VM 实例,例如
ssh-server。 - 向下滚动到 Advanced options(高级选项) > Security(安全) > Manage access(管理访问)。
- 在 SSH Keys (manually generated)(手动生成的 SSH 密钥) 下,选择 Add item(添加项) 并粘贴您创建的公钥。
- 选择 Create(创建)。
- 您的 VM 实例运行后,打开 SSH 旁的下拉菜单并选择 Open in browser window(在浏览器窗口中打开)。
本节介绍如何为您的 SSH 服务器创建新的 Cloudflare Tunnel。您可以为可通过 cloudflared 主机访问的私有网络上的所有服务重复使用相同的隧道。
-
登录 Cloudflare 仪表板,转到 Networking(网络) > Tunnels(隧道)。
Go to Tunnels ↗ -
选择 Create a tunnel(创建隧道)。
-
为您的隧道输入名称。我们建议选择能够反映您希望通过此隧道连接的资源类型的名称(例如,
enterprise-VPC-01)。 -
选择 Create Tunnel(创建隧道)。
-
选择您的操作系统,然后复制安装命令并在您的源服务器的终端上运行。
-
等待隧道连接。连接建立后,选择 Continue(继续)。
主机名路由允许您直接 SSH 到 ssh.internal.local,而无需管理静态 IP 路由。当您的 SSH 服务器具有未知或临时 IP 地址(例如由云提供商配置的动态基础设施)时,主机名路由特别有用。
主机名路由的工作原理
当您在 Cloudflare Tunnel 中创建主机名路由时:
- 用户 SSH 到您的私有主机名(例如,
ssh [email protected])。 - Gateway 将主机名解析为来自 CGNAT 范围的 初始解析 IP。
- 流量通过 WARP 隧道路由到 Cloudflare。
- Gateway 网络策略评估该连接。
- Cloudflared 将连接代理到您的 SSH 服务器的私有 IP。
如果您没有配置私有 DNS 解析器,或者更愿意 SSH 到 IP 地址,请跳至步骤 4。
要将主机名路由添加到您的隧道:
-
转到 Networking(网络) > **Tunnels(隧道)**并选择您的隧道。
-
在 **Routes(路由)**选项卡上,选择 Add route(添加路由),然后选择 Private hostname(私有主机名)。
-
输入您的 SSH 服务器的主机名(例如,
ssh.internal.local)。主机名格式限制
- 字符限制:必须少于 255 个字符。
- 支持的通配符:允许使用单个通配符(
*),且它必须代表一个完整的 DNS 标签。 示例:*.internal.local - 不支持的通配符:不支持以下通配符格式:
- 部分通配符,例如
*-dev.internal.local或dev-*.internal.local。 - 中间的通配符,例如
foo*bar.internal.local或foo.*.internal.local。 - 主机名中的多个通配符,例如
*.*.internal.local。
- 部分通配符,例如
- 通配符修剪:前导通配符(
*)会被修剪掉,并假定有一个隐式的点(.)。例如,*.internal.local会保存为internal.local,但会匹配通配符级别的所有子域名(涵盖foo.internal.local,但不涵盖foo.bar.internal.local)。 - 点修剪:允许前导点和尾随点(
.),但会被修剪掉。
-
选择 Save(保存)。
当 Gateway 收到针对您的私有主机名的请求时,它必须将该主机名解析为您的 SSH 服务器的私有 IP 地址。
默认情况下,cloudflared 使用在其主机上配置的私有 DNS 解析器(例如,Linux 中的 /etc/resolv.conf)。如果运行 cloudflared 的机器已经可以使用本地系统解析器将 ssh.internal.local 解析为其私有 IP,则无需进一步配置。您可以跳到步骤 3.3。
验证本地 DNS 解析
要检查 cloudflared 是否可以成功解析 ssh.internal.local,请从 cloudflared 主机运行以下命令:
nslookup ssh.internal.localServer: 127.0.2.2
Address: 127.0.2.2#53
Non-authoritative answer:
Name: ssh.internal.local
Address: 10.2.0.3输出应包含服务器的私有 IP 地址(GCP VM 的内网 IP)。如果主机名解析失败:
- 确保您的私有 DNS 解析器具有将
ssh.internal.local指向服务器私有 IP 的记录。 - 在 GCP 中,您可能需要将私有区域添加到 Cloud DNS ↗,以便使用您的私有 DNS resolver 解析
internal.local。
如果您需要 cloudflared 使用与主机默认解析器不同的特定内部 DNS 服务器,您必须通过 IP/CIDR 路由将该 DNS 服务器显式连接到 Cloudflare。您还需要配置 Gateway 解析器策略以将查询路由到该特定专用 DNS 服务器。
-
要为 DNS 服务器创建 IP/CIDR 路由:
-
转到 Networking(网络) > Routes(路由)。
Go to Routes ↗ -
选择 Add CIDR route(添加 CIDR 路由)。
-
输入您内部 DNS 解析器的私有 IP 地址。
-
选择连接到该 DNS 服务器所在网络的 Cloudflare Tunnel。
-
选择 Create(创建)。
-
-
要创建解析器策略:
- 转到 Traffic policies(流量策略) > Resolver policies。
- 选择 Create a policy(创建策略)。
- 创建匹配私有主机名的表达式:
选择器 运算符 值 Host in ssh.internal.local - 在 Configure custom DNS resolvers 下,输入您内部 DNS 服务器的私有 IP 地址。
- 从下拉菜单中,选择
- Private路由选项以及分配给您在上一步中选择的隧道的虚拟网络。 - 选择 Create a policy(创建策略)。
要连接到 私有主机名,必须配置 Cloudflare One Client 以将以下流量转发到 Cloudflare:
- 初始解析的 IP(CGNAT 范围:
100.64.0.0/10) - 针对您的私有主机名的 DNS 查询
在您的 WARP 设备配置文件中,配置分流隧道(Split Tunnels),使 初始解析的 IP 通过 WARP 隧道进行路由。配置取决于您的分流隧道模式:
- 排除模式:从您的分流隧道列表中删除
100.64.0.0/10。我们建议重新添加未明确用于 Cloudflare One 服务的 IP 范围。这可以减少与可能使用 CGNAT 地址空间的现有私有网络配置发生冲突的风险。 - 包含模式:为以下 IP 地址添加分流隧道条目:
- IPv4:
100.80.0.0/16 - IPv6:
2606:4700:0cf1:4000::/64
- IPv4:
在 Local Domain Fallback 中,删除您私有主机名的顶级域名。这将配置 WARP 将 DNS 查询发送到 Cloudflare Gateway 进行解析。
例如,如果您的 SSH 主机名是 ssh.internal.local,请从 Local Domain Fallback 中移除 internal.local。
要使用其 IP 地址(而不是主机名)连接到 SSH 服务器,请添加 CIDR 路由,其中包含服务器的私有 IP 地址。
默认情况下,WARP 会排除发往 RFC 1918 地址空间 ↗的流量,这些 IP 地址通常用于私有网络,且无法从互联网访问。为了让 Cloudflare One Client 向您的 private network 发送流量,您必须配置分流隧道(Split Tunnels),以便将您的 private network 的 IP/CIDR 路由通过 Cloudflare One Client。
-
首先,检查您的分流隧道模式是设置为**Exclude(排除)还是Include(包含)**模式。
-
根据该模式编辑您的分流隧道路由:
如果您使用的是**Exclude(排除)**模式:
a. 删除包含您的 private network 的 IP/CIDR 范围的路由。例如,如果您的网络使用默认 AWS 范围
172.31.0.0/16,请删除172.16.0.0/12。b. 重新添加您的 private network 没有明确使用的 IP/CIDR 范围。对于上述 AWS 示例,您需要为
172.16.0.0/13、172.24.0.0/14、172.28.0.0/15和172.30.0.0/16添加新条目。这可确保只有发往172.31.0.0/16的流量通过 Cloudflare One Client 进行路由。您可以使用以下计算器来确定要重新添加的 IP 地址:
计算器说明
- 在 Base CIDR 中,输入您从分流隧道中删除的 RFC 1918 范围。
- 在 Subtracted CIDRs 中,输入您的 private network 所使用的 IP/CIDR 范围。
- 将计算器结果重新添加到您的分流隧道“排除”模式列表中。
通过缩小 Cloudflare One Client 中包含的私有 IP 范围,您可以降低破坏用户访问本地资源的风险。
如果您使用的是**Include(包含)**模式:
- 将所需的 Zero Trust 域或IP 地址添加到您的分流隧道“包含”列表中。
- 添加一条路由以包含您的 private network 的 IP/CIDR 范围。
默认情况下,加入您组织的所有设备都可以 SSH 到该服务器,除非您构建 Gateway 网络策略来允许或阻止特定用户。您可以根据用户身份、设备安全状况、位置和其他标准创建策略。
- 转到 Traffic policies(流量策略)> Traffic settings(流量设置)。
- 在 **Proxy and inspection(代理和检查)**中,开启 Allow Secure Web Gateway to proxy traffic(允许 Secure Web Gateway 代理流量)。
- 选择 TCP。
- 选择 UDP(将流量代理到内部 DNS 解析器所必需)。
- (推荐)要代理
ping和traceroute等诊断工具的流量,请选择 ICMP。您可能还需要更新您的系统以允许 ICMP 流量通过cloudflared。
-
向您的
cloudflare_api_token↗ 添加以下权限:Zero Trust Write
-
使用
cloudflare_zero_trust_device_settings↗ 资源启用 TCP 和/或 UDP 代理:resource "cloudflare_zero_trust_device_settings "global_warp_settings" { account_id = var.cloudflare_account_id gateway_proxy_enabled = true gateway_udp_proxy_enabled = true }
Cloudflare 现在将代理来自注册设备的流量,但在您的 Split Tunnel 设置中排除的流量除外。有关 Gateway 如何转发流量的更多信息,请参阅 Gateway 代理。
以下示例包含两个策略:第一个策略允许特定用户访问您的 SSH 服务器,第二个策略阻止所有其他流量。
-
转到 Traffic policies(流量策略)> Firewall policies(防火墙策略)> Network(网络)。
-
选择 Create a policy(创建策略)。
-
命名您的策略(例如,
Allow SSH to internal server)。 -
创建一个表达式以匹配您的 SSH 主机名和授权用户:
选择器 运算符 值 SNI(服务器名称指示) in ssh.internal.localUser Email(用户电子邮件) in [email protected],[email protected] -
在 **Action(操作)**中,选择 Allow(允许)。
-
选择 Create policy(创建策略)。
为防止 Cloudflare One Client 用户访问您的整个私有网络,我们建议为您的私有 IP 空间创建一个兜底 Gateway 阻止策略。然后,您可以在此基础上叠加更高优先级的允许策略(在 Access 或 Gateway 中),以授予用户对特定应用程序或 IP 的访问权限。
为了获得额外的保护层,请创建 Gateway DNS 策略来控制 DNS 解析:
-
转到 Traffic policies(流量策略)> Firewall Policies(防火墙策略)> DNS(DNS)。
-
选择 Create a policy(创建策略)。
-
命名您的策略(例如,
Allow SSH hostname resolution)。 -
创建一个表达式:
选择器 运算符 值 Host(主机) in ssh.internal.localUser Email(用户电子邮件) in [email protected],[email protected] -
在 **Action(操作)**中,选择 Allow(允许)。
-
选择 Create policy(创建策略)。
设置好隧道路由和用户设备后,用户现在可以 SSH 到该机器。如果您的 SSH 服务器需要 SSH 密钥,则应在 SSH 命令中包含该密钥。
ssh -i ~/.ssh/gcp_ssh <username>@ssh.internal.localCloudflare One Client 必须连接到您的 Zero Trust 组织。如果用户符合您创建的 Gateway 网络策略,他们将能够连接。
如果无法连接,请确认以下内容:
-
确认 DNS 解析 - 从设备确认您可以成功解析私有主机名:
nslookup ssh.internal.localServer: 127.0.2.2 Address: 127.0.2.2#53 Non-authoritative answer: Name: ssh.internal.local Address: 100.80.200.48该查询应使用 WARP 的 DNS 代理进行解析,并返回 Gateway 初始解析 IP。如果查询解析失败或返回了不同的 IP,请检查您的 Local Domain Fallback 配置和 Gateway 解析器策略。
-
检查 Gateway 日志 - 审查您的 Gateway 网络日志以查看连接是否被策略阻止。
-
验证隧道状态 - 通过检查隧道状态来确认您的隧道健康且已连接。
测试到初始解析 IP 的连接性 - 当您使用私有主机名连接到 SSH 服务器时,设备应建立到 初始解析 IP 的连接:
ssh -v <username>@ssh.internal.local... Authenticated to ssh.internal.local ([100.80.200.48]:22) using "publickey". ...查找显示连接到
100.64.0.0/10范围内 IP 的行。如果请求失败,请确认初始解析 IP 通过 WARP 隧道路由。您也可以检查隧道日志以确认请求正路由到服务器的私有 IP。