Service Mesh (ASM)出口網關作為網格內流量的統一出口,可以執行TLS/mTLS請求的發起,進而實現全鏈路的加密通訊。同時,出口網關也可以執行豐富的安全性原則,實現更加精細的存取控制。在服務網格中,出口網關是實現出口流量管理的最佳方案。本文將介紹如何使用ASM出口網關管理出口流量並發起mTLS通訊。
請確保您已經完成在ASM入口網關上配置mTLS服務並限制特定用戶端訪問中的所有步驟,本文將使用此文檔中在ASM和ACK環境部署的應用作為外部mTLS服務端。因此在執行本文中的步驟時,您需要額外建立一套ASM和ACK環境作為主環境。為了方便區別,本文中提到的${ASM網關ip}
均代表在ASM入口網關上配置mTLS服務並限制特定用戶端訪問中使用的入口網關IP,“ACK叢集”和“ASM執行個體”均為主環境資源。
前提條件
已開啟sidecar自動注入。具體操作,請參見配置Sidecar注入策略。
步驟一:部署測試應用sleep
部署sleep應用,具體操作,請參見部署sleep應用。
使用ACK叢集的kubeconfig,執行以下命令測試訪問部署在另一套環境中的httpbin服務。
kubectl exec deploy/sleep -- curl --header "host:test.com" ${ASM網關ip}/status/418
預期輸出:
-=[ teapot ]=-
_...._
.' _ _ `.
| ."` ^ `". _,
\_;`"---"`|//
| ;/
\_ _/
`"""`
步驟二:開啟REGISTRY_ONLY並建立ServiceEntry
Sidecar支援配置外部存取策略為REGISTRY_ONLY
,開啟之後pod只能訪問通過ServiceEntry註冊的服務。您可以根據需要選擇是否開啟此項功能。具體開啟步驟,請參見步驟二:開啟REGISTRY_ONLY。開啟之後,訪問未經註冊的服務將會返回502 Bad Gateway
。
使用以下內容,為test.com配置ServiceEntry。具體操作,請參見建立叢集外服務。
apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
name: test-com
namespace: default
spec:
endpoints:
- address: ${ASM網關IP}
hosts:
- test.com
location: MESH_EXTERNAL
ports:
- name: http
number: 80
protocol: HTTP
- name: https
number: 443
protocol: HTTPS
resolution: STATIC
完成配置後,即可正常從sleep Pod中訪問httpbin服務。
步驟三:建立ASM出口網關,並讓HTTP協議請求經過出口網關
建立出口網關,配置HTTP協議和80連接埠,並開啟雙向TLS認證開關。此開關開啟之後,網格中其他工作負載向網關發送流量時會自動使用mTLS,該mTLS的認證由網格統一管理。具體操作,請參見建立出口網關。
使用以下內容,建立網關規則。具體操作,請參見建立網關規則。
apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: egress-gateway namespace: default spec: selector: istio: egressgateway servers: - hosts: - '*' port: name: http number: 80 protocol: HTTPS tls: mode: ISTIO_MUTUAL
網關規則中聲明了出口網關在80連接埠上開啟mTLS監聽,並且使用網格統一提供的認證。
使用以下內容,建立虛擬服務。
apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: egressgateway-vs spec: hosts: - test.com gateways: - egress-gateway # 上一步建立的網關規則名稱。 - mesh http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-system.svc.cluster.local port: number: 80 weight: 100 - match: - gateways: - egress-gateway port: 80 route: - destination: host: test.com port: number: 80 weight: 100
建立虛擬服務後,Sidecar中的
test.com
的流量將會發送給出口網關,出口網關收到的test.com
流量將發送給真正的test.com
ServiceEntry。執行以下命令,在sleep應用的Pod中訪問
test.com
。kubectl exec deploy/sleep -- curl --header "host:test.com" ${ASM網關ip}/status/418
預期輸出:
-=[ teapot ]=- _...._ .' _ _ `. | ."` ^ `". _, \_;`"---"`|// | ;/ \_ _/ `"""`
使用ASM執行個體的kubeconfig,執行以下命令。
kubectl -n istio-system logs ${出口網關pod名稱}| tail -1
預期輸出:
{"authority_for":"test.com","bytes_received":"0","bytes_sent":"135","downstream_local_address":"192.168.36.32:80","downstream_remote_address":"192.168.36.29:58146","duration":"8","istio_policy_status":"-","method":"GET","path":"/status/418","protocol":"HTTP/1.1","request_id":"9f7b5475-6e45-4700-a85a-e00835b6b6c0","requested_server_name":"outbound_.80_._.istio-egressgateway.istio-system.svc.cluster.local","response_code":"418","response_flags":"-","route_name":"-","start_time":"2024-07-29T03:05:58.421Z","trace_id":"-","upstream_cluster":"outbound|80||test.com","upstream_host":"${ASM網關IP}:80","upstream_local_address":"192.168.36.32:52838","upstream_response_time":"7","upstream_service_time":"7","upstream_transport_failure_reason":"-","user_agent":"curl/8.1.2","x_forwarded_for":"192.168.36.29"}
可以看到,上述日誌可以確認該服務經過了ASM出口網關。
當前的請求鏈路是:sleep pod --> istio-egressgateway --> istio-ingressgateway --> httpbin
。其中:
sleep pod --> istio-egressgateway
這段是mTLS流量。istio-egressgateway --> istio-ingressgateway
這段是明文流量。istio-ingressgateway --> httpbin
這段是mTLS流量。
顯然,兩個網關之間互動通過明文是不安全的。由於服務端網關已經支援了mTLS,因此只需要用戶端出口網關支援發起mTLS請求即可。
步驟四:在出口網關中將HTTP請求升級為mTLS流量
使用以下內容,更新虛擬服務。
apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: egressgateway-vs spec: hosts: - test.com gateways: - egress-gateway - mesh http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-system.svc.cluster.local port: number: 80 weight: 100 - match: - gateways: - egress-gateway port: 80 route: - destination: host: test.com port: number: 443 # 只修改了這一行 weight: 100
這裡的更新只是將發送給
test.com
ServiceEntry80連接埠的流量改為了443連接埠。匯入mTLS認證,即在ASM入口網關上配置mTLS服務並限制特定用戶端訪問中使用的認證。請確保此處匯入的認證名稱為
test.client
。具體操作,請參見使用ASM認證管理。您也可以使用kubectl直接建立secret完成認證匯入。使用ACK叢集的kubeconfig,執行以下命令。kubectl create -n istio-system secret generic test.client \ --from-file=tls.key=client.key.pem \ --from-file=tls.crt=clientcert.pem \ --from-file=ca.crt=cacert.pem
使用以下內容,建立目標規則。
apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: originate-mtls-for-test-com spec: host: test.com trafficPolicy: loadBalancer: simple: ROUND_ROBIN portLevelSettings: - port: number: 443 tls: mode: MUTUAL credentialName: test.client sni: test.com
執行以下命令,再次測試訪問。
kubectl exec deployment/sleep -it -- curl --header "host:test.com" ${ASM網關IP}/status/418
預期輸出:
RBAC: access denied%
可以看到請求被拒絕。這是由於這裡複用了在ASM入口網關上配置mTLS服務並限制特定用戶端訪問中的用戶端認證,其中配置了禁止test.client訪問
status/418
路徑。執行以下命令,訪問
status/200
路徑。kubectl exec deploy/sleep -it -- curl --header "host:test.com" ${ASM網關IP}/status/200 -I
預期輸出:
HTTP/1.1 200 OK server: envoy date: Mon, 29 Jul 2024 03:33:50 GMT content-type: text/html; charset=utf-8 access-control-allow-origin: * access-control-allow-credentials: true content-length: 0 x-envoy-upstream-service-time: 5
可以看到訪問正常。
執行以下命令,查看出口網關訪問日誌。
kubectl -n istio-system logs ${出口網關pod名稱}| tail -1
預期輸出:
{"authority_for":"test.com","bytes_received":"0","bytes_sent":"19","downstream_local_address":"192.168.36.32:80","downstream_remote_address":"192.168.36.29:58146","duration":"3","istio_policy_status":"-","method":"GET","path":"/status/418","protocol":"HTTP/1.1","request_id":"82394ec4-cf13-45cb-ae4c-cb1873fbccda","requested_server_name":"outbound_.80_._.istio-egressgateway.istio-system.svc.cluster.local","response_code":"403","response_flags":"-","route_name":"-","start_time":"2024-07-29T03:34:36.647Z","trace_id":"-","upstream_cluster":"outbound|443||test.com","upstream_host":"${ASM網關IP}:443","upstream_local_address":"192.168.36.32:42214","upstream_response_time":"2","upstream_service_time":"2","upstream_transport_failure_reason":"-","user_agent":"curl/8.1.2","x_forwarded_for":"192.168.36.29"}
可以看到這條請求訪問了入口網關的443連接埠,這個連接埠上只提供mTLS服務。
步驟五:後續配置
sleep Pod發起的是HTTP請求,在經過Sidecar和出口網關之後,全鏈路均使用了mTLS加密。mTLS加密是執行用戶端身份認證的基礎,在請求鏈路中,您可以在兩個地方配置授權策略,限制用戶端行為。
使用以下內容,在出口網關上配置授權策略,這可以限制叢集內哪些服務可以訪問
test.com
服務。apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: labels: gateway: egressgateway name: test namespace: istio-system spec: action: DENY rules: - from: - source: principals: - cluster.local/ns/default/sa/sleep to: - operation: hosts: - test.com paths: - /headers selector: matchLabels: istio: egressgateway
此配置限制了sleep Pod通過出口網關訪問
test.com
的/headers
路徑。在入口網關上配置授權策略,可以限制直接存取入口網關的用戶端身份。在步驟四中,由於之前在入口網關上配置的授權策略,使得當前出口網關無法訪問
/status/418
路徑。