cmd/pubsubhelper: migrate secrets to secret manager

This change retrieves the secrets used by pubsubhelper from secret
manager. It is part of the project to store all secrets in a single
location.

The change required updating the ca-certificates in the container. I
made the docker configuration match the gopherbot configuration in
an effort to maintain uniformity.

Updates golang/go#37171

Change-Id: I0d48beccb08ac2e850a99cff1b45df3907b13474
Reviewed-on: https://go-review.googlesource.com/c/build/+/222177
Run-TryBot: Carlos Amedee <carlos@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Alexander Rakoczy <alex@golang.org>
diff --git a/cmd/pubsubhelper/Dockerfile b/cmd/pubsubhelper/Dockerfile
index cfff76f..1b93f02 100644
--- a/cmd/pubsubhelper/Dockerfile
+++ b/cmd/pubsubhelper/Dockerfile
@@ -32,5 +32,18 @@
 FROM debian:stretch
 LABEL maintainer "golang-dev@googlegroups.com"
 
+# netbase and ca-certificates are needed for dialing TLS.
+# The rest are useful for debugging if somebody needs to exec into the container.
+RUN apt-get update && apt-get install -y \
+	--no-install-recommends \
+	netbase \
+	ca-certificates \
+	curl \
+	strace \
+	procps \
+	lsof \
+	psmisc \
+	&& rm -rf /var/lib/apt/lists/*
+
 COPY --from=build /go/bin/pubsubhelper /
 ENTRYPOINT ["/pubsubhelper"]
diff --git a/cmd/pubsubhelper/github.go b/cmd/pubsubhelper/github.go
index 9e2428f..f4191a0 100644
--- a/cmd/pubsubhelper/github.go
+++ b/cmd/pubsubhelper/github.go
@@ -17,7 +17,6 @@
 	"net/http"
 	"strings"
 
-	"cloud.google.com/go/compute/metadata"
 	"golang.org/x/build/cmd/pubsubhelper/pubsubtypes"
 )
 
@@ -97,16 +96,12 @@
 		return nil, err
 	}
 
-	// Compute expected signature.
-	key, err := metadata.ProjectAttributeValue("pubsubhelper-webhook-secret")
-	if err != nil {
-		return nil, err
-	}
 	body, err = ioutil.ReadAll(http.MaxBytesReader(w, r.Body, 5<<20))
 	if err != nil {
 		return nil, err
 	}
-	mac := hmac.New(h, []byte(key))
+	// TODO(golang/go#37171): find a cleaner solution than using a global
+	mac := hmac.New(h, []byte(*webhookSecret))
 	mac.Write(body)
 	expectSig := mac.Sum(nil)
 
diff --git a/cmd/pubsubhelper/pubsubhelper.go b/cmd/pubsubhelper/pubsubhelper.go
index 9e084a9..91de894 100644
--- a/cmd/pubsubhelper/pubsubhelper.go
+++ b/cmd/pubsubhelper/pubsubhelper.go
@@ -32,19 +32,22 @@
 	"github.com/jellevandenhooff/dkim"
 	"go4.org/types"
 	"golang.org/x/build/cmd/pubsubhelper/pubsubtypes"
+	"golang.org/x/build/internal/secret"
 	"golang.org/x/crypto/acme/autocert"
 )
 
 var (
-	botEmail   = flag.String("rcpt", "\x67\x6f\x70\x68\x65\x72\x62\x6f\x74@pubsubhelper.golang.org", "email address of bot. incoming emails must be to this address.")
-	httpListen = flag.String("http", ":80", "HTTP listen address")
-	acmeDomain = flag.String("autocert", "pubsubhelper.golang.org", "If non-empty, listen on port 443 and serve HTTPS with a LetsEncrypt cert for this domain.")
-	smtpListen = flag.String("smtp", ":25", "SMTP listen address")
+	botEmail      = flag.String("rcpt", "\x67\x6f\x70\x68\x65\x72\x62\x6f\x74@pubsubhelper.golang.org", "email address of bot. incoming emails must be to this address.")
+	httpListen    = flag.String("http", ":80", "HTTP listen address")
+	acmeDomain    = flag.String("autocert", "pubsubhelper.golang.org", "If non-empty, listen on port 443 and serve HTTPS with a LetsEncrypt cert for this domain.")
+	smtpListen    = flag.String("smtp", ":25", "SMTP listen address")
+	webhookSecret = flag.String("webhook-secret", "", "Development mode GitHub webhook secret. This flag should not be used in production.")
 )
 
 func main() {
 	flag.Parse()
 
+	ctx := context.Background()
 	ch := make(chan os.Signal, 1)
 	signal.Notify(ch, os.Interrupt)
 	go func() {
@@ -53,6 +56,21 @@
 		os.Exit(0)
 	}()
 
+	// webhooksecret should not be set in production
+	if *webhookSecret == "" {
+		sc := mustCreateSecretClient()
+		defer sc.Close()
+
+		ctxSc, cancel := context.WithTimeout(ctx, 10*time.Second)
+		defer cancel()
+
+		var err error
+		*webhookSecret, err = sc.Retrieve(ctxSc, secret.NamePubSubHelperWebhook)
+		if err != nil {
+			log.Fatalf("unable to retrieve webhook secret %v", err)
+		}
+	}
+
 	http.HandleFunc("/", handleRoot)
 	http.HandleFunc("/waitevent", handleWaitEvent)
 	http.HandleFunc("/recent", handleRecent)
@@ -410,3 +428,11 @@
 	log.Printf("smtpd: new connection from %v", c.Addr())
 	return nil
 }
+
+func mustCreateSecretClient() *secret.Client {
+	client, err := secret.NewClient()
+	if err != nil {
+		log.Fatalf("unable to create secret client %v", err)
+	}
+	return client
+}