Egress
Egress调用方运营的 SOCKS5 出口代理。Workspace 的网络策略引用它之后,发往指定网段的 TCP 连接从调用方的网络离开。 是调用方运营的 SOCKS5 端点。Workspace 的网络策略引用它之后,发往指定网段的 TCP 连接从调用方的网络离开。本页介绍怎样创建、引用、更新和删除 Egress,以及连接在什么情况下经它离开。
前提条件
服务端必须支持 Egress。不支持时,kibo egress,以及带 Egress 参数或 --drain-seconds 的 kibo workspace network 命令退出 14,不发请求。能力名见用 API。
创建 Egress
下面的命令创建一个带 label 的 Egress,查看它,再列出带这个 label 的 Egress:
egress_id=$(kibo egress create --address proxy.example.com:1080 --username alice --password-file ./proxy-password --label team=infra -q)
kibo egress get "$egress_id"
kibo egress list -l team=infra创建与更新描述完整的端点:
| 参数 | 规则 |
|---|---|
--address | 必填,host:port,host 是 IP 地址或主机名 |
--username 与口令 | 可省略;给出时两个都要有,各 1 到 255 字节,按 RFC 1929 认证,见口令 |
--tls、--tls-server-name、--tls-ca-cert-file | 开启 TLS,SOCKS5 协商与转发的流量都在 TLS 内。给出后两个参数之一也会开启 TLS。校验名缺省取端点的 host;CA 是 PEM,至多 64 KiB,给出时替代系统信任库 |
--udp | 缺省关闭。开启后,引用它的策略才能让 udp Resolver 的查询经它离开,SOCKS5 用 UDP ASSOCIATE 承载 |
--label、--annotation | 只在创建时给出,之后单独修改,见 labels 与 annotations |
警告
开启 TLS 时 UDP 数据报不受 TLS 保护,以明文发往端点答复的中继地址。
- 端点在创建与更新时先核对一次。 IP 地址落在私网、本机、组播、文档用途等固定的特殊用途网段,或主机名在 ctrl 解析一次的结果里有这样的地址,返回
invalid_argument。这一步只是提早发现错误:node 每次拨号都会重新解析,去掉不允许的地址,只连剩下的。 - 每个 Egress 有自己的版本。 由服务端分配:创建时为 1,端点设置变化时加一,与引用它的策略的版本互不影响。
口令
kibo 没有直接写口令值的参数,口令因此不进入命令历史与进程列表。
- 用
--password-stdin从标准输入读,或用--password-file从文件读。 - 只给
--username时,kibo在终端上不回显地询问口令;没有终端时退出2。 - 标准输入与文件末尾的一个换行会被去掉,其余字符都是口令的一部分。
- 口令只写。任何读取、列表、命令输出与错误信息都不返回它;用户名照常返回,详情里只说明有没有配置凭证。
让连接经 Egress 离开
public-internet 的策略可以引用一个 Egress,并写明经它离开的目的网段。目的地落在这些网段里的新建 TCP 连接经 Egress 转发,其余照常直出。下图的网段只写了 10.0.0.0/8:
下面的命令让全部 IPv4 与 IPv6 目的地经 Egress 离开,再加上并删掉网段 10.0.0.0/8,最后解除引用:
kibo workspace network set "$workspace_id" public-internet --egress "$egress_id" --egress-destination 0.0.0.0/0 --egress-destination ::/0
kibo workspace network add "$workspace_id" --egress-destination 10.0.0.0/8
kibo workspace network remove "$workspace_id" --egress-destination 10.0.0.0/8
kibo workspace network remove "$workspace_id" --egress "$egress_id"| 命令 | 对 Egress 的效果 |
|---|---|
network set、workspace create | --egress 加至少一个 --egress-destination 写入一项;不带 --egress 时策略不引用 Egress |
network add | 策略还没有 Egress 时,--egress 加 --egress-destination 引用它;已有时 --egress-destination 给它加网段,--egress 只能写同一个 ID |
network remove | --egress-destination 删掉网段,至少留一条;只写 --egress 时解除引用,这些网段恢复直出 |
add 与 remove 编辑 --allow、--deny 时保留已有的 Egress 项。读到的策略已引用 Egress 时,add 与 remove 同样要求 Egress 的能力。
- 一个策略至多引用一个 Egress,网段 1 到 256 条。 多于一项、网段为空或超过 256 项、条目写法不规范、
DENY_ALL带 Egress,都返回invalid_argument,期望不变。 - 网段的写法与
allow、deny相同。 各自只作用于本地址族。 - Egress 必须存在。 不存在或已删除时返回
not_found。 - 只交给支持 Egress 的 node。 创建或启动时没有宣告出口能力的 node,返回
failed_precondition,reason为CAPABILITY_UNAVAILABLE,不会以不带 Egress 的策略运行;运行中加 Egress 而所在的 node 不支持时,返回同样的错误,期望不变。 - 只改网段的顺序是内容变化,版本加一,但不改变任何连接的走向。
连接的走向
目的地在网段里的新建 TCP 交给 node 上的转发服务,由它向 SOCKS5 端点发起 CONNECT,请求的是 guest 原本要连的目的地址:
一个连接按下面的顺序判定:
- 到链路 DNS 地址的 53 端口:交给链路 DNS,不按目的地经 Egress 转发。
- 在
deny里且不在allow里:拒绝,私网条目同样生效。 - 目的地在网段里的新建 TCP:经 Egress 转发,不做私网与特殊用途地址的拒绝。
- 目的地在网段里的
ping:立即拒绝,回 ICMP 管理性禁止。 - 其余:按目的地的判定直出。
网段可以写私网与平台网段。经 Egress 的连接从调用方的网络离开,不受直出时的私网拒绝约束。下图表明同一个地址直出时照常被拒绝:
目的地在网段里时,各类流量的去向:
| 流量 | 去向 |
|---|---|
| guest 发起的 TCP | 经 Egress 转发 |
ping | 立即拒绝,回 ICMP 管理性禁止 |
| guest 发起的其他 UDP | 与直出相同,PUBLIC_INTERNET 不放行 |
| 发往链路 DNS 地址的查询 | 不经 Egress。只有 Resolver 的路径指名这个 Egress 时,转发的查询才经它离开,见 DNS 与 Resolver |
出口失败不回退直出:端点连不上、TLS 校验失败、SOCKS5 协商或认证失败时,guest 的连接被重置,原因见 Egress 的故障。
改变连接走向
改变连接走向的修改(直出改为经 Egress、反过来,或换掉网段)不立即切断已有连接:
- 新连接立即按新策略建立,旧连接沿原路径继续传输,到宽限期结束后关闭,
draining_revision在这段时间里是旧的策略 revision。 - 宽限期是这次修改的
--drain-seconds,取 0 到 3600,缺省 600,0 表示切换时立即关闭。 - 宽限期内再次修改不延长更早的截止时间。
- 新的 mode、
allow或deny不再放行的连接不等宽限期,立即终止。
| 修改 | 已建立的连接 |
|---|---|
网段从 10.0.0.0/8 改成 0.0.0.0/0 | 原来直出的公网连接继续传输,宽限期满后关闭;新连接经 Egress |
| 解除对 Egress 的引用 | 经 Egress 到 10.0.0.5 的连接继续传输,宽限期满后关闭;新连接直出,被拒绝 |
同一次修改把 10.0.0.5 加进 deny | 立即终止 |
| 解除引用后删除 Egress | 仍在宽限期内的连接立即关闭 |
更新 Egress
更新在 ctrl 保存后返回,不等待 Workspace。引用它的运行中 Workspace 随后把新连接切到新 revision,已有连接按这次更新的宽限期关闭。下图是切换的过程:
| 时间 | 发生什么 | 怎样看到 |
|---|---|---|
运行 kibo egress update(UpdateEgress) | ctrl 保存,revision 3 变为 4 后返回 | Egress 的 revision 为 4 |
| 切换之前 | node 取得新配置,新连接仍用 revision 3 | Workspace 里这个 Egress 的 applied_revision 为 3 |
| 切换,通常在 30 秒内 | 新连接用 revision 4;revision 3 的连接继续传输 | applied_revision 为 4,draining_revision 为 3 |
| 宽限期满 | revision 3 的连接关闭 | draining_revision 为 0 |
下面的命令更新 Egress,旧 revision 的连接在切换 60 秒后关闭:
kibo egress update "$egress_id" --address proxy.example.com:1080 --username alice --password-file ./proxy-password --drain-seconds 60- 更新是整体替换。
kibo egress update没写的参数为空。口令读不回来,每次更新都要重新给出。 - 并发的更新被拒绝。 不传
--expected-revision时,kibo先读取当前版本再提交,期间被别人改过时退出13。脚本重放时把--command-id与--expected-revision一起传入。 - 内容相同的更新成功,版本不变。
- 宽限期是这次更新的参数。
--drain-seconds取 0 到 3600,缺省 600,0 表示切换时立即关闭,不随 Egress 保存。 - node 一时取不到新配置时保持原 revision。 ctrl 会重试,Workspace 状态不变。
- 仍有
udpResolver 经它离开时不能关闭 UDP。 这样的更新返回failed_precondition(CONFLICT),kibo退出13,内容不变。 - 比较两个 revision 判断是否生效。 Workspace 状态里这个 Egress 已应用的 revision 等于 Egress 的 revision 时,新连接已经用上新配置,见确认策略已经生效。
删除 Egress
被引用的 Egress 不能删除,所以下面的命令先解除引用,再删除 Egress:
kibo workspace network remove "$workspace_id" --egress "$egress_id"
kibo egress delete "$egress_id"- 还有未删除的 Workspace 的策略引用它时,删除返回
failed_precondition(CONFLICT),kibo退出13。 - 删除后,仍经它在宽限期内的连接立即关闭。
- 已删除的 Egress 对所有读取与引用都返回
not_found。
用 API
Egress 用 EgressService 管理,写操作都带幂等键,见幂等键。创建 Egress 里的参数对应这些字段:
| kibo 参数 | API 字段 |
|---|---|
--address | socks5.address |
--username 与口令 | socks5.username、socks5.password |
--tls、--tls-server-name、--tls-ca-cert-file | socks5.tls |
--udp | udp_enabled |
--label、--annotation | labels、annotations |
spec.socks5是端点协议。 目前只有 SOCKS5。创建与更新不选协议时返回invalid_argument。revision由服务端分配: 创建时为 1,spec变化时加一。- 更新必须带期望版本。 与当前版本不符返回
aborted(reason为CONFLICT),内容不变。 - 网络策略里的 Egress 是
egresses。 每一项写一个egress_id与它的destinations。 - 宽限期在修改策略与更新 Egress 时都是
drain_seconds。
服务端支持时宣告能力 workspace.network_policy.egress.socks5。以后每种出口协议一个能力名,调用方据此判断部署支持哪些协议。
警告
老版本的服务端会静默丢掉 egresses。写入前先确认能力名存在。
下一步
- DNS 与 Resolver:用 Resolver 让 DNS 查询也经 Egress 离开。
- 网络排查:确认更新已经生效,以及经 Egress 的连接被重置时怎样找原因。
- 网络策略:目的地规则,以及策略的修改什么时候生效。