乐趣区

Istio开启mtls请求503问题分析

背景

为测试 Istio 流量管理,将两个服务 sleep、flaskapp 的两个版本 v1、v2(部署文件见参考链接) 部署到 Istio 环境中,通过 sleep-v1 向 flaskapp 发起调用 http://flaskapp/env/version,正常结果会交替打印出结果 v1 和 v2,然而在调用过程中报错 503 reset reason: connection failure,故将问题的步骤、现象、分析、验证整理于此。

步骤

部署 sleep、flaskapp 应用,同时 Istio 平台开启 mTls,命名空间 kangxzh 开启自动注入,部署如下图所示:

kubectl apply -f sleep.istio.yaml -n kangxzh
kubectl apply -f flask.isito.yaml -n kangxzh

#查看 pod 创建情况
kubectl -n kangxzh get pod -w

flaskapp-v1-775dbb9b79-z54fj   2/2     Running           0          13s
flaskapp-v2-d454cdd47-mdb8s    2/2     Running           0          14s
sleep-v1-7f45c6cf94-zgdsf      2/2     Running           0          19h
sleep-v2-58dff94b49-fz6sj      2/2     Running           0          19h 


现象

在 sleep 应用中发起 http 请求,调用 flaskapp,curl http://flaskapp/env/version,如下所示:

#
export SOURCE_POD=$(kubectl get pod -l app=sleep,version=v1 -o jsonpath={.items..metadata.name})
# 进入 sleep 发起 http 请求
kubectl -n kangxzh exec -it -c sleep $SOURCE_POD bash
bash-4.4# curl http://flaskapp/env/version
# 响应
upstream connect error or disconnect/reset before headers. reset reason: connection failure 

背景

1. 检测 flaskapp tls 配置,如下:

[root@kubernetes-master flaskapp]# istioctl authn tls-check flaskapp-v1-775dbb9b79-z54fj flaskapp.kangxzh.svc.cluster.local
HOST:PORT                                 STATUS     SERVER     CLIENT     AUTHN POLICY     DESTINATION RULE
flaskapp.kangxzh.svc.cluster.local:80     OK         mTLS       mTLS       default/         default/istio-system 

STATUS OK 证明 flaskapp tls 配置正确。

进入 sleep istio-proxy 向 flaskapp 发起 http 请求:

kubectl -n kangxzh exec -it -c istio-proxy $SOURCE_POD bash
# 发起请求
curl http://flaskapp/env/version
# 响应
v1 

2. 发现通过 istio-proxy 可以得到相应,因为开启了 mtls,通过 istio-proxy 直接请求是需要添加 istio 相关证书的,此时没有加入证书也可请求,所以想到检查 flaskapp iptables 配置,如下所示:

# 获取进程号
PID=$(docker inspect --format {{.State.Pid}} $(docker ps | grep flaskapp-v1 | awk '{print $1}' | head -n 1))
# 查看 iptables 规则
nsenter -t ${PID} -n iptables -t nat -L -n -v
# 输出
Chain PREROUTING (policy ACCEPT 477 packets, 28620 bytes)
 pkts bytes target     prot opt in     out     source               destination
  487 29220 ISTIO_INBOUND  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0

Chain INPUT (policy ACCEPT 487 packets, 29220 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 220 packets, 20367 bytes)
 pkts bytes target     prot opt in     out     source               destination
    0   480 ISTIO_OUTPUT  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0

Chain POSTROUTING (policy ACCEPT 220 packets, 20367 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain ISTIO_INBOUND (1 references)
 pkts bytes target     prot opt in     out     source               destination
   10   600 ISTIO_IN_REDIRECT  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:80    #是没有的,修改后增加

Chain ISTIO_IN_REDIRECT (1 references)
 pkts bytes target     prot opt in     out     source               destination
   10   600 REDIRECT   tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            redir ports 15001

Chain ISTIO_OUTPUT (1 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 ISTIO_REDIRECT  all  --  *      lo      0.0.0.0/0           !127.0.0.1
    8   480 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner UID match 1337
    0     0 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner GID match 1337
    0     0 RETURN     all  --  *      *       0.0.0.0/0            127.0.0.1
    0     0 ISTIO_REDIRECT  all  --  *      *       0.0.0.0/0            0.0.0.0/0

Chain ISTIO_REDIRECT (2 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 REDIRECT   tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            redir ports 15001 

证明 envoy 没有劫持到 flaskapp 80 的流量,也就是说上述第 2 步是 sleep-istio-proxy 直接请求 flaskapp,没有经过 flaskapp-istio-proxy 转发。

  1. 此时才检查 flaskapp deployment,如下所示:

---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: flaskapp-v1
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: flaskapp
        version: v1
    spec:
      containers:
      - name: flaskapp
        image: dustise/flaskapp
        imagePullPolicy: IfNotPresent
        ports:
          - name: http
            containerPort: 80  #缺少 containerPort
        env:
        - name: version
          value: v1
... 

官网说明 https://istio.io/docs/setup/k…:

Pod ports: Pods must include an explicit list of the ports each container listens on. Use a containerPort configuration in the container specification for each port. Any unlisted ports bypass the Istio proxy.
# 未列出来来的端口都会绕过 istio proxy 

同时 describe flaskapp pod 如下所示:

kubectl describe pod flaskapp-v1-6df8d69fb8-fb5mr -n kangxzh
#
istio-proxy:
    ... 省略若干
    Args:
      ...
      --concurrency
      2
      --controlPlaneAuthPolicy
      MUTUAL_TLS
      --statusPort
      15020
      --applicationPorts
      "" #为空 

在 deployment 中增加 containerPort: 80 后,如下所示:

istio-proxy:
    ... 省略若干
    Args:
      ...
      --concurrency
      2
      --controlPlaneAuthPolicy
      MUTUAL_TLS
      --statusPort
      15020
      --applicationPorts
      80 

注意:在 Istio1.2 版本以后也可通过设置 Pod annotation 中 traffic.sidecar.istio.io/includeInboundPorts 来达到同样的目的,缺省值为 Pod 的 containerPorts 列表,逗号分隔的监听端口列表,这些流量会被重定向到 Sidecar,* 会重定向所有端口,具体详情参见官网 1.2 新特性 (见参考链接)

验证

sleep 发起请求:

[root@kubernetes-master flaskapp]# kubectl -n kangxzh exec -it -c sleep $SOURCE_POD bash
bash-4.4# curl http://flaskapp/env/version
#响应
v1 

sleep-istio-proxy 未携带证书,发起请求:

kubectl -n kangxzh exec -it -c istio-proxy $SOURCE_POD bash
istio-proxy@sleep-v1-7f45c6cf94-zgdsf:/$ curl http://flaskapp/env/version
#响应
curl: (56) Recv failure: Connection reset by peer 
sleep-istio-proxy 携带证书,发起请求
istio-proxy@sleep-v1-7f45c6cf94-zgdsf:/$ curl https://flaskapp:80/env/version --key /etc/certs/key.pem --cert /etc/certs/cert-chain.pem --cacert /etc/certs/root-cert.pem -k
#响应
v1 


参考链接

https://github.com/fleeto/sleep

https://github.com/fleeto/fla…

https://istio.io/docs/setup/k…

https://preliminary.istio.io/…

退出移动版