借助ASM網關,您可以配置帶有mTLS安全機制的gRPC服務,確保僅授權的客戶端能夠訪問,并在整個數據傳輸過程中實施端到端加密和雙向身份驗證,有效防止信息被竊聽、篡改及非法訪問。
前提條件
創建ASM企業版實例。具體操作,請參見創建ASM實例。
已創建Kubernetes托管版集群。具體操作,請參見創建Kubernetes托管版集群。
已添加集群到ASM實例。具體操作,請參見添加集群到ASM實例。
已部署入口網關服務。具體操作,請參見創建入口網關服務。
已部署應用到ASM實例的集群中。具體操作,請參見在ASM實例關聯的集群中部署應用。
背景信息
服務網格ASM的流量管理功能支持通過入口網關訪問內部的gRPC服務。由于gRPC基于HTTP/2協議,所以也可以使用TLS/mLTS對傳輸數據進行加密,保障數據安全。ASM網關目前同樣支持TLS/mTLS的gRPC協議,可以將加密的TCP數據流在網關處進行TLS終止,網格內的應用不需要再進行TLS配置。
操作步驟
步驟一:部署示例應用
登錄容器服務管理控制臺,在左側導航欄選擇集群。
在集群列表頁面,單擊目標集群名稱,然后在左側導航欄,選擇 。
在無狀態頁面頂部,命名空間右側下拉列表中選擇命名空間,單擊使用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端口暴露服務。具體操作,請參見創建入口網關。
步驟三:設置服務網格ASM的路由規則
登錄ASM控制臺,在左側導航欄,選擇 。
在網格管理頁面,單擊待配置實例的名稱或者操作列中的管理。
創建網關規則。
在網格詳情頁面左側導航欄,選擇 。
在網關規則頁面,單擊使用YAML創建。
在創建頁面,請選擇命名空間為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
創建虛擬服務。
在網格詳情頁面左側導航欄,選擇 。
在虛擬服務頁面,單擊使用YAML創建。
在創建頁面,請選擇命名空間為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及以上
登錄ASM控制臺,在左側導航欄,選擇 。
在網格管理頁面,單擊目標實例名稱,然后在左側導航欄,選擇 。
在證書管理頁面,單擊創建,然后在證書信息面板,配置相關信息,單擊確定。
步驟五:運行gRPC客戶端
本文使用gRPC-go的官網示例作為gRPC的Mtls客戶端。
請參照gRPC-go官網示例安裝gRPC依賴。更多內容,請參見gRPC-go。
請參照gRPC-go官網示例克隆gRPC-go的代碼庫。更多內容,請參見GRPC-go代碼。
使用如下代碼,覆蓋/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()) }
替換完成后,進入examples,執行如下命令。
go run helloworld/greeter_client/main.go
預期結果:
Greeting:Hello World
若返回結果為如下錯誤,則為證書錯誤,請您參照上述步驟,重新掛載證書。