TT Lab
开始
学习 学习路径 课程

Istio 实测实验室

为 Kubernetes 之外的机器赋予同样的身份

在 TT Lab 中继续学习

目标

在用同一台 VM 内的网络命名空间构造的“网格之外的机器”上启动 VM 用的 sidecar,用 WorkloadGroup 和 WorkloadEntry 把它纳入网格,并确认双向 mTLS 以及 STRICT、授权策略会与 Pod 完全一样地生效。

为什么重要

没能迁移到容器中的机器,很容易成为网格的例外,而例外会导致 PERMISSIVE 或宽泛的放行规则,变成安全漏洞。如果给这台机器同样的 sidecar 和同样的身份,就可以无例外地施加同样的策略。这个流程很长,在名称解析、令牌和拦截规则上很容易卡住,所以完整做一遍是最快的学习方式。

步骤

  1. 用 kubectl apply -f /opt/fixtures/istlab/vmworkload-app.yaml 部署材料,等待 Pod 就绪。这台 VM 中有网络命名空间 legacy(192.168.77.2),应用在其中监听 8080。在 /root/istlab-vm/01-outside.txt 中写入三行——在 client 中访问 http://192.168.77.2:8080/ 的状态码 from_client=,在网格之外的 probe 中发出同样请求的状态码 from_outside=,以及 istioctl proxy-status 中能看到 legacy 则为 yes、否则为 no 的 in_mesh=。
  2. 在 /root/istlab-vm/vmns.yaml 中写入并应用四个资源——命名空间 vmns(带注入标签)、服务账号 legacy-sa、WorkloadGroup legacy(元数据标签 app: legacy,模板中的服务账号 legacy-sa,端口 http: 8080),以及用选择器 app: legacy 暴露 8080 的 Service legacy(端口名称 http)。
  3. 把 kubectl -n vmns get workloadgroup legacy -o yaml 的输出保存到 /root/istlab-vm/wg.yaml,并用 istioctl x workload entry configure -f /root/istlab-vm/wg.yaml -o /root/istlab-vm/files --clusterID Kubernetes --ingressIP <istiod 서비스의 ClusterIP> --internalIP 192.168.77.2(占位符为 istiod 服务的 ClusterIP)生成 VM 用的文件。/root/istlab-vm/files 中应生成 cluster.env、istio-token、mesh.yaml、root-cert.pem、hosts。
  4. 把第 3 步的文件放到官方文档指定的位置(root-cert.pem → /etc/certs/root-cert.pem,istio-token → /var/run/secrets/tokens/istio-token,cluster.env → /var/lib/istio/envoy/cluster.env,mesh.yaml → /etc/istio/config/mesh,hosts 中的行追加到命名空间用的 /etc/netns/legacy/hosts),把所有者改为 istio-proxy 后,在命名空间内启动 /usr/local/bin/istio-start.sh(工作目录 /,POD_NAME=legacy-vm)。istioctl proxy-status 中应能看到 legacy-vm.vmns,并在 /root/istlab-vm/04-iptables.txt 中写入两行:netns_backend=(命名空间内含有 ISTIO 规则的一侧:legacy 或 nft)和 host_istio_rules=(主机 nat 表——nft 和 legacy 两者——中的 ISTIO 规则数量)。
  5. 在 /root/istlab-vm/workloadentry.yaml 中写入并应用 WorkloadEntry legacy-vm(命名空间 vmns,地址 192.168.77.2,标签 app: legacy,服务账号 legacy-sa)。应用后,在 client 中访问 http://legacy.vmns:8080/ 应返回正文 legacy-vm 和 200。
  6. 在命名空间内带上 x-request-id 访问 http://web.shop/,并把接收该请求的 web sidecar 的访问日志中的一行原样保存到 /root/istlab-vm/06-from-vm.log。
  7. 在 /root/istlab-vm/secure.yaml 中写入并应用两个资源——vmns 的 PeerAuthentication strict(STRICT)和 AuthorizationPolicy legacy-only-client(选择器 app: legacy,ALLOW,主体 cluster.local/ns/shop/sa/client)。应用后,client 应得到 200,other 中的 intruder 应得到 403,网格之外的 probe 以明文访问 192.168.77.2:8080 时连接应被断开。
  8. 在 /root/istlab-vm/08-report.md 中写入五行——vm_identity=(VM sidecar 所获得证书的 SPIFFE URI)、netns_iptables_backend=、host_istio_rules=(第 4 步)、plain_from_outside=(现在 probe 的明文请求能通则为 allowed,被断开则为 rejected)、intruder=(现在 intruder 的状态码)——并在其下写出学到的内容,至少四行。

参考

网格之外的机器现在是什么样子

用 kubectl apply -f /opt/fixtures/istlab/vmworkload-app.yaml 部署材料,等待 Pod 就绪。这台 VM 中有网络命名空间 legacy(192.168.77.2),应用在其中监听 8080。在 /root/istlab-vm/01-outside.txt 中写入三行——在 client 中访问 http://192.168.77.2:8080/ 的状态码 from_client=,在网格之外的 probe 中发出同样请求的状态码 from_outside=,以及 istioctl proxy-status 中能看到 legacy 则为 yes、否则为 no 的 in_mesh=。

网络命名空间是内核单独提供的网络栈——地址、路由表、iptables 全都是独立的,所以即使在同一台 VM 里,它的行为也像“另一台机器”。它与主机之间通过一对 veth(192.168.77.1 ↔ 192.168.77.2)相连,从 Pod 发往该地址的流量由主机路由。要查看内部时,使用 ip netns exec legacy <명령>(占位符为命令)。现在这台机器对网格来说是一个不认识的地址,所以 client 的 sidecar 只会直接放行。

为 VM 准备的模板——WorkloadGroup 和服务

在 /root/istlab-vm/vmns.yaml 中写入并应用四个资源——命名空间 vmns(带注入标签)、服务账号 legacy-sa、WorkloadGroup legacy(元数据标签 app: legacy,模板中的服务账号 legacy-sa,端口 http: 8080),以及用选择器 app: legacy 暴露 8080 的 Service legacy(端口名称 http)。

WorkloadGroup 是为 VM 准备的 Pod 模板——像标签、服务账号、端口这样,写明“这样的机器以这样的身份打开这个端口”。Kubernetes Service 的选择器不仅会选中 Pod,也会选中 Istio 的 WorkloadEntry,所以可以把 VM 放在已有的服务名称后面。目前还没有一台 VM(WorkloadEntry),所以服务的端点是空的。

生成要交给 VM 的文件

把 kubectl -n vmns get workloadgroup legacy -o yaml 的输出保存到 /root/istlab-vm/wg.yaml,并用 istioctl x workload entry configure -f /root/istlab-vm/wg.yaml -o /root/istlab-vm/files --clusterID Kubernetes --ingressIP <istiod 서비스의 ClusterIP> --internalIP 192.168.77.2(占位符为 istiod 服务的 ClusterIP)生成 VM 用的文件。/root/istlab-vm/files 中应生成 cluster.env、istio-token、mesh.yaml、root-cert.pem、hosts。

VM 的 sidecar 需要知道五件事——自己是谁(cluster.env 中的命名空间、服务账号、标签)、首次获取证书时出示的令牌(istio-token,服务账号令牌)、网格配置(mesh.yaml)、要信任的根(root-cert.pem),以及用来查找 istiod 的地址(hosts)。如果是跨多个网络的安装,要给出东西向网关的地址,但在这台 VM 上,网络命名空间会借助主机的 kube-proxy 规则直接到达 istiod 的 ClusterIP。istiod 的地址用 kubectl -n istio-system get svc istiod -o jsonpath='{.spec.clusterIP}' 获取。

在网格之外的机器上启动 sidecar

把第 3 步的文件放到官方文档指定的位置(root-cert.pem → /etc/certs/root-cert.pem,istio-token → /var/run/secrets/tokens/istio-token,cluster.env → /var/lib/istio/envoy/cluster.env,mesh.yaml → /etc/istio/config/mesh,hosts 中的行追加到命名空间用的 /etc/netns/legacy/hosts),把所有者改为 istio-proxy 后,在命名空间内启动 /usr/local/bin/istio-start.sh(工作目录 /,POD_NAME=legacy-vm)。istioctl proxy-status 中应能看到 legacy-vm.vmns,并在 /root/istlab-vm/04-iptables.txt 中写入两行:netns_backend=(命名空间内含有 ISTIO 规则的一侧:legacy 或 nft)和 host_istio_rules=(主机 nat 表——nft 和 legacy 两者——中的 ISTIO 规则数量)。

istio-sidecar.deb(配方已经装好)会放入 pilot-agent、envoy 和 istio-start.sh。istio-start.sh 会用 iptables 植入拦截规则,并以 istio-proxy 用户启动 pilot-agent。用 ip netns exec legacy setsid --fork nohup env POD_NAME=legacy-vm /usr/local/bin/istio-start.sh > 로그 2>&1 </dev/null(占位符为日志文件)在命名空间内运行它,规则就只会进入该命名空间的 iptables。脚本使用 ./var/lib/istio 这样的相对路径,所以请在 cd / 之后启动。规则用 ip netns exec legacy iptables-legacy -t nat -S 和 iptables-nft 查看,主机一侧则不加命名空间直接查看。日志在 /var/log/istio/istio.log。

把一台 VM 放到服务后面——WorkloadEntry

在 /root/istlab-vm/workloadentry.yaml 中写入并应用 WorkloadEntry legacy-vm(命名空间 vmns,地址 192.168.77.2,标签 app: legacy,服务账号 legacy-sa)。应用后,在 client 中访问 http://legacy.vmns:8080/ 应返回正文 legacy-vm 和 200。

WorkloadEntry 是把一台 VM 表示为类似 Pod 的资源。标签与服务 legacy 的选择器匹配,所以 istiod 会把这个地址作为该服务的端点下发给各个 sidecar。client 的 sidecar 与 VM 的 sidecar 之间用 mTLS 通信,在进入的一侧,由命名空间内的 iptables 把 8080 转给 VM 的 sidecar。在 istioctl proxy-config endpoints client.shop --cluster 'outbound|8080||legacy.vmns.svc.cluster.local' 中应能看到 192.168.77.2。这套安装关闭了自动注册,所以要手工创建。

在 VM 上按名称访问网格内的服务

在命名空间内带上 x-request-id 访问 http://web.shop/,并把接收该请求的 web sidecar 的访问日志中的一行原样保存到 /root/istlab-vm/06-from-vm.log。

VM 的 sidecar 同样开启了 DNS 代理(cluster.env 中的 ISTIO_META_DNS_CAPTURE),所以能解析集群服务名称,发出的请求由 sidecar 接收后通过 mTLS 发送。请在 web 一侧的日志中查看该请求的来源是不是 192.168.77.2,SNI 是不是 outbound_.80_._.web.shop.svc.cluster.local——这就是它不是明文、而是网格内连接的证据。发起访问时用 ip netns exec legacy curl …。

在 VM 前面也设置 mTLS 和授权

在 /root/istlab-vm/secure.yaml 中写入并应用两个资源——vmns 的 PeerAuthentication strict(STRICT)和 AuthorizationPolicy legacy-only-client(选择器 app: legacy,ALLOW,主体 cluster.local/ns/shop/sa/client)。应用后,client 应得到 200,other 中的 intruder 应得到 403,网格之外的 probe 以明文访问 192.168.77.2:8080 时连接应被断开。

无论是 Pod 还是 VM,PeerAuthentication 和 AuthorizationPolicy 都通过工作负载标签来选择。VM 的 sidecar 带着 cluster.env 中的标签(app: legacy)连上了 istiod,所以同样的策略会下发给 VM 的 sidecar。从网格之外以明文进入的请求,由命名空间内的 iptables 转给 sidecar,而处于 STRICT 的 sidecar 会断开这个连接。策略扩散需要几秒钟。

写下网格之外的机器进入网格的路径

在 /root/istlab-vm/08-report.md 中写入五行——vm_identity=(VM sidecar 所获得证书的 SPIFFE URI)、netns_iptables_backend=、host_istio_rules=(第 4 步)、plain_from_outside=(现在 probe 的明文请求能通则为 allowed,被断开则为 rejected)、intruder=(现在 intruder 的状态码)——并在其下写出学到的内容,至少四行。

VM sidecar 的证书可以在命名空间内通过 Envoy 管理端口查看——把 ip netns exec legacy curl -s 'localhost:15000/config_dump?resource=dynamic_active_secrets' 中的 default 证书用 base64 解码,再用 openssl x509 -noout -ext subjectAltName 读取(它不是 Pod,所以 istioctl proxy-config 连不上这个代理)。