本文介绍如何在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控制台,在左侧导航栏,选择 。
- 在网格管理页面,单击待配置实例的名称或者操作列中的管理。
- 创建网关规则。
- 创建虚拟服务。
步骤四:挂载证书
gRPC的客户端通常要求挂载SAN格式的证书,这里推荐您使用我们为您提供的示例。更多内容,请参见grpc-go示例的证书组。
由于证书需要在ASM网关中使用,所以需要将证书配置在ACK集群中的istio-system命名空间下。使用如下命令在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相同。
步骤五:运行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
若返回结果为如下错误,则为证书错误,请您参照上述步骤,重新挂载证书。