iPhone VPN 按域名:决定拒绝发生在哪一层
NeverConnect 只是阻止 VPN 启动,并不封锁网站。先决定拒绝应属于服务边界,还是受管策略。
两个需求常常被写成一句话,却在完全不同的地方实现。本网站只能通过 VPN 访问,说的是准入,天然属于服务前方的网络。本 iPhone 绝不能直接联系该域名,说的是设备,只有受管客户端策略才能表达。打开配置文件编辑器之前,先判断你真正面对的是哪一种。
两条听起来一样的需求
以示例主机 records.corp.example 为例。准入场景下,你只把它发布到 VPN 后方的地址,于是手机在蜂窝网络上的直连尝试会在网络层失败,而同一请求经隧道则能成功,并且仍然需要真实的账户登录。设备场景下,手机可以访问公网,主机对任何人都会解析并应答,唯一能拦住尝试的地方就是设备本身。服务无法对从未到达它的请求执行任何规则。
误读需求,会体现为一种具体的部署。记录仍然是公开的,运维方以为 VPN 是强制的,而对蜂窝尝试的审计显示请求从未进入隧道。日志里看不出任何故障,因为根本没有东西被拦截。
照字面理解评估动作
按需机制有两层彼此不同的动作,把它们混为一谈正是这里大部分混乱的来源。外层规则动作决定规则命中时隧道如何变化,连接评估动作则决定评估规则内部的主机名匹配如何处理。Apple 的 Never Connect 参考文档只描述了第二层。
| Layer | Action | What it controls |
|---|---|---|
| Outer rule | connect | Bring the tunnel up when the rule matches |
| Outer rule | disconnect | Tear the tunnel down when the rule matches |
| Outer rule | evaluateConnection | Run a hostname evaluation instead of acting directly |
| Outer rule | ignore | Leave the current tunnel state alone |
| Connection evaluation | connectIfNeeded | Start the tunnel when the hostname cannot be resolved |
| Connection evaluation | neverConnect | Do not start the tunnel for that match |
neverConnect 是最常被误读的取值,因为名字听起来像是封锁。它控制的是对匹配主机名是否启动隧道,而不是手机访问某个名称的权限,所以 Never Connect 条目并不是域名封锁。在设计文档里这样标注,就会让一次部署带着它实际上并不具备的强制边界获得批准。
你拥有服务时,就在边界上强制
限制准入意味着只在 VPN 路径能够到达的地方发布名称,然后验证预期路径可用、另一条路径不可用。覆盖每一条已发布的记录、如果你发布就覆盖两类地址族,以及应用使用的任何中间名或备用名。一条仍指向公网负载均衡器的旧 CNAME,会让直连路径继续存活,主记录整理得再干净也没用。
这保护的是服务而不是设备。它不会阻止手机发出 DNS 查询,也不会阻止应用去尝试。如果这些尝试可以接受,边界强制就是更便宜、更持久的选择,因为它对每个客户端都成立,而不只是你配置过的那些。它也能扛住从未注册过的手机。
当手机连尝试都不该有时,你需要受管策略
要阻止尝试,需要一项受支持的强制策略,覆盖连接前的应用或目标、隧道故障期间以及网络切换之后。请 VPN 或设备管理供应商说明该策略的名称、是否需要组织级管理,以及它还会影响什么。按应用划分的隧道加一条按需规则并不是一回事,主屏幕上的连接快捷方式也不是。
通过关闭隧道并观察请求是否外发,来测试失败场景。如果外发了,你记录的边界就不是你部署的边界。
用三个问题来决定
第一,你控制的是服务还是只有手机?第二,设备是否可以为其他一切合法使用公网?第三,手机是否受管,由谁管理?拥有服务加上受管设备群,意味着两层都可用;只拥有手机,则客户端策略是唯一选项,而且它必须得到支持。
在碰配置文件之前先回答这三个问题。此后配置就不再是对一个名为 Never 的复选框含义的猜测。