通过 Istio 入口网关的 TLS 握手失败 (tlsMode=passthrough)
TLS handshake through Istio ingress gateway fails (tlsMode=passthrough)
从外部客户端到 Kubernetes 集群内服务器的 TLS 握手失败。这是关于理解为什么。
我已经配置了一个 Istio 入口网关以通过在端口 15433 上接收到的 TLS,并将其路由到端口 433 上的服务器。
当客户端尝试 TLS 握手时,入口网关日志显示 activity,但服务器日志和 istio-proxy 日志均不显示。
TLS 客户端:
openssl s_client \
-connect [redacted]-[redacted].us-west-2.elb.amazonaws.com:15443 \
-servername myservice.mynamespace \
-CAfile /path/to/ca.cert \
-cert /path/to/cert.pem \
-key /path/to/cert.key <<< "Q"
日志
CONNECTED(00000006)
140090868934296:error:140790E5:SSL routines:ssl23_write:ssl handshake failure:s23_lib.c:177:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 0 bytes and written 298 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.2
Cipher : 0000
Session-ID:
Session-ID-ctx:
Master-Key:
Key-Arg : None
PSK identity: None
PSK identity hint: None
SRP username: None
Start Time: 1600987862
Timeout : 300 (sec)
Verify return code: 0 (ok)
Istio 入口网关日志:
"- - -" 0 - "-" "-" 298 0 1069 - "-" "-" "-" "-" "192.168.101.136:443" outbound|443||myservice.mynamespace.svc.cluster.local 192.168.115.141:42350 192.168.115.141:15443 192.168.125.206:23298 myservice.mynamespace -
其中 192.168.101.136 是 myservice pod 的 IP,192.168.115.141 是 ingressgateway pod 的 IP。
根据 IP,这意味着客户端连接已到达网关,网关似乎已应用虚拟服务路由并记录它正在将其转发到 pod。看起来很正常,除了 pod 上的 istio-proxy 没有显示 activity 也没有服务器日志(尽管服务器不记录传输层发生的事情)。
据我所知,服务器已正确配置为 TLS,因为以下端口转发的 TLS 握手成功:
kubectl port-forward -n mynamespace service/myservice 4430:443 &
openssl s_client \
-connect localhost:4430 \
-CAfile /path/to/ca.cert \
-cert /path/to/cert.pem \
-key /path/to/cert.key <<< "Q"
# I get back a TLS session ID, looks good.
所以这表明 istio 的网关或虚拟服务配置存在问题。
网关:
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: mygateway
namespace: mynamespace
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 15443
name: tls-passthrough
protocol: TLS
tls:
mode: PASSTHROUGH
hosts:
- "*"
虚拟服务:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: myservice
namespace: mynamespace
spec:
hosts:
- "*"
gateways:
- mygateway
tls:
- match:
- port: 15443
sniHosts:
- myservice.mynamespace
route:
- destination:
host: myservice
port:
number: 443
Kubernetes 服务:
apiVersion: v1
kind: Service
metadata:
name: myservice
namespace: mynamespace
labels:
app: myservice
spec:
selector:
app: myservice
ports:
- protocol: TCP
port: 443
targetPort: 443
name: grpc-svc
更新:
实际上,来自客户端的 TLS 流量确实到达了服务器 pod,我已经通过在服务器 pod 上执行 tcpdump port 443
并在我 运行 openssl s_client 命令时看到数据包来确认这一点。不清楚为什么 pod 上的 istio-proxy 没有显示这个,这并不能解释为什么握手失败。
我注意到了其他事情。将 -msg
标志传递给 openssl s_client
,我没有看到任何返回,在“>>>”之后没有“<<<”,但 tcpdump 显示服务器 pod 将数据包发送回网关。
我的配置中有 2 个错误:
在我的 Kubernetes 服务的配置中。不幸的是,我的 TCP 端口 443 的名称是 grpc-svc
,这会破坏 TLS 直通。将此端口重命名为 tcp-svc
即可解决问题。
我不应该使用入口端口 15443,它似乎是为其他东西保留的。在入口网关上打开另一个端口 9444,然后完全按照我在问题中配置端口 15443 的方式在网关上配置端口 9444(即 TLS 直通配置),然后将虚拟服务配置为路由 9444,就像我配置虚拟服务一样我的问题是 15433 的路线。
同时执行这两个操作允许外部客户端 openssl s_client
通过入口成功与 kubernetes 服务进行 TLS 握手。
从外部客户端到 Kubernetes 集群内服务器的 TLS 握手失败。这是关于理解为什么。
我已经配置了一个 Istio 入口网关以通过在端口 15433 上接收到的 TLS,并将其路由到端口 433 上的服务器。
当客户端尝试 TLS 握手时,入口网关日志显示 activity,但服务器日志和 istio-proxy 日志均不显示。
TLS 客户端:
openssl s_client \
-connect [redacted]-[redacted].us-west-2.elb.amazonaws.com:15443 \
-servername myservice.mynamespace \
-CAfile /path/to/ca.cert \
-cert /path/to/cert.pem \
-key /path/to/cert.key <<< "Q"
日志
CONNECTED(00000006)
140090868934296:error:140790E5:SSL routines:ssl23_write:ssl handshake failure:s23_lib.c:177:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 0 bytes and written 298 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.2
Cipher : 0000
Session-ID:
Session-ID-ctx:
Master-Key:
Key-Arg : None
PSK identity: None
PSK identity hint: None
SRP username: None
Start Time: 1600987862
Timeout : 300 (sec)
Verify return code: 0 (ok)
Istio 入口网关日志:
"- - -" 0 - "-" "-" 298 0 1069 - "-" "-" "-" "-" "192.168.101.136:443" outbound|443||myservice.mynamespace.svc.cluster.local 192.168.115.141:42350 192.168.115.141:15443 192.168.125.206:23298 myservice.mynamespace -
其中 192.168.101.136 是 myservice pod 的 IP,192.168.115.141 是 ingressgateway pod 的 IP。
根据 IP,这意味着客户端连接已到达网关,网关似乎已应用虚拟服务路由并记录它正在将其转发到 pod。看起来很正常,除了 pod 上的 istio-proxy 没有显示 activity 也没有服务器日志(尽管服务器不记录传输层发生的事情)。
据我所知,服务器已正确配置为 TLS,因为以下端口转发的 TLS 握手成功:
kubectl port-forward -n mynamespace service/myservice 4430:443 &
openssl s_client \
-connect localhost:4430 \
-CAfile /path/to/ca.cert \
-cert /path/to/cert.pem \
-key /path/to/cert.key <<< "Q"
# I get back a TLS session ID, looks good.
所以这表明 istio 的网关或虚拟服务配置存在问题。
网关:
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: mygateway
namespace: mynamespace
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 15443
name: tls-passthrough
protocol: TLS
tls:
mode: PASSTHROUGH
hosts:
- "*"
虚拟服务:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: myservice
namespace: mynamespace
spec:
hosts:
- "*"
gateways:
- mygateway
tls:
- match:
- port: 15443
sniHosts:
- myservice.mynamespace
route:
- destination:
host: myservice
port:
number: 443
Kubernetes 服务:
apiVersion: v1
kind: Service
metadata:
name: myservice
namespace: mynamespace
labels:
app: myservice
spec:
selector:
app: myservice
ports:
- protocol: TCP
port: 443
targetPort: 443
name: grpc-svc
更新:
实际上,来自客户端的 TLS 流量确实到达了服务器 pod,我已经通过在服务器 pod 上执行 tcpdump port 443
并在我 运行 openssl s_client 命令时看到数据包来确认这一点。不清楚为什么 pod 上的 istio-proxy 没有显示这个,这并不能解释为什么握手失败。
我注意到了其他事情。将 -msg
标志传递给 openssl s_client
,我没有看到任何返回,在“>>>”之后没有“<<<”,但 tcpdump 显示服务器 pod 将数据包发送回网关。
我的配置中有 2 个错误:
在我的 Kubernetes 服务的配置中。不幸的是,我的 TCP 端口 443 的名称是
grpc-svc
,这会破坏 TLS 直通。将此端口重命名为tcp-svc
即可解决问题。我不应该使用入口端口 15443,它似乎是为其他东西保留的。在入口网关上打开另一个端口 9444,然后完全按照我在问题中配置端口 15443 的方式在网关上配置端口 9444(即 TLS 直通配置),然后将虚拟服务配置为路由 9444,就像我配置虚拟服务一样我的问题是 15433 的路线。
同时执行这两个操作允许外部客户端 openssl s_client
通过入口成功与 kubernetes 服务进行 TLS 握手。