[tor-commits] [snowflake/master] autocert (Let's Encrypt) for broker.

dcf at torproject.org dcf at torproject.org
Thu Aug 3 02:35:44 UTC 2017


commit 2d89aa0b7bf10c571f934b846c363cf4a2b9b761
Author: David Fifield <david at 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's_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)
+	}
 }





More information about the tor-commits mailing list