在限制出站连接后保持应用正常工作

KubernetesBeginner
立即练习

介绍

Meadow Supply 应通过 API 显示实时供应情况并计算训练购物篮报价。在这个独立场景中,原始应用均在运行,但一条旧的 API 出站迁移规则允许范围宽泛的 TCP 连接,却遗漏了 DNS。因此,商品目录显示供应信息错误。你将修复必需的依赖连接,再撤销旧规则中不必要的权限,同时保持店铺和独立提货服务正常运行。

运用上一引导实验教过的命名空间、角色、策略、终端和真实请求方法。本实验会在使用出站流量、DNS 协议/端口要求、终端变量和策略并集之前解释它们。准备好的真实单节点集群独立包含完整应用和已批准的库存入站策略,不需要上一台 VM 中的文件或进程。无需安装集群或编写应用程序。时长由作者估计,并非对初学者实际计时所得。全部商品和提货记录均为合成数据,训练报价不会预留库存、下单或收费。

恢复 API 必需的依赖连接

在这一步中,你将恢复 Shop API 的真实 DNS 和库存连接,而不放开全部目标。

打开 Shop。完整的预期结果与之前相同,是包含三件商品的 Meadow Supply 商品目录:Glass water bottle 价格为 $18.00,库存 6 件;Everyday notebook 为 $14.00,库存 4 件;Canvas market bag 为 $24.00,库存 0 件。初始场景中,页面却显示 Live availability unavailable.。价格仍可见,但应用没有库存备用数据,无法给出有效报价。这是有意设置、需要修复的依赖故障,不要误认为库存集合为空。Reference 应仍显示两条原始提货记录。切换到 Workspace。

独立工作区为 /home/labex/project/stock-policy。使用与之前相同的路径恢复方法:pwd、ls,以及需要时使用的绝对路径 cd。读取提供的操作范围:

cd /home/labex/project/stock-policy
cat scope.json

本 VM 已准备好库存入站边界。它允许 meadow-shop 中的 API 角色访问;请保持此策略不变。API 的出站连接单独控制。Egress 指离开所选 Pod 的流量。选择这些 Pod 的 Egress 策略会在该方向上将其隔离,由所有适用出站规则的并集决定哪些流量可以离开。获准连接的回复流量会被隐式允许。

读取 API 命名空间中现有的迁移策略:

kubectl --context=labex-v135 -n meadow-shop get networkpolicies
kubectl --context=labex-v135 -n meadow-shop describe networkpolicy legacy-egress

legacy-egress 选择 role=shop-api,允许到任意目标的 TCP 端口 8080,却未包含 DNS。CoreDNS 是准备好的集群名称服务。在 HTTP 连接能够使用 Service 名称对应的地址之前,需要先发起 DNS 查询。DNS(Domain Name System,域名系统)将名称转换为地址。UDP(User Datagram Protocol,用户数据报协议)发送独立的数据报;TCP(Transmission Control Protocol,传输控制协议)建立连接。本集群的 DNS 服务在端口 53 上同时接受这两种协议,因此需要允许通往 kube-system 中 DNS Pod 的两条路径。

提供的诊断工具中,dns 模式向该 Pod 的解析器发送一次新的 UDP DNS 查询;dns-tcp 发送一次新的 TCP 查询。两者都不依赖应用缓存的结果。测试实际 API 身份:

./tools/network-test api dns stock.meadow-stock.svc.cluster.local
./tools/network-test api dns-tcp stock.meadow-stock.svc.cluster.local

两条命令都应报告 NETWORK_TIMEOUT 并以非零状态退出。这些预期失败涉及 DNS 连接。为将其与库存进程停止区分开,请对原始库存 Service 地址发起一次明确的诊断请求。

下面的赋值通过 $(...) 捕获命令输出,存入 shell 变量 stock_ip。-o jsonpath='{.spec.clusterIP}' 仅选择 Service 的 spec.clusterIP 字段;引号将表达式保留为整体。此变量属于当前 Workspace 终端会话。它是诊断值,不是策略目标或永久 Pod 地址。如果重新连接后进入了新的 shell,请先重复赋值,再使用它。

stock_ip=$(kubectl --context=labex-v135 -n meadow-stock get service stock -o jsonpath='{.spec.clusterIP}')

printf 打印捕获的字符串;%s 表示字符串,\n 结束该行。双引号将展开后的值保留为一个参数:

printf '%s\n' "$stock_ip"

${stock_ip} 在请求 URL 中展开此变量。现有的宽泛 TCP 规则允许这个无需 DNS 的连接:

./tools/network-test api http "http://${stock_ip}:8080/stock.json"

预期返回 HTTP_REPLY 200 和原始库存记录。TCP 访问是通的;名称解析是单独的依赖。绝不能将该地址写入最终策略:应使用稳定的命名空间与角色关系。

选择 DNS Pod 之前,先检查真实标签。-l k8s-app=kube-dns 选择准备好的 DNS Pod:

kubectl --context=labex-v135 get namespace kube-system --show-labels
kubectl --context=labex-v135 -n kube-system get pods -l k8s-app=kube-dns --show-labels

创建自己的 api-egress 策略。它选择 API 角色。其中两条 to 规则按 OR(或)组合:kube-system 中 DNS 的 UDP/TCP 53,或 meadow-stock 中库存的 TCP 8080。在每个单独的 peer(通信对端)中,命名空间与 Pod 选择器按 AND(且)组合。每条规则的端口只适用于该规则中的目标。

mkdir -p 会保留已有的发布目录。如前面所教,带引号的 here-document 和 > 仅写入你的可编辑发布文件:

mkdir -p release
cat > release/api-egress.yaml <<'YAML'
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-egress
  namespace: meadow-shop
spec:
  podSelector:
    matchLabels:
      role: shop-api
  policyTypes:
    - Egress
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - protocol: UDP
          port: 53
        - protocol: TCP
          port: 53
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: meadow-stock
          podSelector:
            matchLabels:
              role: inventory
      ports:
        - protocol: TCP
          port: 8080
YAML

读取、应用并检查保存的清单:

cat release/api-egress.yaml
kubectl --context=labex-v135 apply -f release/api-egress.yaml
kubectl --context=labex-v135 -n meadow-shop describe networkpolicy api-egress

确认两种真实 DNS 传输协议,以及通过名称建立的库存连接。应用后,策略执行可能需要几秒才生效;如果仍看到先前边界,请稍等后重复请求。

./tools/network-test api dns stock.meadow-stock.svc.cluster.local
./tools/network-test api dns-tcp stock.meadow-stock.svc.cluster.local
./tools/network-test api http http://stock.meadow-stock.svc.cluster.local:8080/stock.json

预期返回 DNS_REPLY UDP、DNS_REPLY TCP,然后是带全部原始库存数据的 HTTP_REPLY 200。切换到 Shop 并重新加载。实时供应情况应恢复。打开 Glass water bottle,选择 Quantity 2,使用 Try a basket quote。预期看到 Ready for collection、总价 $36.00 和可用数量 6,同时保留不预留库存的训练提示。通过 Back to product 和 Back to collection 返回。

将恢复后的实时商品目录与这个实际运行结果比较:

必需依赖连接恢复后的 Meadow Supply

至此,必需连接已修复,但还不能证明无关目标已被拒绝。其他策略仍可能增加权限。将此视为最终边界之前,请继续下一步。

对于拼写错误,使用 pwd、ls 和绝对路径 cd 返回。对于格式错误的清单或失败的依赖请求,请读取保存的文件、describe 输出,以及已教过的真实标签/端口,修正文件并重新应用。DNS_REPLY 是名称服务结果;HTTP_REPLY 是应用响应;NETWORK_TIMEOUT 表示在预设的网络超时内未收到响应;CONNECTION_REFUSED 表示目标拒绝了连接。工具设有时限的 REQUEST_TIMEOUT 涵盖整个请求,包括 DNS。一般性失败不能证明策略正确。不要修改应用代码、标签、源文件、原始 Pod、库存入站策略、Service、主机网络或 DNS 基础设施。

撤销旧策略的宽泛权限

在这一步中,你将移除旧迁移策略不必要的允许项,同时保留已修复的顾客流程和独立提货服务。

从 Workspace 开始,位于 /home/labex/project/stock-policy。你的新策略只允许 DNS 和库存。现在从 API 测试无关的提货服务:

./tools/network-test api http http://dispatch.meadow-stock.svc.cluster.local:8080/notes.json

它当前返回 HTTP_REPLY 200 和两条提货记录。这个成功结果暴露了多余权限;Shop API 不需要访问提货服务。新的窄范围策略不会覆盖现有的宽泛策略。NetworkPolicy 将允许的连接相加,与应用顺序无关。要使连接成功,来源的出站策略与目标的入站策略必须都允许它。

再次列出两条策略,然后读取受管理的迁移策略及其原始源文件:

kubectl --context=labex-v135 -n meadow-shop get networkpolicies
kubectl --context=labex-v135 -n meadow-shop describe networkpolicy legacy-egress
cat starter/legacy-egress.yaml

旧规则允许 TCP 端口 8080,未通过 to 限制目标。该权限仍对选中的 API Pod 生效。在此次发布中,应保留原始受管理的 legacy-egress 对象,原位撤销其权限。将其保存为不包含任何出站允许项的策略,用空列表 egress: [] 表示。独立的 api-egress 策略继续提供两类必需连接。保持只读起始文件不变。

cat > release/legacy-egress.yaml <<'YAML'
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: legacy-egress
  namespace: meadow-shop
spec:
  podSelector:
    matchLabels:
      role: shop-api
  policyTypes:
    - Egress
  egress: []
YAML

读取并应用保存的受管理策略。不要删除后再重建它:

cat release/legacy-egress.yaml
kubectl --context=labex-v135 apply -f release/legacy-egress.yaml
kubectl --context=labex-v135 -n meadow-shop describe networkpolicy legacy-egress

它应仍选择 API 角色,但不再贡献任何出站允许项。最终发布目录包含两份保存的策略。准备好的库存入站策略保持不变。

现在,API 对无关提货服务的请求必须超时,而 Customer 对完全相同服务的对照请求仍应成功:

./tools/network-test api http http://dispatch.meadow-stock.svc.cluster.local:8080/notes.json
./tools/network-test customer http http://dispatch.meadow-stock.svc.cluster.local:8080/notes.json

预期 API 返回 NETWORK_TIMEOUT 并以非零状态退出,然后 Customer 返回 HTTP_REPLY 200 和两条未改变的记录。这一对测试防止服务停止被误认为正确隔离。如果 API 请求在应用后立即仍成功,请等待几秒再重复,直到观察到实际的新边界。

再次确认已批准的库存路径和两种 DNS 协议:

./tools/network-test api http http://stock.meadow-stock.svc.cluster.local:8080/stock.json
./tools/network-test api dns stock.meadow-stock.svc.cluster.local
./tools/network-test api dns-tcp stock.meadow-stock.svc.cluster.local

切换到 Shop,重新加载,再次为 Glass water bottle 请求 Quantity 2 的报价:Ready for collection、**$36.00、6 件。再为 Canvas market bag 请求 Quantity 1 的报价:Not enough stock、$24.00**、0 件。返回商品系列,打开 Our approach 确认训练范围。切换到 Reference 并重新加载;两条原始提货记录均保留。使用 Download notes,检查实际下载的两条记录。浏览器下载位置与终端工作区不同,无需将文件复制到工作区。

你的交付内容是 release/api-egress.yaml 和 release/legacy-egress.yaml,应用于原始策略身份。实际生效与保存的权限均必须符合已教过的命名空间/角色和协议/端口边界:DNS UDP/TCP 53 和库存 TCP 8080,旧策略不再贡献任何允许项。保留全部原始应用资源、Pod、命名空间标签、数据和提供的源文件。如果修正导致店铺故障,请检查已教过的 DNS 与库存路径,只修正可编辑策略文件,再次应用。不要新增另一条全部允许的规则,也不要修改应用来绕过 DNS。这些有限的 TCP/UDP 观测不能证明具备抵御节点或管理员访问的生产网络安全边界。

总结

你区分了名称解析与应用连接,恢复了 API 的真实 DNS 和库存依赖,并让实时顾客报价继续工作。你还发现了为什么窄范围策略不能移除另一条策略提供的权限,随后在不停止无关服务的情况下撤销了旧允许项。

最终保存的发布配置和实际生效的策略并集允许必需的 DNS 与库存路径,同时拒绝 API 访问提货服务。策略应用顺序不代表优先级;判断失败原因时,应评估组合后的权限,并保留正向对照。