DNS 与 Resolver
本页介绍 guest 的 DNS 查询发往哪里,以及怎样用 Resolver 把查询交给调用方选定的上游。
链路 DNS
guest 只向自己链路上的一个地址发 DNS 查询,查询去哪里由策略决定。下图依次是三种去向:不引用 Resolver、Resolver 的路径为 direct、Resolver 的路径经 Egress。
| 项 | 规则 |
|---|---|
| 链路 DNS 地址 | 第一个部署 DNS 服务器所在地址族的 guest 网关地址;IPv6 是 fe80::1 |
/etc/resolv.conf | 只有一个 nameserver,即链路 DNS 地址 |
| 端口 | 53,UDP 与 TCP |
| 策略 | 查询的去向 |
|---|---|
DENY_ALL | 立即失败:UDP 收到端口不可达,TCP 被重置,没有报文离开 Workspace |
PUBLIC_INTERNET,不引用 Resolver | 转给与链路 DNS 地址同族的第一个部署 DNS 服务器,其余的不使用 |
PUBLIC_INTERNET,引用 Resolver | 按 Resolver 的协议与路径转给调用方的上游,见在策略中引用 Resolver |
allow、deny与 Egress 网段都不作用于这些查询。 只有 Resolver 能让查询经 Egress 离开。- 改策略不改 guest 的 DNS 配置。 改 mode、引用、更换或解除 Resolver,
/etc/resolv.conf都不变。 - guest 直接发往部署 DNS 服务器的 UDP 被拒绝。 只有发往链路 DNS 地址的查询算 DNS。
- 升级前启动的 Workspace 保持原来的 DNS 配置,直到重启。 它的
/etc/resolv.conf仍列出部署 DNS 服务器,不能引用 Resolver:这样的修改返回failed_precondition,reason为CONFLICT,期望与生效的策略都不变。停止再启动后换到链路 DNS 地址,之后可以引用。
Resolver
Resolver调用方提供的 DNS 服务器。Workspace 的网络策略引用它之后,guest 的 DNS 查询发往它。 是调用方选定的 DNS 上游。服务端必须支持 Resolver;不支持时,kibo resolver 与带 Resolver 的 kibo workspace network 命令退出 14,不发请求。能力名见用 API。
创建 Resolver
下面的命令创建一个带 label 的 DNS over HTTPS Resolver,查看它,再列出带这个 label 的 Resolver:
resolver_id=$(kibo resolver create --https https://dns.example.com/dns-query --label team=infra -q)
kibo resolver get "$resolver_id"
kibo resolver list -l team=infra创建与更新必须选一种协议,不选时返回 invalid_argument:
| 参数 | 规则 |
|---|---|
--udp | IP 地址或 IP:port,端口缺省 53,不接受主机名。guest 经 TCP 发来的查询经 TCP 发往同一地址 |
--tcp | IP 地址或 IP:port,端口缺省 53,不接受主机名 |
--tls | DNS over TLS,host 或 host:port,host 可以是主机名,端口缺省 853 |
--https | DNS over HTTPS,https://host[:port]/path,端口缺省 443,路径必须给出,至多 2048 字节;不接受用户信息、查询串与片段。查询用 POST 发送 |
--label、--annotation | 只在创建时给出,之后单独修改,见 labels 与 annotations |
- IP 地址的写法同
allow、deny的条目。 IPv6 后面跟端口时写在方括号里,例如[2001:db8::53]:53。 kibo在发请求前拒绝写法不对的地址,退出2。- 读取原样返回写入的内容,缺省的端口不补上。
tls与https用系统信任库校验证书,校验的名字是 host。 host 是 IP 地址时,证书要带这个 IP。- 每个 Resolver 有自己的版本。 由服务端分配:创建时为 1,上游设置变化时加一,与引用它的策略的版本互不影响。
警告
Resolver 没有凭证,读取返回全部内容。URL 的路径对同一部署里能读 Resolver 的其他调用方可见,不要把访问令牌放在路径里。
在策略中引用 Resolver
public-internet 的策略引用一个 Resolver 后,guest 的 DNS 查询转给它。下面的命令引用一个直接发往上游的 Resolver:
kibo workspace network set "$workspace_id" public-internet --resolver "$resolver_id" --resolver-path direct策略还没有 Resolver 时,下面的命令在一次修改里加上一个 Egress 和经它离开的 Resolver:
kibo workspace network add "$workspace_id" --egress "$egress_id" --egress-destination 10.0.0.0/8 --resolver "$resolver_id" --resolver-path "egress:$egress_id"下面的命令解除引用:
kibo workspace network remove "$workspace_id" --resolver "$resolver_id"一个策略至多引用一个 Resolver,它必须存在,不存在或已删除时返回 not_found。路径决定到上游的连接怎么离开,没有默认值:
--resolver-path | 到上游的连接 |
|---|---|
direct | 从 node 的上联地址直接发往上游 |
egress:<egress-id> | 经这个 Egress 发往上游。它必须是同一策略引用的 Egress,与网段是否覆盖上游无关;上游可以在调用方的内网。udp Resolver 还要求这个 Egress 开启 UDP |
| 命令 | 对 Resolver 的效果 |
|---|---|
network set、workspace create | --resolver 加 --resolver-path 写入一项;不带 --resolver 时策略不引用 Resolver |
network add | 策略还没有 Resolver 时引用它;已有时只能写同一个 ID 与路径。换 Resolver 或改路径用 set |
network remove | --resolver 解除引用,查询回到部署 DNS 服务器。Resolver 路径指名的 Egress 只能与 --resolver 一起删 |
读到的策略已引用 Resolver 时,add 与 remove 同样要求 Resolver 的能力。
上游不可用时 guest 收到 SERVFAIL,不回退部署 DNS 服务器。转发查询有下面的时限与上限:
| 项 | 规则 |
|---|---|
| 一次查询 | 从收到到应答至多 4 秒 |
udp 上游的重发 | 2 秒没有应答时重发一次 |
| 同时处理的查询 | 每个 Workspace 至多 256 个,超出的立即回 SERVFAIL |
| guest 经 UDP 收的应答 | 上限取查询里 EDNS 声明的大小,没有 EDNS 时为 512 字节;超出时回带 TC 位的应答,guest 改用 TCP 重查 |
- 直出的上游在引用时先核对一次。 IP 地址落在私网、本机、组播、文档用途等固定的特殊用途网段,或主机名在 ctrl 解析一次的结果里有这样的地址,返回
invalid_argument;被直出引用的 Resolver 更新成这样的上游也返回invalid_argument。 - 这一步只是提早发现错误。 与 Egress 端点一样,node 拨号时用部署 DNS 服务器解析主机名,去掉不允许的地址,只连剩下的,全被去掉时这次查询得到
SERVFAIL。 - 经 Egress 时 node 不解析也不核对上游。 主机名交给端点解析;
udp上游经UDP ASSOCIATE,其余经CONNECT。端点答复的 UDP 中继地址按端点的规则核对。 - Egress 更新后, 经它的查询与 TCP 一起换用新 revision;宽限期只作用于 TCP 连接。
- 非法组合返回
invalid_argument,期望不变:DENY_ALL带 Resolver、多于一项、没有路径、路径指名的 Egress 不在策略里、udpResolver 经未开启 UDP 的 Egress、直出的上游落在特殊用途网段。 - 只交给支持 Resolver 的 node。 创建或启动时没有宣告 Resolver 能力的 node,返回
failed_precondition,reason为CAPABILITY_UNAVAILABLE,不会以不带 Resolver 的策略运行;运行中加 Resolver 而所在的 node 不支持时,返回同样的错误,期望不变。 - 引用、更换或解除 Resolver 都是内容变化,版本加一;请求在新配置生效后返回,之后的新查询按新配置发出。
更新与删除 Resolver
下面的命令把 Resolver 改为 DNS over TLS,然后解除引用并删除它:
kibo resolver update "$resolver_id" --tls dns.example.com
kibo workspace network remove "$workspace_id" --resolver "$resolver_id"
kibo resolver delete "$resolver_id"- 更新是整体替换。 内容相同时成功且版本不变。
- 并发的更新被拒绝。 不传
--expected-revision时,kibo先读取当前版本再提交,期间被别人改过时退出13;脚本重放时把--command-id与--expected-revision一起传入。 - 更新在保存后返回,不等待 Workspace。 引用它的运行中 Workspace 随后把新查询切到新 revision,通常在 30 秒内完成;已经发出的查询按原配置完成。
- 比较两个 revision 判断是否生效。 Workspace 状态里对应项已应用的 revision 等于 Resolver 的 revision 时,更新已经生效,见确认策略已经生效。
- 被直出引用时不能改成特殊用途地址。 核对规则见在策略中引用 Resolver。
- 被引用的 Resolver 不能删除。 还有未删除的 Workspace 的策略引用它时,删除返回
failed_precondition(CONFLICT),kibo退出13。先解除引用。 - 已删除的 Resolver 对所有读取与引用都返回
not_found。
用 API
Resolver 用 ResolverService 管理,写操作都带幂等键,见幂等键。创建 Resolver 里的参数对应这些字段:
| kibo 参数 | API 字段 |
|---|---|
--udp | udp.address |
--tcp | tcp.address |
--tls | tls.address |
--https | https.url |
--label、--annotation | labels、annotations |
revision由服务端分配: 创建时为 1,spec变化时加一。- 更新必须带期望版本。 与当前版本不符返回
aborted(CONFLICT),内容不变。 - 网络策略里的 Resolver 是
resolvers。 至多一项,每项用resolver_id写一个 Resolver 与它的路径;direct对应path.direct,经 Egress 的路径对应path.egress_id。 - 更新是否生效看 Workspace 状态里对应项的
applied_revision。
服务端支持时宣告能力 workspace.network_policy.resolver。
警告
老版本的服务端会静默丢掉 resolvers。写入前先确认能力名存在。