Golang Engineering Components: High-performance RPC framework gRPC’s TLS and two-way TLS to ensure communication security

gRPC is a high-performance, general-purpose RPC framework open sourced by Google that supports multiple programming languages. Compared with the traditional RESTful API method, it can perform service calls and data transmission faster, and supports multiple codec protocols and load balancing algorithms. In gRPC, we can ensure communication security by setting TLS and mutual TLS.

  1. TLS

TLS (Transport Layer Security) is a secure transport layer protocol based on an encryption protocol. It can establish an encrypted channel between the client and the server to ensure that the data will not be eavesdropped, tampered or forged during transmission. In gRPC, we can use TLS to ensure communication security.

Enabling TLS in gRPC requires two steps:

The first step is to generate the certificate and private key files. The certificate file contains the public key information, and the private key file contains the corresponding private key information. These files need to be signed by a trusted Certificate Authority (CA) or be self-generated.

The second step is to set relevant parameters and enable TLS connection on the server and client respectively. Specifically, the grpc.Creds() option needs to be set to the credentials.NewServerTLSFromFile() method on the server side, which contains the path information of the certificate file and the private key file; the grpc.WithTransportCredentials() option needs to be set to credentials on the client side .NewClientTLSFromFile() method, which contains the host name information of the server certificate.

For example, to enable TLS connections on the server:

creds, err := credentials. NewServerTLSFromFile(certFile, keyFile)
if err != nil {
    log.Fatalf("failed to create server TLS credentials: %v", err)
}
server := grpc.NewServer(grpc.Creds(creds))

In the above code, we use the credentials.NewServerTLSFromFile() method to create a TLS credentials object and pass it to the grpc.NewServer() method as the grpc.Creds() option. Among them, certFile and keyFile are the path information of the certificate file and the private key file respectively.

Enable TLS connections in the client:

creds, err := credentials. NewClientTLSFromFile(serverNameOverride, "")
if err != nil {
    log.Fatalf("failed to create client TLS credentials: %v", err)
}
conn, err := grpc.Dial(address,
    grpc.WithTransportCredentials(creds),
)

In the above code, we use the credentials.NewClientTLSFromFile() method to create a client TLS credentials object and pass it to the grpc.Dial() method as the grpc.WithTransportCredentials() option. Where serverNameOverride indicates the host name information of the server.

  1. Mutual TLS

Mutual TLS (Mutual TLS) is a two-way authentication protocol that establishes a mutual trust relationship between the server and the client. In addition to encrypting the channel, it also requires authentication of the supplicant. In gRPC, we can use mutual TLS to ensure communication security.

Enabling mutual TLS in gRPC requires three steps:

The first step is to generate certificate and private key files, same as for TLS. But at this time, separate certificate and private key files need to be generated for the client and server.

The second step is to set relevant parameters on the server and client respectively and enable two-way TLS connection. Specifically, the grpc.Creds() option needs to be set to the credentials.NewTLS() method on the server side, and the tls.Config object containing the server certificate, private key and CA root certificate needs to be passed; grpc. The WithTransportCredentials() option is the credentials.NewTLS() method and passes a tls.Config object containing the client certificate, private key, and CA root certificate.

The third step is to implement the authentication function in the code. The authentication function will receive a context object and the authentication information provided by the requester, and return a Boolean value indicating whether the authentication is passed. During the authentication process, we can use the authentication information provided by the requesting party for authentication, such as username and password.

For example, to enable mutual TLS connections on the server:

serverCreds, err := credentials. NewServerTLSFromFile(certFile, keyFile)
if err != nil {
    log.Fatalf("failed to create server TLS credentials: %v", err)
}
caCert, err := ioutil. ReadFile(caCertFile)
if err != nil {
    log.Fatalf("failed to read CA certificate: %v", err)
}
certPool := x509. NewCertPool()
if !certPool.AppendCertsFromPEM(caCert) {
    log.Fatalf("failed to append CA certificate")
}
tlsConfig := &tls. Config{
    ClientAuth: tls.RequireAndVerifyClientCert,
    ClientCAs: certPool,
}
serverOption := grpc.Creds(credentials.NewTLS(tlsConfig))
server := grpc.NewServer(serverOption)

In the above code, we use the credentials.NewServerTLSFromFile() method to create a server TLS credentials object and pass it to the grpc.NewServer() method as the grpc.Creds() option. Then, we read the CA root certificate file and create a certificate pool object certPool through the x509.NewCertPool() method. Finally, we create a tls.Config object containing the client credentials and pass it as an argument to the credentials.NewTLS() method.

Enable mutual TLS connections in the client:

clientCreds, err := credentials. NewClientTLSFromFile(certFile, serverNameOverride)
if err != nil {
    log.Fatalf("failed to create client TLS credentials: %v", err)
}
caCert, err := ioutil. ReadFile(caCertFile)
if err != nil {
    log.Fatalf("failed to read CA certificate: %v", err)
}
certPool := x509. NewCertPool()
if !certPool.AppendCertsFromPEM(caCert) {
    log.Fatalf("failed to append CA certificate")
}
tlsConfig := &tls. Config{
    ServerName: serverNameOverride,
    RootCAs: certPool,
    Certificates: []tls. Certificate{clientCert},
}
clientOption := grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig))
conn, err := grpc.Dial(address, clientOption)

In the above code, we use the credentials.NewClientTLSFromFile() method to create a client TLS credentials object and pass it to the grpc.Dial() method as the grpc.WithTransportCredentials() option. Then, we read the CA root certificate file and create a certificate pool object certPool through the x509.NewCertPool() method. Next, we create a tls.Config object containing the client credentials and pass it as an argument to the grpc.WithTransportCredentials() option.

Implement the authentication function in code:

func authenticate(ctx context.Context) (context.Context, error) {
    md, ok := metadata. FromIncomingContext(ctx)
    if !ok {
        return nil, status. Errorf(codes. Unauthenticated, "missing credentials")
    }
    authValue := md. Get("authorization")
    if len(authValue) == 0 {
        return nil, status.Errorf(codes.Unauthenticated, "missing authorization header")
    }
    // TODO: verify the authentication token
    return ctx, nil
}

In the above code, we define an authenticate function and pass it to the grpc.NewServer() method as a UnaryInterceptor option. This function will obtain authentication information from the requested metadata and perform authentication. It should be noted that the authentication process should be implemented according to specific business needs.

Summarize

By setting TLS and mutual TLS, we can ensure the communication security between gRPC server and client. When enabling TLS connection, you need to generate certificate and private key files, and set relevant parameters on the server and client respectively; when enabling two-way TLS connection, you need to generate independent certificate and private key files for client and server respectively , and need to implement the authentication function to ensure the legitimacy of the identity of the requesting party.

I hope this article was helpful to you, and please feel free to contact me if you have any other questions or concerns.

The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledge. Go skill tree HomepageOverview 3522 people are studying systematically