全部產品
Search
文件中心

Alibaba Cloud Service Mesh:使用ASMEgressTrafficPolicy管理出口流量

更新時間:Sep 04, 2024

ASM自1.16.4版本起,支援使用ASMEgressTrafficPolicy CRD。本文介紹如何使用ASMEgressTrafficPolicy管理出口流量。

前提條件

  • 已建立ASM商業版執行個體(企業版或旗艦版),且版本為1.16.4及以上。關於建立執行個體的具體操作,請參見建立ASM執行個體;關於升級執行個體的具體操作,請參見升級ASM執行個體

  • 已為default命名空間開啟自動注入。具體操作,請參見啟用自動注入

功能介紹

ASM提供了一種統一的方式來串連、管理和保護應用程式之間的通訊。與基於網路IP的方法不同,ASM採用以應用程式為中心的方法,且無需修改現有的應用代碼。ASMEgressTrafficPolicy定義了如何通過出口網關來管理和訪問外部流量。通過結合ASM出口網關和AuthorizationPolicy,您可以更靈活地控制出口流量。Dingtalk_20230411112608

本文樣本的流量鏈路可以分為兩大類:

1. 網格代理之間以及網格代理和網關之間的通訊:通訊預設開啟mTLS,認證完全由ASM管理。

2. 應用與網格代理之間以及網關和叢集外服務之間:

a. 為了網格7層進階能力可以正常運行,應用與網格代理之間盡量採用明文通訊。這樣網格代理可以擷取流量的L7資訊,支援更多的進階功能。如果由於某些特殊原因,應用必須直接發起HTTPS,這時只能使用網格的L4能力。

b. 出口網關和外部服務之間的通訊協定使用者可以自行配置,明文或者HTTPS都可以。

準備工作

一、設定外部服務存取原則

  1. 登入ASM控制台,在左側導覽列,選擇服務網格 > 網格管理

  2. 網格管理頁面,單擊目標執行個體名稱,然後在左側導覽列,選擇資料面組件管理 > Sidecar代理配置

  3. 全域頁簽,單擊外部服務存取原則,然後在對外部服務的存取原則OutboundTrafficPolicy右側,單擊REGISTRY_ONLY,然後單擊更新設定

二、建立命名空間

  1. 建立istio-egress命名空間。具體操作,請參見管理全域命名空間

  2. 全域命名空間頁面,單擊同步自動注入至Kubernetes叢集,將該命名空間同步至ASM執行個體管理的ACK叢集。

三、建立出口網關

在ASM中建立一個名為egressgateway-a的出口網關,連接埠映射配置為HTTP 80、HTTPS 443和HTTPS 444,並開啟支援雙向TLS認證。具體操作,請參見建立出口網關服務

請確保在產生的YAML檔案中,spec欄位中包含以下內容。若不存在,請進行添加。

spec:
  podLabels:
    security.istio.io/tlsMode: istio

四、建立應用樣本

  1. 在ASM執行個體中,建立名為mytest的命名空間並開啟自動注入。具體操作,請參見管理全域命名空間

  2. 在ACK叢集中,在mytest命名空間中部署sleep-a服務,在default命名空間中部署nginx服務。

    1. 使用以下內容,建立test.yaml

      展開查看YAML檔案

      apiVersion: v1
      kind: Service
      metadata:
        name: sleep-a
        namespace: mytest
        labels:
          app: sleep-a
          service: sleep-a
      spec:
        ports:
        - port: 80
          name: http
        selector:
          app: sleep-a
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: sleep-a
        namespace: mytest
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: sleep-a
        template:
          metadata:
            labels:
              app: sleep-a
          spec:
            terminationGracePeriodSeconds: 0
            containers:
            - name: sleep
              image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/curl:asm-sleep
              command: ["/bin/sleep", "infinity"]
              imagePullPolicy: IfNotPresent
              volumeMounts:
              - mountPath: /etc/sleep/tls
                name: secret-volume
            volumes:
            - name: secret-volume
              secret:
                secretName: sleep-secret
                optional: true
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        labels:
          app: nginx
        name: nginx
        namespace: default
      spec:
        progressDeadlineSeconds: 600
        replicas: 1
        revisionHistoryLimit: 10
        selector:
          matchLabels:
            app: nginx
        strategy:
          rollingUpdate:
            maxSurge: 25%
            maxUnavailable: 25%
          type: RollingUpdate
        template:
          metadata:
            creationTimestamp: null
            labels:
              app: nginx
          spec:
            containers:
            - image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/nginx:1.27.0
              imagePullPolicy: Always
              name: nginx
              resources: {}
              terminationMessagePath: /dev/termination-log
              terminationMessagePolicy: File
            dnsPolicy: ClusterFirst
            restartPolicy: Always
            schedulerName: default-scheduler
            securityContext: {}
            terminationGracePeriodSeconds: 30
    2. 在ACK叢集中,執行以下命令,部署sleep-a和nginx服務。

      kubectl apply -f test.yaml
  3. 執行以下命令,通過sleep-a和nginx服務訪問http://www.httpbin.org

    kubectl -n mytest exec deployment/sleep-a -- curl -s -o /dev/null -w "%{http_code}\n" http://www.httpbin.org
    kubectl -n default exec deployment/nginx -- curl -s -o /dev/null -w "%{http_code}\n" http://www.httpbin.org

    輸出結果均返回502,表明訪問失敗。

sleep-a服務訪問HTTP外部服務

方案一:sidecar到出口網關之間使用HTTP明文

此方案在實際環境中並不合理,目前ASMEgressTrafficPolicy並不支援使用HTTP明文訪問出口網關。

  • 流量管理主要在用戶端sidecar實施,並不需要出口網關。

  • 可觀測不依賴出口網關。

  • 安全能力依賴出口網關,但是如果沒有mTLS,基於用戶端身份的所有授權能力將不可用。出口網關只能無差別地拒絕所有請求。

方案二:sidecar到出口網關之間使用mTLS(推薦方案)

  1. 使用以下內容,建立egress-by-egressgateway.yaml

    關於欄位的相關說明,請參見ASMEgressTrafficPolicy CRD說明

    apiVersion: istio.alibabacloud.com/v1
    kind: ASMEgressTrafficPolicy
    metadata:
      name: egress-by-egressgateway  # 名稱約定為egress-by-{出口網關名稱},與出口網關對應。
      namespace: istio-egress         # 命名空間約定:固定到istio-egress命名空間。
    spec:
      byEgressGateway:
        name: egressgateway
      egressRules:
      - from:
        - namespace: mytest
          workloadSelector:
            app: sleep-a
        to:
        - name: httpbin-service-http
          hosts:
          - www.httpbin.org  # 要求多個網域名稱對應DNS解析返回的地址保持一致。
          - httpbin.org      # 要求多個網域名稱對應DNS解析返回的地址保持一致。
          port:
            name: http
            number: 80
            protocol: HTTP
          byEgressGateway:
            port: 80        # Sidecar → 80 Gateway → 80 Service (httpbin.org)
  2. 在ACK叢集中,執行以下命令,建立ASMEgressTrafficPolicy資源。

    kubectl apply -f egress-by-egressgateway.yaml
  3. 驗證ASMEgressTrafficPolicy配置是否生效。

    1. 執行以下命令,通過default命名空間下的nginx服務訪問http://www.httpbin.org

      kubectl -n default exec deployment/nginx -- curl -s -o /dev/null -w "%{http_code}\n" http://www.httpbin.org

      輸出結果返回502,表明nginx服務訪問http://www.httpbin.org失敗。

    2. 執行以下命令,通過mytest命名空間下的sleep-a服務訪問http://www.httpbin.org

      kubectl -n mytest exec deployment/sleep-a -- curl  -s -o /dev/null -w "%{http_code}\n"  http://www.httpbin.org

      輸出結果返回200,符合預期。

    3. 執行以下命令,刪除egress-by-egressgateway後,再次通過mytest命名空間下的sleep-a服務訪問http://www.httpbin.org

      kubectl -n istio-egress delete ASMEgressTrafficPolicy  egress-by-egressgateway
      kubectl -n mytest exec deployment/sleep-a -- curl -s -o /dev/null -w "%{http_code}\n" http://www.httpbin.org

      輸出結果返回502,表明刪除ASMEgressTrafficPolicy配置後,sleep-a服務http://www.httpbin.org失敗。

    輸出以上結果,表明ASMEgressTrafficPolicy配置生效。

sleep-a服務訪問HTTPS外部服務

方案一:sidecar到出口網關之間使用mTLS(推薦方案)

  1. 使用以下內容,更新egress-by-egressgateway.yaml

    spec欄位下增加了httpsUpgrade欄位和直接存取https://www.httpbin.org的相關定義。關於欄位的相關說明,請參見ASMEgressTrafficPolicy CRD說明

    apiVersion: istio.alibabacloud.com/v1
    kind: ASMEgressTrafficPolicy
    metadata:
      name: egress-by-egressgateway  # 名稱約定為egress-by-{出口網關名稱},與出口網關對應。
      namespace: istio-egress          # 命名空間約定:固定到istio-egress命名空間。
    spec:
      byEgressGateway:
        name: egressgateway
      egressRules:
      - from:
         - namespace: mytest
           workloadSelector:
              app: sleep-a
        to:
        - name: httpbin-service-http
          hosts:
          - www.httpbin.org  # 要求多個網域名稱對應DNS解析返回的地址一致。
          - httpbin.org      # 要求多個網域名稱對應DNS解析返回的地址一致。
          port:
            name: http
            number: 80
            protocol: HTTP
          byEgressGateway:
            port: 80        # Sidecar → 80 Gateway → 80 Service (httpbin.org)
          httpsUpgrade:
            enabled: true   # 若enabled配置為false,則httpsUpgrade對應的port不生效。
            port: 443       # Sidecar → 80 Gateway → 443 Service (httpbin.org)
  2. 在ACK叢集中,執行以下命令,建立ASMEgressTrafficPolicy資源。

    kubectl apply -f egress-by-egressgateway.yaml
  3. 驗證ASMEgressTrafficPolicy配置是否生效。

    1. 驗證mytest命名空間下的sleep-a服務。

      1. 執行以下命令,通過sleep-a服務訪問http://www.httpbin.org

        kubectl -n mytest exec deployment/sleep-a -- curl -s -o /dev/null -w "%{http_code}\n" http://httpbin.org

        輸出結果返回200,表明sleep-a服務訪問http://www.httpbin.org成功。

      2. 執行以下命令,請求httpbin.organything介面,驗證出口網關是否將HTTP請求升級為HTTPS請求。

        kubectl -n mytest exec deployment/sleep-a -- sh -c "curl -s  http://httpbin.org/anything |grep url"

        預期輸出:

        "url": "https://httpbin.org/anything"

        可以看到,url欄位資訊以https開頭,表明出口網關將請求成功升級為https,然後轉寄給httpbin.org

      3. 執行以下命令,通過mytest命名空間下的sleep-a服務訪問https://www.httpbin.org

        kubectl -n mytest exec deployment/sleep-a -- curl  -s -o /dev/null -w "%{http_code}\n"  https://www.httpbin.org

        輸出結果返回200,表明sleep-a服務訪問https://www.httpbin.org成功。

    2. 驗證default命名空間下的Nginx服務。

      1. 執行以下命令,通過Nginx服務訪問http://www.httpbin.org

        kubectl -n default exec deployment/nginx -- curl -s -o /dev/null -w "%{http_code}\n" http://www.httpbin.org

        輸出結果返回502,表明nginx服務訪問http://www.httpbin.org失敗。

      2. 執行以下命令,通過Nginx服務訪問https://www.httpbin.org

        kubectl -n default exec deployment/nginx -- curl -s -o /dev/null -w "%{http_code}\n" https://www.httpbin.org

        輸出結果顯示請求串連被拒絕,表明Nginx服務訪問https://www.httpbin.org失敗。

      3. 執行以下命令,查看Nginx工作負載對應的Sidecar的accessLog,瞭解串連被拒絕的原因。

         kubectl -n default  logs -f deployment/nginx -c istio-proxy   --tail=1 

        預期輸出:

        {"authority":"-","bytes_received":"0","bytes_sent":"0","downstream_local_address":"52.86.XX.XX:443","downstream_remote_address":"172.16.0.199:56748","duration":"0","istio_policy_status":"-","method":"-","path":"-","protocol":"-","request_id":"-","requested_server_name":"-","response_code":"0","response_flags":"UH","route_name":"-","start_time":"2023-04-11T02:00:07.409Z","trace_id":"-","upstream_cluster":"BlackHoleCluster","upstream_host":"-","upstream_local_address":"-","upstream_service_time":"-","upstream_transport_failure_reason":"-","user_agent":"-","x_forwarded_for":"-"}

        預期輸出表明,請求轉寄給BlackHoleCluster,因此導致串連被拒絕。

    3. 執行以下命令,刪除egress-by-egressgateway後,再次通過mytest命名空間下的sleep-a服務訪問http://www.httpbin.orghttps://www.httpbin.org

      kubectl -n istio-egress delete ASMEgressTrafficPolicy  egress-by-egressgateway
      kubectl -n mytest exec deployment/sleep-a -- curl -s -o /dev/null -w "%{http_code}\n"  http://www.httpbin.org
      kubectl -n mytest exec deployment/sleep-a -- curl -s -o /dev/null -w "%{http_code}\n"  https://www.httpbin.org

      訪問http://www.httpbin.org時,返回502;訪問https://www.httpbin.org時,請求串連被拒絕。刪除ASMEgressTrafficPolicy配置後,sleep-a服務無法訪問http://www.httpbin.orghttps://www.httpbin.org

    輸出以上結果,表明ASMEgressTrafficPolicy配置生效。

方案二:sidecar到出口網關之間使用HTTPS

  1. 使用以下內容,更新egress-by-egressgateway.yaml

    spec欄位下增加了httpsUpgrade欄位和直接存取https://www.httpbin.org的相關定義。關於欄位的相關說明,請參見ASMEgressTrafficPolicy CRD說明

    apiVersion: istio.alibabacloud.com/v1
    kind: ASMEgressTrafficPolicy
    metadata:
      name: egress-by-egressgateway  # 名稱約定為egress-by-{出口網關名稱},與出口網關對應。
      namespace: istio-egress          # 命名空間約定:固定到istio-egress命名空間。
    spec:
      byEgressGateway:
        name: egressgateway
      egressRules:
      - from:
         - namespace: mytest
           workloadSelector:
              app: sleep-a
        to:
        - name: httpbin-service-https
          hosts:
          - www.httpbin.org
          - httpbin.org
          port:
            name: https
            number: 443
            protocol: HTTPS
          byEgressGateway:
            port: 444   # 準備工作的第三步中,出口網關定義的HTTPS 444連接埠。
  2. 在ACK叢集中,執行以下命令,建立ASMEgressTrafficPolicy資源。

    kubectl apply -f egress-by-egressgateway.yaml
  3. 驗證ASMEgressTrafficPolicy配置是否生效。

    1. 驗證mytest命名空間下的sleep-a服務。

      1. 執行以下命令,通過sleep-a服務訪問http://www.httpbin.org

        kubectl -n mytest exec deployment/sleep-a -- curl -s -o /dev/null -w "%{http_code}\n" http://httpbin.org

        輸出結果返回502,表明sleep-a服務訪問http://www.httpbin.org失敗。

      2. 執行以下命令,通過mytest命名空間下的sleep-a服務訪問https://www.httpbin.org

        kubectl -n mytest exec deployment/sleep-a -- curl  -s -o /dev/null -w "%{http_code}\n"  https://www.httpbin.org

        輸出結果返回200,表明sleep-a服務訪問https://www.httpbin.org成功。

    2. 驗證default命名空間下的Nginx服務。

      1. 執行以下命令,通過Nginx服務訪問http://www.httpbin.org

        kubectl -n default exec deployment/nginx -- curl -s -o /dev/null -w "%{http_code}\n" http://www.httpbin.org

        輸出結果返回502,表明Nginx服務訪問http://www.httpbin.org失敗。

      2. 執行以下命令,通過Nginx服務訪問https://www.httpbin.org

        kubectl -n default exec deployment/nginx -- curl -s -o /dev/null -w "%{http_code}\n" https://www.httpbin.org

        輸出結果顯示請求串連被拒絕,表明Nginx服務訪問https://www.httpbin.org失敗。

      3. 執行以下命令,查看Nginx工作負載對應的Sidecar的access log,瞭解串連被拒絕的原因。

         kubectl -n default  logs -f deployment/nginx -c istio-proxy   --tail=1 

        預期輸出:

        {"authority":"-","bytes_received":"0","bytes_sent":"0","downstream_local_address":"52.86.XX.XX:443","downstream_remote_address":"172.16.0.199:56748","duration":"0","istio_policy_status":"-","method":"-","path":"-","protocol":"-","request_id":"-","requested_server_name":"-","response_code":"0","response_flags":"UH","route_name":"-","start_time":"2023-04-11T02:00:07.409Z","trace_id":"-","upstream_cluster":"BlackHoleCluster","upstream_host":"-","upstream_local_address":"-","upstream_service_time":"-","upstream_transport_failure_reason":"-","user_agent":"-","x_forwarded_for":"-"}

        預期輸出表明,請求轉寄給BlackHoleCluster,因此導致串連被拒絕。

    3. 執行以下命令,刪除egress-by-egressgateway後,再次通過mytest命名空間下的sleep-a服務訪問http://www.httpbin.orghttps://www.httpbin.org

      kubectl -n istio-egress delete ASMEgressTrafficPolicy  egress-by-egressgateway
      kubectl -n mytest exec deployment/sleep-a -- curl -s -o /dev/null -w "%{http_code}\n"  http://www.httpbin.org
      kubectl -n mytest exec deployment/sleep-a -- curl -s -o /dev/null -w "%{http_code}\n"  https://www.httpbin.org

      訪問http://www.httpbin.org時,返回502;訪問https://www.httpbin.org時,請求串連被拒絕。刪除ASMEgressTrafficPolicy配置後,sleep-a服務無法訪問http://www.httpbin.orghttps://www.httpbin.org

    輸出以上結果,表明ASMEgressTrafficPolicy配置生效。

相關操作

拒絕來自指定命名空間下的POST請求

通過ASM出口網關結合ASMEgressTrafficPolicy,您可以靈活地控制叢集內向外的外部流量。結合AuthorizationPolicy,您還可以進行更細粒度的存取控制。例如,通過如下定義拒絕來自mytest命名空間下的POST請求。

kind: AuthorizationPolicy
apiVersion: security.istio.io/v1beta1
metadata:
  name: sleep-a-egress-www-httpbin-org
  namespace: istio-system
spec:
  action: DENY
  rules:
    - to:
        - operation:
            hosts:
            - www.httpbin.org
            - httpbin.org
            methods:
              - POST
      from:
        - source:
            namespaces: ["mytest"]
  selector:
    matchLabels:
      istio: egressgateway-a

應用上述配置後,通過sleep-a服務採用POST方式的請求訪問www.httpbin.org,將返回RBAC: access,通過GET方式的請求訪問www.httpbin.org則不受影響。