Transport Layer Security (TLS) protects communication between microservices. gRPC uses HTTP/2 over SSL/TLS to authenticate peers and encrypt data exchanged between a client and server. This matters when a network call replaces an in-process call: service boundaries introduce both communication failures and a need to protect data in transit. TLS succeeds SSL. section 1.1 section 1.1.4 section 6.3
For a gRPC connection using client and server certificates, each side needs its own certificate and key, plus a certificate pool for the CA certificate. The server loads its certificate, configures client-certificate requirements and passes TLS transport credentials into gRPC server initialization. The client loads its certificate, sets a server name and trusted roots, and supplies TLS credentials when connecting. Certificate-loading and pool errors must be handled before accepting or making calls. section 6.3.3
Listing 6.8 gRPC TLS configuration
...
func getTlsCredentials() (credentials.TransportCredentials, error) {
serverCert, serverCertErr := tls.LoadX509KeyPair("cert/server.crt",
"cert/server.key") #1
// handle serverCertErr
certPool := x509.NewCertPool() #2
caCert, caCertErr := ioutil.ReadFile("cert/ca.crt")
// handle caCertErr
if ok := certPool.AppendCertsFromPEM(caCert); !ok { #3
return nil, errors.New("failed to append the CA certs")
}
return credentials.NewTLS(
&tls.Config{
ClientAuth: tls.RequireAnyClientCert, #4
Certificates: []tls.Certificate{serverCert}, #5
ClientCAs: certPool, #6
}), nil
}
...
func main() {
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", 8080))
// handle err
tlsCredentials, tlsCredentialsErr := getTlsCredentials()
// handle tlsCredentialsErr
var opts []grpc.ServerOption
opts = append(opts, grpc.Creds(tlsCredentials)) #7
grpcServer := grpc.NewServer(opts...)
...
}
The Go server listing shows certificate loading, a CA certificate pool and credentials.NewTLS applied to the gRPC server. section 6.3.3
func getTlsCredentials() (credentials.TransportCredentials, error) {
clientCert, clientCertErr := tls.LoadX509KeyPair("cert/client.crt",
"cert/client.key") #1
// handle clientCertErr
certPool := x509.NewCertPool() #2
caCert, caCertErr := ioutil.ReadFile("cert/ca.crt")
// handle caCertErr
if ok := certPool.AppendCertsFromPEM(caCert); !ok { #3
return nil, errors.New("failed to append CA cert.")
}
return credentials.NewTLS(&tls.Config{
ServerName: "*.microservices.dev", #4
Certificates: []tls.Certificate{clientCert}, #5
RootCAs: certPool, #6
}), nil
}
...
func main() {
tlsCredentials, tlsCredentialsErr := getTlsCredentials()
// handle tlsCredentialsErr
var opts []grpc.DialOption
opts = append(opts, grpc.WithTransportCredentials(tlsCredentials)) #7
conn, err := grpc.Dial("localhost:8080", opts...)
// handle err
}
...
The companion client listing shows its certificate, RootCAs and ServerName configuration. section 6.3.3
Local certificate setup is useful for development, not a complete production certificate-management plan. In a larger microservice deployment, delegate certificate generation and management to a third party. TLS also needs attention at the deployment boundary: a Kubernetes Ingress can be configured with a TLS host and certificate-issuer annotation for a gRPC service, but its certificate is not automatically available to clients. The self-signed ingress.local certificate is intended only for local development. section 6.3 section 6.3.3 section 8.3.3
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/backend-protocol: GRPC
nginx.ingress.kubernetes.io/ssl-redirect: "true"
cert-manager.io/cluster-issuer: selfsigned-issuer #1
name: order
spec:
rules:
- http:
paths:
- path: /Order
pathType: Prefix
backend:
service:
name: order
port:
number: 8080
tls:
- hosts:
- ingress.local #2
The Ingress manifest shows the gRPC backend, HTTPS redirect, certificate issuer and TLS host together. section 8.3.3














