Skip to content

Instantly share code, notes, and snippets.

@lxdlam
Created January 10, 2025 09:51
Show Gist options
  • Save lxdlam/ccd02a9b42f41b5d34df318742c1ec0d to your computer and use it in GitHub Desktop.
Save lxdlam/ccd02a9b42f41b5d34df318742c1ec0d to your computer and use it in GitHub Desktop.
golang mTLS + step-ca example
  1. Bootstrap a local smallstep CA following the guide. Remember to start your CA server.
  2. Issue certificates:
    • Download Root ca: step ca root ca.crt
    • Issue server cert: step ca certificate "mtls.internal" server.crt server.key
    • Issue client cert: step ca certificate "mtls.internal" client.crt client.key
  3. Start the server at the same directory or modify the code to locate the cert files. If you issued the certs like my setup, remember to add the domain mtls.internal in your hosts or so on.
  4. Test with TestClient or test with curl: curl -vvvv https://mtls.internal:8080 --cacert ca.crt --cert client.crt --key client.key.
package main
import (
"crypto/tls"
"crypto/x509"
"fmt"
"net/http"
"os"
"time"
)
type mtlsHandler struct{}
func (mtlsHandler) ServeHTTP(w http.ResponseWriter, _r *http.Request) {
fmt.Fprintf(w, "Hello from my mTLS server! Time: %s", time.Now().Format(time.RFC3339))
}
func main() {
caCert, _ := os.ReadFile("ca.crt")
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
tlsConfig := &tls.Config{
ClientCAs: caCertPool,
ClientAuth: tls.RequireAndVerifyClientCert,
}
server := &http.Server{
Addr: ":8080",
Handler: &mtlsHandler{},
TLSConfig: tlsConfig,
}
panic(server.ListenAndServeTLS("server.crt", "server.key"))
}
// or you should read this file as "client.go"
package main
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io"
"net/http"
"os"
"testing"
)
func TestClient(t *testing.T) {
caCert, _ := os.ReadFile("ca.crt")
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
cert, _ := tls.LoadX509KeyPair("client.crt", "client.key")
client := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: caCertPool,
Certificates: []tls.Certificate{cert},
},
},
}
r, err := client.Get("https://mtls.internal:8080")
if err != nil {
t.Fatal(err)
}
defer r.Body.Close()
ret, err := io.ReadAll(r.Body)
if err != nil {
t.Fatal(err)
}
fmt.Println(string(ret))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment