加上 waypoint 后出现了 503
目标
在 k3s 上真实的 Ambient 网格中,分别体验由 ztunnel 强制执行的 L4 和由 waypoint 强制执行的 L7,并通过请求和日志确认附加 waypoint 时需要一并修改什么。
为什么重要
Ambient 去掉了 sidecar,所以很轻量,但策略和路由被分到了两层(ztunnel、waypoint)。如果不清楚哪一层看什么,HTTP 规则就会悄悄丢失,附加 waypoint 的瞬间原本正常的流量会中断,发往 Pod IP 的请求也会绕过 L7 策略。这三点仅看清单是看不出来的,只有在真实网格中亲身经历才会记住。
步骤
- 用
kubectl apply -f /opt/fixtures/istlab/ambient-app.yaml部署材料,等待 Pod 就绪后,给命名空间shop加上标签istio.io/dataplane-mode=ambient(不要重新创建 Pod)。然后在/root/istlab-ambient/01-enroll.txt中写入两行:web_containers=(web-v1 Pod 的容器名称,用逗号分隔)和protocol=(istioctl ztunnel-config workloads中 shop 各 Pod 的 PROTOCOL 一栏)。 - 在 client 中访问一次
http://web/,并把记录该连接的 ztunnel 访问日志中的一行(消息为connection complete、src.identity为 client、dst.identity为 web 的那一行)原样保存到/root/istlab-ambient/02-ztunnel.log。 - 在
/root/istlab-ambient/web-l4.yaml中写入并应用AuthorizationPolicyweb-l4(命名空间shop,选择器app: web,ALLOW,主体cluster.local/ns/shop/sa/client)。应用后,分别在 client 和 outside 中的 stranger 里访问http://web.shop/,并在/root/istlab-ambient/03-l4.txt中写入client=(状态码)和stranger_exit=(stranger 一侧 curl 的退出码)两行。 - 在
/root/istlab-ambient/l7-wrong.yaml中写入并应用AuthorizationPolicyweb-get-only-l4(选择器app: web,ALLOW,主体 client,方法 GET),把该策略status.conditions中ZtunnelAccepted条件的reason以status_reason=写入/root/istlab-ambient/04-l7.txt,并把 client 的POST请求的状态码以post_code=写入。记录之后删除这个策略。 - 用
istioctl waypoint apply -n shop --enroll-namespace --wait给 shop 附加 waypoint。紧接着把 client 访问http://web/的状态码以code_after_waypoint=写入/root/istlab-ambient/05-waypoint.txt,然后修复原因——把/root/istlab-ambient/web-l4.yaml中的允许主体改为只有 waypoint 的身份cluster.local/ns/shop/sa/waypoint一个,重新应用。修复后,client 访问http://web/应为 200,client 直接用 web-v1 的 Pod IP 访问则连接应被断开。 - 在
/root/istlab-ambient/web-get-only.yaml中写入并应用AuthorizationPolicyweb-get-only——用targetRefs指向服务web(group"",kindService),ALLOW,主体cluster.local/ns/shop/sa/client,方法GET。应用后,client 的 GET 应为 200,POST 应为 403。 - 在
/root/istlab-ambient/httproute.yaml中写入并应用HTTPRouteweb——父资源为服务web(group"",kindService,端口 80),两条规则:请求头x-canary: yes时转到web-v2,其余转到web-v1。应用后,client 带x-canary: yes的请求应得到 v2,不带请求头的请求始终是 v1。 - 在
/root/istlab-ambient/08-report.md中写入六行——protocol=(第 1 步)、l7_without_waypoint=(第 4 步中 GET 规则被强制执行则为enforced,被去掉则为ignored)、broke_with_waypoint=(第 5 步的 code_after_waypoint)、l4_allowed_principal=(现在 web-l4 允许的主体)、post_via_waypoint=(现在 client 的 POST 状态码)、direct_pod_ip=(现在 client 直接访问 Pod IP 时为allowed或rejected)——并在其下写出学到的内容,至少四行。
参考
- 这台 VM 的准备需要 2–4 分钟。ambient profile(istiod、istio-cni、ztunnel)已通过
values.global.platform=k3s安装。 - Ambient 的 Pod 没有 sidecar,所以像
kubectl -n shop exec client -- curl …这样不指定容器也可以。 - ztunnel 所知的工作负载和服务用
istioctl ztunnel-config workloads、istioctl ztunnel-config services查看,ztunnel 日志用kubectl -n istio-system logs ds/ztunnel查看,waypoint 日志用kubectl -n shop logs deploy/waypoint查看。 - 修改策略之后,要过几秒钟才会扩散到 ztunnel 和 waypoint。
- 常见错误——把 HTTP 条件(方法、路径)写进选择器策略。waypoint 策略要用
targetRefs来附加。
用一个标签纳入网格——无需重启
用 kubectl apply -f /opt/fixtures/istlab/ambient-app.yaml 部署材料,等待 Pod 就绪后,给命名空间 shop 加上标签 istio.io/dataplane-mode=ambient(不要重新创建 Pod)。然后在 /root/istlab-ambient/01-enroll.txt 中写入两行:web_containers=(web-v1 Pod 的容器名称,用逗号分隔)和 protocol=(istioctl ztunnel-config workloads 中 shop 各 Pod 的 PROTOCOL 一栏)。
在 Ambient 中,istio-cni 节点代理会在 Pod 的网络命名空间内部植入拦截规则,由每个节点上的一个 ztunnel 接收这些流量。因为不注入 sidecar,所以不需要重新创建 Pod。被纳入的 Pod 会带上注解 ambient.istio.io/redirection: enabled,在 ztunnel 所知的工作负载列表中,协议会变为 HBONE。网格之外的 stranger 仍然是 TCP。
ztunnel 看到的两个身份
在 client 中访问一次 http://web/,并把记录该连接的 ztunnel 访问日志中的一行(消息为 connection complete、src.identity 为 client、dst.identity 为 web 的那一行)原样保存到 /root/istlab-ambient/02-ztunnel.log。
Ambient 的 mTLS 由 ztunnel 之间通过 HBONE(HTTP CONNECT 之上的 mTLS 隧道,端口 15008)建立。ztunnel 是 L4 代理,所以不知道请求路径或方法,但知道双方工作负载的 SPIFFE 身份。日志用 kubectl -n istio-system logs ds/ztunnel 查看,同一个连接可能会在出发一侧和到达一侧各留下一行。带有 dst.hbone_addr 的那一行,就是通过 HBONE 进入的连接。
由 ztunnel 强制执行的 L4 策略
在 /root/istlab-ambient/web-l4.yaml 中写入并应用 AuthorizationPolicy web-l4(命名空间 shop,选择器 app: web,ALLOW,主体 cluster.local/ns/shop/sa/client)。应用后,分别在 client 和 outside 中的 stranger 里访问 http://web.shop/,并在 /root/istlab-ambient/03-l4.txt 中写入 client=(状态码)和 stranger_exit=(stranger 一侧 curl 的退出码)两行。
用选择器附加的策略由该 Pod 的 ztunnel 强制执行。ztunnel 在接收连接的瞬间根据来源身份决定是否放行,所以拒绝不是 HTTP 403,而是表现为连接被断开(curl 退出码 56)。网格之外的 stranger 没有身份,不符合任何主体规则。退出码用 …; echo $? 查看。
没有 waypoint 时写下的 HTTP 规则会怎样
在 /root/istlab-ambient/l7-wrong.yaml 中写入并应用 AuthorizationPolicy web-get-only-l4(选择器 app: web,ALLOW,主体 client,方法 GET),把该策略 status.conditions 中 ZtunnelAccepted 条件的 reason 以 status_reason= 写入 /root/istlab-ambient/04-l7.txt,并把 client 的 POST 请求的状态码以 post_code= 写入。记录之后删除这个策略。
ztunnel 不解析 HTTP。如果把带有方法、路径之类条件的规则以选择器策略的形式给出,istiod 会去掉这条规则再下发给 ztunnel,并在策略状态中记下这一事实。ALLOW 策略之间是“只要有一条匹配就放行”,所以如果已有的 web-l4 放行了 client,POST 也会通过——写的是只允许 GET,POST 却可以通过。状态用 kubectl -n shop get authorizationpolicy web-get-only-l4 -o yaml 查看。
一附加 waypoint,原本正常的请求就变成 503
用 istioctl waypoint apply -n shop --enroll-namespace --wait 给 shop 附加 waypoint。紧接着把 client 访问 http://web/ 的状态码以 code_after_waypoint= 写入 /root/istlab-ambient/05-waypoint.txt,然后修复原因——把 /root/istlab-ambient/web-l4.yaml 中的允许主体改为只有 waypoint 的身份 cluster.local/ns/shop/sa/waypoint 一个,重新应用。修复后,client 访问 http://web/ 应为 200,client 直接用 web-v1 的 Pod IP 访问则连接应被断开。
有了 waypoint 之后,发往服务的请求按 client 的 ztunnel → waypoint → web 的 ztunnel 的顺序走。所以 web 的 ztunnel 看到的来源不是 client,而是 waypoint。只允许 client 的 L4 策略会切断这个连接,waypoint 则返回 503(waypoint 日志中的 tunnel_response:401)。只允许 waypoint 身份后,通往服务的路径是通的,而不经过 waypoint 的路径(直接用 Pod IP)则被关闭——服务级 waypoint 不处理发往 Pod IP 的请求,所以要这样关闭,才不会绕过第 7 步的 L7 策略。
把 HTTP 规则设置在 waypoint 上
在 /root/istlab-ambient/web-get-only.yaml 中写入并应用 AuthorizationPolicy web-get-only——用 targetRefs 指向服务 web(group "",kind Service),ALLOW,主体 cluster.local/ns/shop/sa/client,方法 GET。应用后,client 的 GET 应为 200,POST 应为 403。
waypoint 是 Envoy,所以会解析 HTTP。把策略附加到 waypoint 的方法不是选择器,而是 targetRefs——指向服务时,由处理发往该服务的请求的 waypoint 来强制执行。在 waypoint 看到的来源是 client 自身,所以主体写 client。这次拒绝不是连接被断开,而是 HTTP 403(RBAC: access denied)。
waypoint 也负责路由——HTTPRoute
在 /root/istlab-ambient/httproute.yaml 中写入并应用 HTTPRoute web——父资源为服务 web(group "",kind Service,端口 80),两条规则:请求头 x-canary: yes 时转到 web-v2,其余转到 web-v1。应用后,client 带 x-canary: yes 的请求应得到 v2,不带请求头的请求始终是 v1。
在 Ambient 中,网格内部的路由同样用 Gateway API 来写。与 Ingress 不同之处在于,父资源不是 Gateway,而是服务(GAMMA)。实际处理这个路由的是 web 的 waypoint,所以没有 waypoint 的话路由不会生效。是否已经附加,可以通过 HTTPRoute 状态中的 ResolvedWaypoints 条件查看。
整理 L4 和 L7 分别由谁负责
在 /root/istlab-ambient/08-report.md 中写入六行——protocol=(第 1 步)、l7_without_waypoint=(第 4 步中 GET 规则被强制执行则为 enforced,被去掉则为 ignored)、broke_with_waypoint=(第 5 步的 code_after_waypoint)、l4_allowed_principal=(现在 web-l4 允许的主体)、post_via_waypoint=(现在 client 的 POST 状态码)、direct_pod_ip=(现在 client 直接访问 Pod IP 时为 allowed 或 rejected)——并在其下写出学到的内容,至少四行。
请同时对照前面步骤的记录和现在的状态。说明行中请写下“ztunnel 和 waypoint 各自看什么、强制执行什么”以及“附加 waypoint 时为什么要一并修改 L4 策略”。