Mutually Authenticated TLS from a Go client
Mutually Authenticated TLS is a good way to secure an API that will only have a handful of users. (You have to generate a new certificate for every user, and they have to jump through some hoops in order to use them.) Consumers aren’t going to do that, but for your internal services, you can.
I had to do this in Go, and if I ever do it again I’m going to wish I’d written it down. Maybe it’ll be useful to you too?
This assumes you already have your own internal CA, have generated server and client certificates with it, and the server is set up to require that every client provide valid certificates in order to connect.
To connect to such an API from a Go client, you’ll need to load the root CA certificate and the client certificate and key such that your HTTP client can use them.
import (
"crypto/tls"
"crypto/x509"
"io/ioutil"
"net/http"
)// the CertPool wants to add a root as a []byte so we read the file ourselves
caCert, err := ioutil.ReadFile("/path/to/ca.crt")
pool := x509.NewCertPool()
pool.AppendCertsFromPEM(caCert)// LoadX509KeyPair reads files, so we give it the paths
clientCert, err := tls.LoadX509KeyPair("/path/to/client.crt", "/path/to/client.key")tlsConfig := tls.Config{
RootCAs: pool,
Certificates: []tls.Certificate{clientCert},
}transport := http.Transport{
TLSClientConfig: &tlsConfig,
}client := http.Client{
Transport: &transport,
}
Of course you can add whatever other parameters you want to the http.Transport
and the http.Client
, these are just the minimum you need in order to get mutually authenticated TLS working.
Now that you have your HTTP client, you can use it as you normally would.
resp, err := client.Get("https://example.com/things")req, err := http.NewRequest("POST", "https://example.com/things", body)
resp, err := client.Do(req)
Setting it up is sensible due to Go’s crypto
packages, and once you've done it, you won't have to think about it any more and it doesn't change the way the rest of your net/http
-related code works. This is what I've come to expect from Go.