commit 2d89aa0b7bf10c571f934b846c363cf4a2b9b761 Author: David Fifield david@bamsoftware.com Date: Fri Jul 14 20:25:46 2017 -0700
autocert (Let's Encrypt) for broker.
Replaces --cert and --key with --acme-hostnames and --acme-email. --- broker/README.md | 26 +++++++++++++++++++--- broker/broker.go | 68 +++++++++++++++++++++++++++----------------------------- 2 files changed, 56 insertions(+), 38 deletions(-)
diff --git a/broker/README.md b/broker/README.md index 1efe9fc..8d8c968 100644 --- a/broker/README.md +++ b/broker/README.md @@ -22,9 +22,29 @@ The Broker expects:
### Running your own
-You can run your own Broker on localhost, you'll need to pass a TLS -certificate file using `--cert` option and the corresponding private key -file using `--key` option. +The server uses TLS by default. +There is a `--disable-tls` option for testing purposes, +but you should use TLS in production. + +The server automatically fetches certificates +from [Let's Encrypt](https://en.wikipedia.org/wiki/Let%27s_Encrypt) as needed. +Use the `--acme-hostnames` option to tell the server +what hostnames it may request certificates for. +You can optionally provide a contact email address, +using the `--acme-email` option, +so that Let's Encrypt can inform you of any problems. + +In order to fetch certificates automatically, +the server needs to be listening on port 443 (the default). +On Linux, you can use the `setcap` program, +part of libcap2, to enable the broker to bind to low-numbered ports +without having to run as root: +``` +setcap 'cap_net_bind_service=+ep' /usr/local/bin/broker +``` +You can control the listening port with the --tlsPort +or --webPort options (--webPort is honored only when +also using --disable-tls).
You'll need to provide the URL of the custom broker to the client plugin using the `--url $URL` flag. diff --git a/broker/broker.go b/broker/broker.go index f56f31b..9892fc3 100644 --- a/broker/broker.go +++ b/broker/broker.go @@ -7,15 +7,17 @@ package main
import ( "container/heap" + "crypto/tls" "flag" "fmt" "io/ioutil" "log" "net" "net/http" - "os" - "sync" + "strings" "time" + + "golang.org/x/crypto/acme/autocert" )
const ( @@ -230,26 +232,18 @@ func ipHandler(w http.ResponseWriter, r *http.Request) { }
func main() { - var cert, cert_key, http_port, https_port string - - flag.StringVar(&cert, "cert", "", "TLS certificate file") - flag.StringVar(&cert_key, "key", "", "TLS key file") + var acmeEmail string + var acmeHostnamesCommas string + var disableTLS bool + var http_port, https_port string
+ flag.StringVar(&acmeEmail, "acme-email", "", "optional contact email for Let's Encrypt notifications") + flag.StringVar(&acmeHostnamesCommas, "acme-hostnames", "", "comma-separated hostnames for TLS certificate") + flag.BoolVar(&disableTLS, "disable-tls", false, "don't use HTTPS") flag.StringVar(&http_port, "webPort", "80", "HTTP port number") flag.StringVar(&https_port, "tlsPort", "443", "HTTPS port number") - flag.Parse()
- if cert == "" || cert_key == "" { - log.Println("Missing options, exiting.") - fmt.Println("Usage:") - flag.PrintDefaults() - os.Exit(1) - } - - log.Println("Using cert file:", cert) - log.Println("Using cert key file: ", cert_key) - ctx := NewBrokerContext()
go ctx.Broker() @@ -262,26 +256,30 @@ func main() { http.Handle("/answer", SnowflakeHandler{ctx, proxyAnswers}) http.Handle("/debug", SnowflakeHandler{ctx, debugHandler})
- var wg sync.WaitGroup - wg.Add(2) + var err error + var server http.Server
- //Run HTTP server - go func() { - defer wg.Done() - err := http.ListenAndServe(":"+http_port, nil) - if err != nil { - log.Println("ListenAndServe: ", err) - } - }() + if acmeHostnamesCommas != "" { + acmeHostnames := strings.Split(acmeHostnamesCommas, ",") + log.Printf("ACME hostnames: %q", acmeHostnames)
- //Run HTTPS server - go func() { - defer wg.Done() - err := http.ListenAndServeTLS(":"+https_port, cert, cert_key, nil) - if err != nil { - log.Println("ListenAndServeTLS: ", err) + certManager := autocert.Manager{ + Prompt: autocert.AcceptTOS, + HostPolicy: autocert.HostWhitelist(acmeHostnames...), + Email: acmeEmail, } - }()
- wg.Wait() + server.Addr = net.JoinHostPort("", https_port) + server.TLSConfig = &tls.Config{GetCertificate: certManager.GetCertificate} + err = server.ListenAndServeTLS("", "") + } else if disableTLS { + server.Addr = net.JoinHostPort("", http_port) + err = server.ListenAndServe() + } else { + log.Fatal("the --acme-hostnames or --disable-tls option is required") + } + + if err != nil { + log.Fatal(err) + } }
tor-commits@lists.torproject.org