Skip to content

Instantly share code, notes, and snippets.

@xlab
Created January 10, 2017 13:00
Show Gist options
  • Save xlab/9ccd6a8ae6ac54c35368fabc885e145a to your computer and use it in GitHub Desktop.
Save xlab/9ccd6a8ae6ac54c35368fabc885e145a to your computer and use it in GitHub Desktop.
A TLS Cert management example for Go server. For different domains.
package main
import (
"crypto/tls"
"flag"
"log"
"net/http"
"os"
"path/filepath"
"strings"
"time"
)
var certsDir = flag.String("certs", "ssl/", "A location of SSL certificates dir.")
func init() {
flag.Parse()
log.SetFlags(log.Lshortfile)
}
func main() {
http.HandleFunc("/", rootHandler)
go http.ListenAndServe(":80", nil)
tlsConfig := getTLSConfig()
srv := &http.Server{
ReadTimeout: time.Minute,
WriteTimeout: time.Minute,
MaxHeaderBytes: 1 << 20,
TLSConfig: tlsConfig,
}
listener, err := tls.Listen("tcp", ":443", tlsConfig)
orPanic(err)
orPanic(srv.Serve(listener))
}
func orPanic(err error) {
if err != nil {
panic(err)
}
}
func getTLSConfig() *tls.Config {
info, err := os.Stat(*certsDir)
if err != nil {
panic("no SSL certs found: " + err.Error())
} else if !info.IsDir() {
panic("SSL certs dir is not a dir")
}
var defaultCert string
certs := make(map[string]bool)
var defaultKey string
keys := make(map[string]bool)
filepath.Walk(*certsDir, func(name string, info os.FileInfo, err error) error {
orPanic(err)
if info.IsDir() {
return nil
}
base := filepath.Base(name)
switch filepath.Ext(name) {
case ".crt":
if filepath.HasPrefix(base, "default_") {
defaultCert = name
return nil
}
certs[name] = true
case ".key":
if filepath.HasPrefix(base, "default_") {
defaultKey = name
return nil
}
keys[name] = true
default:
log.Println("[WARN] unknown file in SSL cert dir:", name)
}
return nil
})
tlsConfig := &tls.Config{}
switch {
case len(defaultCert) == 0 && len(defaultKey) == 0:
log.Println("[WARN] no default cert and key set (no files with prefix default_)")
case len(defaultCert) == 0:
log.Println("[WARN] no default cert set (no files with prefix default_)")
case len(defaultKey) == 0:
log.Println("[WARN] default cert set, but no default key (no files with prefix default_)")
log.Println("[WARN] omitting default cert")
defaultCert = ""
default:
cert, err := tls.LoadX509KeyPair(defaultCert, defaultKey)
orPanic(err)
tlsConfig.Certificates = append(tlsConfig.Certificates, cert)
log.Printf("[INFO] using %s and %s as default cert and key", defaultCert, defaultKey)
}
for certName := range certs {
base := strings.TrimSuffix(certName, filepath.Ext(certName))
key := base + ".key"
if !keys[key] {
if len(defaultKey) == 0 {
log.Println("[WARN] skipping cert", certName, "because no key and no default key file set.")
continue
}
log.Println("[WARN] no key for cert", certName, "fallback to default", defaultKey)
key = defaultKey
}
cert, err := tls.LoadX509KeyPair(certName, key)
orPanic(err)
tlsConfig.Certificates = append(tlsConfig.Certificates, cert)
}
if len(tlsConfig.Certificates) == 0 {
log.Println("[WARN] no certificates loaded from", *certsDir)
return nil
}
tlsConfig.BuildNameToCertificate()
return tlsConfig
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment