Skip to content
Santekno.com | Tech Tutorials and Trends
EN
📖 0%
29 Jul 2025 · 6 min read ·Article 51 / 110
Go

51. Using TLS in a gRPC Server

IH
Ihsan Arif
Writer at Santekno · Backend Engineer

51. Using TLS in a gRPC Server

These days, security is a non-negotiable aspect of application development, especially when our application involves the exchange of sensitive data between services or with clients. One of the communication protocols widely used by modern developers is gRPC, an open source remote procedure call (RPC) framework from Google that runs on top of HTTP/2. But are you confident that your gRPC server is actually secure?

In this 51st article of the gRPC series, I’ll walk through the practice of securing a gRPC server using TLS (Transport Layer Security) in detail. I’ll guide you through the theory, the security flow, preparing TLS certificates, and implementing them on the server, including simulating client-server communication and troubleshooting common issues you’ll encounter when using TLS with gRPC in the real world.


Why Use TLS in gRPC?

gRPC is fundamentally an RPC protocol that runs on top of HTTP/2, which by default has no security whatsoever (plaintext). Every piece of data sent across the network can be eavesdropped on by malicious third parties. This is where TLS plays a crucial role:

  • Encryption: Protects data in transit from wiretapping/interception.
  • Integrity: Prevents data from being tampered with while in transit.
  • Authentication: Allows the client to verify the server’s identity, and even perform mutual authentication (mTLS).

Just like SSL over HTTP, the TLS protocol is a best practice that must be implemented, especially for services handling sensitive data (payment gateways, personal data, and so on).


TLS Architecture in a gRPC Server

Let’s take a look at how TLS is applied within the gRPC workflow using the following diagram:

MERMAID
sequenceDiagram
    participant Client
    participant Server

    Client->>Server: Open Connection (Request over HTTP/2)
    Server-->>Client: Provide Digital Certificate & Key
    Client->>Server: Validate Certificate (CA)
    alt Certificate Valid
        Client->>Server: Establish TLS Handshake
        Note right of Client: Encrypt traffic with symmetric key from handshake
        Server-->>Client: Accept Encrypted gRPC Calls
    else Certificate Invalid
        Client-->>Server: Connection Rejected
    end

As you can see, in the early stage the client ensures it only communicates with a server it can trust (one that holds a valid certificate, issued by a CA the client trusts).


Preparing the TLS Certificate

One crucial step before configuring the server: your gRPC server must have a certificate and a private key. In a development environment, we often use certificates from a local CA such as OpenSSL.

As a simulation, here are the commands to create a CA, key, and certificate:

bash
1# Create a private key
2openssl genrsa -out server.key 2048
3
4# Create a Certificate Signing Request (CSR)
5openssl req -new -key server.key -out server.csr \
6    -subj "/CN=localhost/O=MyOrganization"
7
8# Create a self-signed certificate valid for 365 days
9openssl x509 -req -in server.csr -signkey server.key -out server.crt -days 365

At minimum, you’ll end up with two important files:

  • server.key (the private key, which must be kept secret!)
  • server.crt (the public certificate, which can be distributed to clients)

A Simple Example: gRPC Server with TLS

Let’s move on to the code! I’ll use Go, a very popular language for implementing gRPC.

Setting Up the TLS Server

Suppose we have a helloworld.proto protocol that has already been generated by the proto compiler.

server.go

go
 1package main
 2
 3import (
 4    "crypto/tls"
 5    "log"
 6    "net"
 7
 8    "google.golang.org/grpc"
 9    "google.golang.org/grpc/credentials"
10
11    pb "github.com/yourusername/yourrepo/helloworld"
12)
13
14func main() {
15    // Load the certificate and key
16    creds, err := credentials.NewServerTLSFromFile("server.crt", "server.key")
17    if err != nil {
18        log.Fatalf("failed loading cert: %v", err)
19    }
20
21    // Initialize the gRPC Server with TLS
22    s := grpc.NewServer(grpc.Creds(creds))
23
24    // Register the service
25    pb.RegisterGreeterServer(s, &server{})
26
27    // Start the server and listen on port 8443
28    lis, err := net.Listen("tcp", ":8443")
29    if err != nil {
30        log.Fatalf("failed to listen: %v", err)
31    }
32    log.Println("gRPC server listening securely on :8443")
33    s.Serve(lis)
34}

The core of this code is the credentials.NewServerTLSFromFile function, where the server is told to use the certificate and private key. With just this code, your server will only accept inbound communication over TLS.


Simulating a TLS Client Connection

The client side must also validate the server’s certificate and establish a TLS connection.

client.go

go
 1package main
 2
 3import (
 4    "context"
 5    "log"
 6    "time"
 7
 8    "google.golang.org/grpc"
 9    "google.golang.org/grpc/credentials"
10    pb "github.com/yourusername/yourrepo/helloworld"
11)
12
13func main() {
14    creds, err := credentials.NewClientTLSFromFile("server.crt", "localhost")
15    if err != nil {
16        log.Fatalf("could not create creds: %v", err)
17    }
18    conn, err := grpc.Dial("localhost:8443", grpc.WithTransportCredentials(creds))
19    if err != nil {
20        log.Fatalf("did not connect: %v", err)
21    }
22    defer conn.Close()
23
24    c := pb.NewGreeterClient(conn)
25    ctx, cancel := context.WithTimeout(context.Background(), time.Second)
26    defer cancel()
27    resp, err := c.SayHello(ctx, &pb.HelloRequest{Name: "World"})
28    if err != nil {
29        log.Fatalf("could not greet: %v", err)
30    }
31    log.Printf("Greeting: %s", resp.Message)
32}

With this code, the client will refuse to communicate if the server’s certificate is invalid, expired, or does not belong to the intended server.


Troubleshooting: Common Errors & Their Solutions

Here are some issues that frequently come up (and their quick fixes):

ProblemCauseSolution
Handshake failure / x509: certificate invalidCN/SAN does not match the hostMake sure the Common Name or Subject Alternative Names on the certificate match the server domain
expired certificateThe certificate has expiredRegenerate a new certificate
PEM_read_bio failureWrong key/cert formatMake sure the .crt and .key files are in PEM format and not corrupted
cannot load certificate chainWrong paths, permission errorMake sure the file paths and permissions are correct when running
client error: connection rejectedSelf-signed certificateThe client must be able to trust the server cert (register it with a trusted CA or use the insecure flag)

Bonus: Implementing mTLS (Mutual TLS)

For a higher level of security, use mTLS, where the client is also required to have a certificate. Both the server and the client verify each other’s identity.

To implement it:

  • Generate a client certificate and a trust chain to the server
  • On the server, use credentials.NewTLS(&tls.Config{...}) with ClientAuth: tls.RequireAndVerifyClientCert

Conclusion

Implementing TLS in a gRPC server is not just a best practice; it’s an absolute requirement for secure communication. The setup is very straightforward—just provide a certificate and key, whether in development or production. By taking this step, you prevent many potential security risks, including Man-in-the-Middle (MitM) attacks, sniffing, and spoofing.

If you’re just getting started with implementing TLS in a gRPC server, always test the connection from the client. Make sure all communication is fully encrypted. For larger scales, also consider the role of an internal Certificate Authority or integration with cloud provider services (GCP, AWS ACM).

Apply it now, and make security the foundation of your application!


References:


I hope this article boosts your confidence in securing your gRPC server! Have a unique challenge while setting up TLS? Share it in the comments! 🚀

Related Articles

💬 Comments