驗(yàn)證網(wǎng)格內(nèi)部是否已啟用mTLS通信
mTLS加密通信是服務(wù)網(wǎng)格ASM提供的一項(xiàng)重要的基礎(chǔ)能力,您無(wú)需對(duì)應(yīng)用進(jìn)行改造,只需要給應(yīng)用Pod注入Sidecar代理就會(huì)默認(rèn)啟用mTLS。但由于mTLS是無(wú)感啟用的,無(wú)法直觀判斷流量是否真正進(jìn)行了加密,本文將介紹和演示如何確認(rèn)網(wǎng)格內(nèi)部是否啟用了mTLS通信。
背景信息
TLS(Transport Layer Security)是一個(gè)廣泛應(yīng)用于互聯(lián)網(wǎng)的安全協(xié)議,旨在為通信兩端提供安全的數(shù)據(jù)傳輸通道。常見(jiàn)的TLS通信通常只執(zhí)行單向的身份認(rèn)證,比如在瀏覽器中通過(guò)HTTPS訪問(wèn)一個(gè)網(wǎng)站時(shí),只需要網(wǎng)站服務(wù)器提供網(wǎng)站自身的證書,向客戶證明自己是這個(gè)網(wǎng)站的合法所有者,并不需要客戶提供證書證明客戶的身份。
普通的TLS通信僅執(zhí)行單向驗(yàn)證,服務(wù)器需要向客戶端提供證書來(lái)建立安全的連接;而在mTLS(Mutual Transport Layer Security)中,客戶端也必須向服務(wù)器提供證書,雙方需要相互驗(yàn)證對(duì)方的身份。如此一來(lái)就可以保證只有被授權(quán)的客戶端才能訪問(wèn)指定服務(wù)端。
服務(wù)網(wǎng)格中的授權(quán)機(jī)制依賴于mTLS協(xié)議來(lái)驗(yàn)證客戶端身份,這種互相認(rèn)證的機(jī)制能夠確保在服務(wù)網(wǎng)格中的每個(gè)服務(wù)調(diào)用都來(lái)自受信任的客戶端,從而為微服務(wù)通信提供了一層額外的安全保護(hù)。
以下將以sleep訪問(wèn)httpbin應(yīng)用為例,演示通過(guò)間接和直接的方式確認(rèn)網(wǎng)格內(nèi)部是否已啟用mTLS通信。
前提條件
已創(chuàng)建ASM實(shí)例。具體操作,請(qǐng)參見(jiàn)創(chuàng)建ASM實(shí)例。
已創(chuàng)建Kubernetes托管版集群。具體操作,請(qǐng)參見(jiàn)創(chuàng)建ACK托管集群。
已添加集群到ASM實(shí)例。具體操作,請(qǐng)參見(jiàn)添加集群到ASM實(shí)例。
已開啟Sidecar網(wǎng)格代理自動(dòng)注入。具體操作,請(qǐng)參見(jiàn)啟用自動(dòng)注入。
已經(jīng)部署了httpbin應(yīng)用,并且可以正常訪問(wèn),請(qǐng)參見(jiàn)部署httpbin應(yīng)用。
步驟一:部署sleep應(yīng)用
通過(guò)kubectl連接到ASM實(shí)例添加的Kubernetes集群,使用以下內(nèi)容創(chuàng)建sleep.yaml。
apiVersion: v1 kind: ServiceAccount metadata: name: sleep --- apiVersion: v1 kind: Service metadata: name: sleep labels: app: sleep service: sleep spec: ports: - port: 80 name: http selector: app: sleep --- apiVersion: apps/v1 kind: Deployment metadata: name: sleep spec: replicas: 1 selector: matchLabels: app: sleep template: metadata: labels: app: sleep spec: terminationGracePeriodSeconds: 0 serviceAccountName: sleep containers: - name: sleep image: registry.cn-hangzhou.aliyuncs.com/acs/curl:8.1.2 command: ["/bin/sleep", "infinity"] imagePullPolicy: IfNotPresent volumeMounts: - mountPath: /etc/sleep/tls name: secret-volume volumes: - name: secret-volume secret: secretName: sleep-secret optional: true ---
執(zhí)行以下命令,部署測(cè)試客戶端應(yīng)用sleep。
kubectl apply -f sleep.yaml
步驟二:驗(yàn)證是否已啟用mTLS
通過(guò)Header標(biāo)識(shí)間接確認(rèn)是否啟用mTLS
X-FORWARDED-CLIENT-CERT(XFCC)是一個(gè)特殊的Proxy Header,用來(lái)標(biāo)識(shí)請(qǐng)求從客戶端到服務(wù)端的途中經(jīng)過(guò)的部分或全部的客戶端或代理的證書信息。具體信息,請(qǐng)參見(jiàn)HTTP header manipulation。
在sleep應(yīng)用中使用curl
命令訪問(wèn)httpbin應(yīng)用時(shí),httpbin應(yīng)用收到的請(qǐng)求會(huì)攜帶XFCC header,標(biāo)識(shí)這個(gè)請(qǐng)求由sleep應(yīng)用發(fā)出,通過(guò)這個(gè)Header可以間接確定兩端通信中啟用了mTLS。
登錄ASM控制臺(tái),在左側(cè)導(dǎo)航欄,選擇 。
在網(wǎng)格管理頁(yè)面,單擊目標(biāo)實(shí)例名稱,然后在左側(cè)導(dǎo)航欄,選擇 。
在全局配置中的日志設(shè)置中找到X-FORWARDED-CLIENT-CERT,選中后點(diǎn)擊最下方的提交。
通過(guò)kubectl連接到ASM實(shí)例添加的Kubernetes集群,執(zhí)行以下命令在sleep應(yīng)用Pod中訪問(wèn)httpbin服務(wù)。
kubectl exec <sleep pod name> -- curl httpbin:8000 -I
執(zhí)行以下命令查看httpbin應(yīng)用Pod的日志。
kubectl logs <httpbin pod> -c istio-proxy | tail -1
預(yù)期輸出:
{"bytes_received":"0","bytes_sent":"0","downstream_local_address":"192.168.34.76:80","downstream_remote_address":"192.168.34.74:45042","duration":"2","istio_policy_status":"-","method":"HEAD","path":"/","protocol":"HTTP/1.1","request_id":"7bd9862b-69d8-4d14-bc62-4520b2b45370","requested_server_name":"outbound_.8000_._.httpbin.default.svc.cluster.local","response_code":"200","response_flags":"-","route_name":"default","start_time":"2024-06-11T11:24:04.163Z","trace_id":"-","upstream_cluster":"inbound|80||","upstream_host":"192.168.34.76:80","upstream_local_address":"127.0.0.6:54963","upstream_service_time":"2","upstream_response_time":"2","upstream_transport_failure_reason":"-","user_agent":"curl/8.1.2","x_forwarded_for":"-","authority_for":"httpbin:8000","x_forwarded_client_cert":"By=spiffe://cluster.local/ns/default/sa/httpbin;Hash=583116d4dfd7b548400031f5c8685ee4f8ca99f217aca2af8634022362988114;Subject="";URI=spiffe://cluster.local/ns/default/sa/sleep"}
從上述輸出中的XFCC header信息可以看到客戶端身份標(biāo)識(shí)是sleep應(yīng)用。
通過(guò)tcpdump抓包直接確認(rèn)是否啟用mTLS
本節(jié)在sleep應(yīng)用Pod中抓取sleep Sidecar發(fā)送給httpbin Sidecar的數(shù)據(jù)包。抓包有兩種方式可以實(shí)現(xiàn),您可以根據(jù)實(shí)際情況選擇。
抓包前請(qǐng)先刪除已有的httpbin Pod使其重啟,確保Sidecar之間的長(zhǎng)連接被強(qiáng)制斷開。
通過(guò)ASMPacketInspector實(shí)現(xiàn)抓包(ASM實(shí)例版本1.21以上)
通過(guò)kubectl連接到ASM實(shí)例,使用以下內(nèi)容創(chuàng)建ASMPacketInspector.yaml。
apiVersion: istio.alibabacloud.com/v1beta1 kind: ASMPacketInspector metadata: name: test spec: pod: clusterId: ${ACK Cluster ID} namespace: default name: ${sleep pod name} tcpDumpParams: '-i any port 80' duration: 60s fileName: sleep.pcap
執(zhí)行以下命令部署ASMPacketInspector資源。
kubectl apply -f ASMPacketInspector.yaml
ASMPacketInspector資源部署后,ASM會(huì)自動(dòng)在sleep pod中抓取80端口的數(shù)據(jù)包(httpbin pod暴露的服務(wù)端口),抓包時(shí)長(zhǎng)為60s。在此期間,通過(guò)kubectl連接到ASM實(shí)例添加的Kubernetes集群,執(zhí)行以下命令。
kubectl exec -it <sleep pod name> -c sleep -- sh -c 'for i in $(seq 1 30); do curl httpbin:8000 -I ; echo "request $i done"; done'
此命令會(huì)自動(dòng)從sleep pod向httpbin服務(wù)發(fā)送30次請(qǐng)求。
通過(guò)kubectl連接到ASM實(shí)例,執(zhí)行以下命令查看抓包結(jié)果。
kubectl get ASMPacketInspector test -o yaml
預(yù)期結(jié)果:
apiVersion: istio.alibabacloud.com/v1beta1 kind: ASMPacketInspector metadata: ****** spec: ****** status: completedAt: null conditions: - time: "2024-06-12T08:15:33Z" type: Inspecting - message: 'inspecting job status: Running' time: "2024-06-12T08:15:43Z" type: Inspecting - message: 'inspecting job status: Running' time: "2024-06-12T08:15:53Z" type: Inspecting - message: 'inspecting job status: Running' time: "2024-06-12T08:16:03Z" type: Inspecting - message: 'inspecting job status: Running' time: "2024-06-12T08:16:13Z" type: Inspecting - message: 'inspecting job status: Running' time: "2024-06-12T08:16:23Z" type: Inspecting filePath: /tmp/sleep.pcap phase: Inspecting runningOnNode: ******* startAt: "2024-06-12T08:15:43Z" taskId: inspector-zumnmwdc
從
status
部分的runningOnNode
可以看到抓包運(yùn)行的node,filePath
代表輸出文件的路徑。登錄到指定節(jié)點(diǎn)將文件下載到本地。
直接在sleep應(yīng)用Pod所在節(jié)點(diǎn)上抓包
通過(guò)kubectl連接到ASM實(shí)例添加的Kubernetes集群,執(zhí)行以下命令查看sleep應(yīng)用運(yùn)行在哪個(gè)Node上。
kubectl get pod -o wide
預(yù)期輸出:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES httpbin-6c8f47d9b9-stq72 2/2 Running 0 33m 172.16.*.* cn-***.172.16.*.* <none> <none> sleep-84f9785988-ft9rm 2/2 Running 0 3h56m 172.16.*.* cn-***.172.16.*.* <none> <none>
登錄到目標(biāo)節(jié)點(diǎn)。操作步驟詳情,請(qǐng)參見(jiàn)通過(guò)密碼或密鑰認(rèn)證登錄Linux實(shí)例。
執(zhí)行以下命令查看sleep應(yīng)用對(duì)應(yīng)的容器
CONTAINER ID
。sudo crictl ps |grep <Pod名稱關(guān)鍵字>
預(yù)期輸出:
CONTAINER IMAGE CREATED STATE a1a214d2***** 35d28df4***** 2 days ago Running
使用
CONTAINER ID
參數(shù),執(zhí)行以下命令查看容器PID。sudo crictl inspect a1a214d2***** |grep -i PID
預(yù)期輸出:
"pid": 2309838, # 目標(biāo)容器的PID進(jìn)程號(hào)。 "pid": 1 "type": "pid"
執(zhí)行以下抓包命令。
sudo nsenter -t <容器PID> tcpdump -i any port 80 -w /tmp/test.pcap
將命令執(zhí)行后生成的
test.pcap
文件下載到本地。
確保本地安裝了Wireshark,使用wireshark打開上述下載到本地pcap
格式文件,選擇對(duì)應(yīng)端口協(xié)議為TLS,可以看到如下結(jié)果。
通過(guò)對(duì)應(yīng)的TLS報(bào)文,可以確認(rèn)Sidecar之間通信使用了mTLS進(jìn)行了加密。
這里只能看到Client Hello和Server Hello,之后就是Application Data報(bào)文了。這里之所以沒(méi)有直接看到TLS的證書信息,是因?yàn)門LSv1.3中對(duì)后續(xù)的證書交換消息都進(jìn)行了加密,所以無(wú)法直接在WireShark中查看到證書的明文信息,這是正常現(xiàn)象。
相關(guān)文檔
您可以通過(guò)PeerAuthentication資源來(lái)配置服務(wù)之間的mTLS策略。請(qǐng)參見(jiàn)對(duì)等身份認(rèn)證(Peer Authentication)。