全部產品
Search
文件中心

Alibaba Cloud Service Mesh:通過ASM網關配置基於mTLS的gRPC服務

更新時間:Jun 30, 2024

藉助ASM網關,您可以配置帶有mTLS安全機制的gRPC服務,確保僅授權的用戶端能夠訪問,並在整個資料轉送過程中實施端到端加密和雙向身分識別驗證,有效防止資訊被竊聽、篡改及非法訪問。

前提條件

背景資訊

Service MeshASM的流量管理功能支援通過入口網關訪問內部的gRPC服務。由於gRPC基於HTTP/2協議,所以也可以使用TLS/mLTS對傳輸資料進行加密,保障資料安全。ASM網關目前同樣支援TLS/mTLS的gRPC協議,可以將加密的TCP資料流在網關處進行TLS終止,網格內的應用不需要再進行TLS配置。

操作步驟

步驟一:部署樣本應用

  1. 登入Container Service管理主控台,在左側導覽列選擇叢集

  2. 叢集列表頁面,單擊目的地組群名稱,然後在左側導覽列,選擇工作負載 > 無狀態

  3. 無狀態頁面頂部,命名空間右側下拉式清單中選擇命名空間,單擊使用YAML建立資源

  4. 建立頁面,將如下YAML模板粘貼至模板文字框內,單擊建立

    展開查看YAML

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: istio-grpc-server-v1
      labels:
        app: istio-grpc-server
        version: v1
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: istio-grpc-server
          version: v1
      template:
        metadata:
          labels:
            app: istio-grpc-server
            version: v1
        spec:
          containers:
          - args:
            - --address=0.0.0.0:8080
            image: registry.cn-hangzhou.aliyuncs.com/aliacs-app-catalog/istio-grpc-server
            imagePullPolicy: Always
            livenessProbe:
              exec:
                command:
                - /bin/grpc_health_probe
                - -addr=:8080
              initialDelaySeconds: 2
            name: istio-grpc-server
            ports:
            - containerPort: 8080
            readinessProbe:
              exec:
                command:
                - /bin/grpc_health_probe
                - -addr=:8080
              initialDelaySeconds: 2
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: istio-grpc-server
      labels:
        app: istio-grpc-server
    spec:
      ports:
      - name: grpc-backend
        port: 8080
        protocol: TCP
      selector:
        app: istio-grpc-server
      type: ClusterIP
    ---
    說明

    由於Istio的協議選擇機制,此處Service配置中的ports欄位的name必須以http2-或者grpc-開頭,否則Istio無法正確識別服務合約。

步驟二:部署入口網關

本例中使用預設的443連接埠暴露服務。具體操作,請參見建立入口網關

步驟三:設定Service MeshASM的路由規則

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

  2. 網格管理頁面,單擊待配置執行個體的名稱或者操作列中的管理

  3. 建立網關規則。

    1. 在網格詳情頁面左側導覽列,選擇ASM網關 > 網關規則

    2. 網關規則頁面,單擊使用YAML建立

    3. 建立頁面,請選擇命名空間default,將如下的YAML粘貼至文字框中,單擊建立

      apiVersion: networking.istio.io/v1beta1
      kind: Gateway
      metadata:
        name: gw-grpc-443
        namespace: default
      spec:
        selector:
          istio: ingressgateway
        servers:
          - hosts:
              - '*'
            port:
              name: https
              number: 443
              protocol: HTTPS
            tls:
              credentialName: example-credential
              mode: MUTUAL
                                      
  4. 建立虛擬服務。

    1. 在網格詳情頁面左側導覽列,選擇流量管理中心 > 虛擬服務

    2. 虛擬服務頁面,單擊使用YAML建立

    3. 建立頁面,請選擇命名空間default,將如下的YAML粘貼至文字框中,單擊建立

      apiVersion: networking.istio.io/v1alpha3
      kind: VirtualService
      metadata:
        name: grpc-vs
      spec:
        hosts:
        - "*"
        gateways:
        - gw-grpc-443
        http:
          - match:
              - port: 443
            route:
              - destination:
                  host: istio-grpc-server

步驟四:掛載認證

gRPC的用戶端通常要求掛載SAN格式的認證。推薦您使用grpc-go樣本的認證組。由於認證需要在ASM網關中使用,所以需要將認證配置在ACK叢集中的istio-system命名空間下。

  • ASM執行個體為1.17以下

    執行以下命令,在istio-system命名空間建立Secret。

    kubectl create -n istio-system secret generic example-credential --from-file=tls.key=server_key.pem --from-file=tls.crt=server_cert.pem --from-file=ca.crt=client_ca_cert.pem
    說明

    Secret名稱需要和網關規則中配置的credentialName相同。

  • ASM執行個體為1.17及以上

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

    2. 網格管理頁面,單擊目標執行個體名稱,然後在左側導覽列,選擇ASM網關 > 認證管理

    3. 認證管理頁面,單擊建立,然後在認證資訊面板,配置相關資訊,單擊確定

步驟五:運行gRPC用戶端

本文使用gRPC-go的官網樣本作為gRPC的Mtls用戶端。

  1. 請參照gRPC-go官網樣本安裝gRPC依賴。更多內容,請參見gRPC-go

  2. 請參照gRPC-go官網樣本複製gRPC-go的程式碼程式庫。更多內容,請參見GRPC-go代碼

  3. 使用如下代碼,覆蓋/grpc-go/examples/helloworld/greeter_client/main.go檔案,將address的值修改為${ASM網關地址}:443

    展開查看代碼

    /*
     *
     * Copyright 2015 gRPC authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *     http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     *
     */
    
    // Package main implements a client for Greeter service.
    package main
    
    import (
        "context"
        "crypto/tls"
        "crypto/x509"
        "flag"
        "io/ioutil"
        "log"
        "time"
    
        "google.golang.org/grpc"
        "google.golang.org/grpc/credentials"
        pb "google.golang.org/grpc/examples/helloworld/helloworld"
    )
    
    const (
        defaultName = "world"
    )
    
    var (
        addr       = flag.String("addr", "localhost:50051", "the address to connect to")
        name       = flag.String("name", defaultName, "Name to greet")
        cert       = flag.String("cert", "./data/x509/client_cert.pem", "server cert for mTLS")
        key        = flag.String("key", "./data/x509/client_key.pem", "server key for mTLS")
        cacert     = flag.String("cacert", "./data/x509/ca_cert.pem", "ca cert for mTLS")
        servername = flag.String("servername", "x.test.example.com", "the cert name of server")
    )
    
    func main() {
        flag.Parse()
    
        certPair, err := tls.LoadX509KeyPair(*cert, *key)
        if err != nil {
            log.Fatalf("failed to load client cert: %v", err)
        }
    
        ca := x509.NewCertPool()
        caFilePath := *cacert
        caBytes, err := ioutil.ReadFile(caFilePath)
        if err != nil {
            log.Fatalf("failed to read ca cert %q: %v", caFilePath, err)
        }
        if ok := ca.AppendCertsFromPEM(caBytes); !ok {
            log.Fatalf("failed to parse %q", caFilePath)
        }
    
        tlsConfig := &tls.Config{
            ServerName:   *servername,
            Certificates: []tls.Certificate{certPair},
            RootCAs:      ca,
        }
    
        conn, err := grpc.Dial(*addr, grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)))
        if err != nil {
            log.Fatalf("did not connect: %v", err)
        }
        defer conn.Close()
        c := pb.NewGreeterClient(conn)
    
        // Contact the server and print out its response.
        ctx, cancel := context.WithTimeout(context.Background(), time.Second)
        defer cancel()
        r, err := c.SayHello(ctx, &pb.HelloRequest{Name: *name})
        if err != nil {
            log.Fatalf("could not greet: %v", err)
        }
        log.Printf("Greeting: %s", r.GetMessage())
    }
                            
  4. 替換完成後,進入examples,執行如下命令。

    go run helloworld/greeter_client/main.go

    預期結果:

    Greeting:Hello World

    若返回結果為如下錯誤,則為認證錯誤,請您參照上述步驟,重新掛載認證。2