A little about TLS use in gRPC

When you look at most examples for gRPC client and server, there are two examples given:

  • Set grpc.WithInsecure for the client, turning off TLS
  • Create a self-signed certificate for the server and supply the public cert to the client

Both of these are bad practices.

WithInsecure just says: "Hey! Please man in the middle me". There are plenty of websites you might turn up where you really don't care about hacking potential or state-sponsored manipulation. But, generally gRPC services for your company are not going to be those.

Self-signed certificates are just a bad habit to get into. How are the certificates managed, are the properly secured (much harder than you think), how often do you rotate them? Having a Certificate Authority (CA) can provide you with robust mechanisms for generating, revoking and disseminating your private keys.

Your cloud providers such as Azure, AWS, and GCP offer services for interacting with many popular CAs and storage of these secrets.

In addition, for smaller shops, Let's Encrypt can offer TLS certificates for free.

Why supply a public cert anyways?

I was recently using gRPC for a few projects. I hadn't really used it with certificates before, as my previous experience had been with Google's internal version where this is automated away from the developer.

I was surprised that the examples required you to supply a certificate. Web browsers don't hold public certificates for TLS, why should my application?

Not being a browser's internals expert, I simply read up on the process. A browser reaches a site with TLS, retrieves the public cert from the service, validates its certificate chain and checks to see that the root CA that signed it is in the browser's trusted CA list.

So a small tool for auto-retrieval of certificates from a TLS server was born:

https://godoc.org/github.com/johnsiilver/getcert

Usage is simple:

tlsCert, xCerts, err := FromTLSServer("service.com:443", true)

This command will return the TLS certificate (including the public cert, intermediate cert and root certs if provided by the server) for use in gRPC or other HTTPS client. In addition, it returns it in x509 form in case you wish to do inspections on the information (such as do you trust the CA).

The boolean simply does a validation check against the certificate chain to make sure that the root signs the intermediate which should sign the public and that it is for the endpoint specified. You may turn off validation, but that is not recommended unless you are going to do the validations yourself.

You can use this to supply your applications now without pulling the public certificate from storage.

A note on PKCS#12

I have been dealing with PCKS#12 lately as that is what one of the CAs I use returns. As Go really likes PEM, I have been needing the use of the PKCS#12 library that is published in golang.org/x/crypto/pkcs12 .

I'm grateful for the library, as I wouldn't want to have to try and unravel the RFC if there even is one. However, the library still has that "in progress" API feel to it and lacks some features.

The Decode() method for one cannot handle public certificate chains (and notes it). You need to use another function that doesn't get you to where you need to be to use the returned values.

It also lacks the ability to decode PKCS#12 certificates that can be generated by Windows CAs. There are a few OIDs there that are used in OSCP and others I haven't found good documentation on. Those aren't required for the general use case.

I have a wrapper that should make this easier based on a vendored version of the pkcs12 package:

https://godoc.org/github.com/johnsiilver/getcert/pkcs12

Please be aware there are no tests here, so your mileage may vary. I'm sure I haven't compensated for all uses and encodings. If nothing else, maybe someone can use this to make a much better package.

Author Note:

I am not a TLS expert. At best I am a TLS hacker by reverse engineering code by my betters.

Because of that I use existing code with wrappers or slight modifications.

All validation comes out of the stdlib, which doesn't do revocation checking. You may wish to test for this and other things (such as you trust the CA) before using the certificate.

About the Author

John Doak is the manager of Process Engineering for the Azure Fleet Program and the Principal Automation SWE for Azure Fleet at Microsoft.

Previously he was a Google Staff Site Reliability Engineer, a Network Systems Engineer (a now defunct subtype of SRE for Network Systems of which he was Google’s first), and a Network Engineer (among other titles).

In a previous life he worked on movies and games for LucasArts/LucasFilm/ILM as a Network Engineer/Systems Admin.

Contact
Website (Golang, SRE): www.gophersre.com,
Website (Photography): www.obscuredworld.com
Linkedin: https://www.linkedin.com/in/johngdoak/