先上解决办法
option 1: 直接全局关闭mtls
$ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: "default"
namespace: "istio-system"
spec:
mtls:
mode: DISABLE
EOF
option2:使用mtls的STRICT模式
$ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: "default"
namespace: "istio-system"
spec:
mtls:
mode: STRICT
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: mysql-mtls-dr
spec:
host: YOUR-MYSQL-SERVICE
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
EOF
现象
istio是服务网格的一种实践,官方的说法是Service Mesh. Simplified.
众所周知的是service mesh会对服务的网络做一些治理,而我就碰到了mysql在istio环境下的无法连接的问题。
原因
1.istio协议选择
Istio 默认支持代理所有 TCP 流量。包括 HTTP、HTTPS、gRPC 以及原始 TCP 协议。但为了提供额外的能力, 比如路由和丰富的指标,必须确定协议。协议可以被自动检测或者手动声明。
使用非基于 TCP 的协议时,如 UDP,不会被 Istio 代理拦截,可以继续正常工作。 但是不能在仅代理的组件中使用,如 Ingress 或 Egress Gateway。
协议可以在 Service 定义中手动指定:
方法1: 通过端口名称配置:name: <protocol>[-<suffix>]
方法2: 在版本 1.18+ 的Kubernetes,通过 appProtocol 字段配置:appProtocol: <protocol>
对于没有指定协议的场景呢,istio 可以自动检测出 HTTP 和 HTTP/2 流量。如果未自动检测出协议,流量将会视为普通 TCP 流量
其中官网中特别提到mysql对自动检测协议的不兼容
Server First protocols, such as MySQL, are incompatible with automatic protocol selection. See Server first protocols for more information.
2. 服务器优先协议
从istio官网中我们知道了,所有服务器优先(server first)协议都是不支持自动检测的。
“服务器优先” 协议意味着服务器将发送第一个字节,而istio的 PERMISSIVE mTLS 和自动协议选择都是通过检查连接的初始字节来确定协议,这与服务器优先协议不兼容。
官网给出了以下几个解决办法
1. Configure mTLS mode STRICT for the server. This will enforce TLS encryption for all requests.
2. Configure mTLS mode DISABLE for the server. This will disable the TLS sniffing, allowing server first protocols to be used.
3. Configure all clients to send TLS traffic, generally through a DestinationRule or by relying on auto mTLS.
4. Configure your application to send TLS traffic directly.
我稍微解释一下为啥这几个办法有效, 解释之前我们补充一下理论知识,首先要知道TLS通讯不是服务器优先的,所以所有的TLS请求是可以兼容istio的自动协议选择的,第二istio的mTLS默认是PERMISSIVE模式,也就是纵容模式,这种模式下代理将接受mTLS和纯文本流量,而如前文所说纯文本流量是不支持server first的。
现在我们就可以逐条解释原因了,实际上可以总结为2点:
- 关闭mTLS,这将允许server first协议
- 将所有服务设置为TLS流量,可以通过DestinationRule或者应用原生支持或者其他什么办法