All Products
Search
Document Center

Alibaba Cloud Service Mesh:Use an ingress gateway to configure an mTLS-based gRPC service

Last Updated:Mar 11, 2024

Ingress gateways allow you to configure Google Remote Procedure Call (gRPC) services that are based on the mutual TLS (mTLS) protocol. This security mechanism ensures that only authorized clients can access gRPC services. End-to-end encryption and two-way authentication are implemented throughout the data transmission process to effectively protect information from eavesdropping, tampering, and unauthorized access.

Prerequisites

Background information

You can route traffic to gRPC services in an ASM instance by using an ingress gateway.Service Mesh gRPC services are built on top of the HTTP/2 protocol. This allows you to use the TLS or mTLS protocol to encrypt transmitted data to ensure data security. Ingress gateways support gRPC with TLS or mTLS. TLS termination is performed on encrypted TCP data streams when they pass through ingress gateways. You do not need to configure TLS for applications in the ASM instance.

Procedure

Step 1: Deploy a sample application

  1. Log on to the ACK console. In the left-side navigation pane, click Clusters.

  2. On the Clusters page, click the name of the cluster that you want to manage and choose Workloads > Deployments in the left-side navigation pane.

  3. In the upper part of the Deployments page, select a namespace from the Namespace drop-down list and click Create from YAML.

  4. On the Create page, copy the following YAML code to the code editor and click Create.

    Expand to view the YAML code

    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
    ---
    Note

    The name parameter of the ports field in the service configuration must start with http2- or grpc-. Otherwise, Istio cannot identify the service protocol.

Step 2: Create an ingress gateway

In this example, the default port 443 is used to expose the service. For more information, see Create an ingress gateway.

Step 3: Configure an Istio gateway and a virtual service

  1. Log on to the ASM console. In the left-side navigation pane, choose Service Mesh > Mesh Management.

  2. On the Mesh Management page, find the ASM instance that you want to configure, and click the instance name or click Manage in the Actions column.

  3. Create an Istio gateway.

    1. On the details page of the ASM instance, choose ASM Gateways > Gateway in the left-side navigation pane.

    2. On the Gateway page, click Create from YAML.

    3. On the Create page, select default from the Namespace drop-down list, copy the following YAML code to the code editor, and then click Create.

      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. Create a virtual service.

    1. On the details page of the ASM instance, choose Traffic Management Center > VirtualService in the left-side navigation pane.

    2. On the VirtualService page, click Create from YAML.

    3. On the Create page, select default from the Namespace drop-down list, copy the following YAML code to the code editor, and then click Create.

      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

Step 4: Mount a certificate

Typically, a gRPC client requires a Subject Alternative Name (SAN) certificate. We recommend that you use the certificates listed in grpc-go. Mount the certificate to the istio-system namespace of the ACK cluster because the ingress gateway requires the certificate.

  • For an ASM instance of a version earlier than 1.17

    Run the following command to create a secret in the istio-system namespace:

    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
    Note

    The secret name must be the same as the credentialName that is configured in the Istio gateway.

  • For an ASM instance of version 1.17 or later

    1. Log on to the ASM console. In the left-side navigation pane, choose Service Mesh > Mesh Management.

    2. On the Mesh Management page, click the name of the ASM instance. In the left-side navigation pane, choose ASM Gateways > Certificate Management.

    3. On the Certificate Management page, click Create. In the Certificate Information panel, configure the required parameters and click OK.

Step 5: Start the gRPC client

In this example, a gRPC client that uses mTLS is started. For more information, see the official gRPC website.

  1. Install dependencies. For more information, see Quick start of gRPC in Go.

  2. Clone the gRPC-go code repository. For more information, see gRPC-go.

  3. Replace the content of the main.go file in the /grpc-go/examples/helloworld/greeter_client/ path with the following code and change the address value to ${IP address of the ingress gateway}:443:

    Expand to view the sample code

    /*
     *
     * 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. Go to the examples path and run the following command:

    go run helloworld/greeter_client/main.go

    Expected result:

    Greeting: Hello World

    If the error shown in the following figure is returned, the certificate is invalid. Perform the preceding steps to mount the certificate again.2