As of Go 1.11, this simply isn't possible to accomplish fully within a _test.go
program, due to the mechanics of HTTPS.
However, you can do a single certificate signing and generation of server.crt
and server.key
files, then reference them in your _test.go
programs from a local directory indefinitely.
One-time .crt
and .key
generation
This is an abridged, slightly streamlined version of the steps specified in Daksh Shah's Medium article, How to get HTTPS working on your local development environment in 5 minutes, which will work on a Mac.
In the directory where you want your server.crt
and server.key
files, create the two configuration files
server.csr.cnf
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
[dn]
C=US
ST=RandomState
L=RandomCity
O=RandomOrganization
OU=RandomOrganizationUnit
emailAddress=hello@example.com
CN = localhost
and
v3.ext
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
IP.1 = 127.0.0.1
Then enter the following commands in that directory
openssl genrsa -des3 -out rootCA.key 2048
# create a passphrase
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.pem -config server.csr.cnf
# enter passphrase
openssl req -new -sha256 -nodes -out server.csr -newkey rsa:2048 -keyout server.key -config server.csr.cnf
openssl x509 -req -in server.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out server.crt -days 500 -sha256 -extfile v3.ext
# enter passphrase
Finally, make your system trust the certificate you used to sign the files by running
open rootCA.pem
This should open the certificate in the Keychain Acces app, where it will be found in the section Certificates and named localhost
. Then to Always Trust it
- Press enter to open its window
- Press space to twirl down Trust
- Change "When using this certificate:" to Always Trust
- Close the window and authenticate your decision
Note: I have tried many permutations of security add-trusted-cert
from the command line and, despite the fact that it adds the cert to the keychain and marks it as "Always Trust", my Go programs just won't trust it. Only the GUI method puts the system in a state that my Go programs will trust the cert.
Any Go programs you run locally using HTTPS will now trust servers you run using server.crt
and server.key
.
Running the server
You can create *httptest.Server
instances that use these credentials with
func NewLocalHTTPSTestServer(handler http.Handler) (*httptest.Server, error) {
ts := httptest.NewUnstartedServer(handler)
cert, err := tls.LoadX509KeyPair("server.crt", "server.key")
if err != nil {
return nil, err
}
ts.TLS = &tls.Config{Certificates: []tls.Certificate{cert}}
ts.StartTLS()
return ts, nil
}
Here is an example usage:
func TestLocalHTTPSserver(t *testing.T) {
ts, err := NewLocalHTTPSTestServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello, client")
}))
assert.Nil(t, err)
defer ts.Close()
res, err := http.Get(ts.URL)
assert.Nil(t, err)
greeting, err := ioutil.ReadAll(res.Body)
res.Body.Close()
assert.Nil(t, err)
assert.Equal(t, "Hello, client", string(greeting))
}