maintner: migrate secrets to secret manager

This change retrieves the secrets used by maintner from secret
manager. It is part of the project to store all secrets in a single
location. It also modifies how gitauth retrieves secrets (which is
used by other packages including maintner).

Updates golang/go#37171

Change-Id: I53cf3e2a3f1be8d98c0ac2481f4d6c05d4d0fc46
Reviewed-on: https://go-review.googlesource.com/c/build/+/222960
Run-TryBot: Carlos Amedee <carlos@golang.org>
Run-TryBot: Alexander Rakoczy <alex@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Alexander Rakoczy <alex@golang.org>
diff --git a/internal/gitauth/gitauth.go b/internal/gitauth/gitauth.go
index 6eb5495..fc5e083 100644
--- a/internal/gitauth/gitauth.go
+++ b/internal/gitauth/gitauth.go
@@ -8,6 +8,7 @@
 
 import (
 	"bytes"
+	"context"
 	"fmt"
 	"io/ioutil"
 	"log"
@@ -15,8 +16,10 @@
 	"os/exec"
 	"path/filepath"
 	"strings"
+	"time"
 
 	"cloud.google.com/go/compute/metadata"
+	"golang.org/x/build/internal/secret"
 )
 
 func Init() error {
@@ -28,14 +31,19 @@
 		// Do nothing for now.
 		return nil
 	}
-	slurp, err := metadata.ProjectAttributeValue("gobot-password")
+
+	sc := mustCreateSecretClient()
+	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+	defer cancel()
+
+	slurp, err := sc.Retrieve(ctx, secret.NameGobotPassword)
 	if err != nil {
 		proj, _ := metadata.ProjectID()
 		if proj != "symbolic-datum-552" { // TODO: don't hard-code this; use buildenv package
-			log.Printf("gitauth: ignoring 'gobot-password' GCE metadata lookup on non-prod project: %v", err)
+			log.Printf("gitauth: ignoring %q secret manager lookup on non-prod project: %v", secret.NameGobotPassword, err)
 			return nil
 		}
-		return fmt.Errorf("gitauth: getting gobot-password GCE metadata: %v", err)
+		return fmt.Errorf("gitauth: getting %s secret manager: %v", secret.NameGobotPassword, err)
 	}
 	slurp = strings.TrimSpace(slurp)
 	var buf bytes.Buffer
@@ -51,3 +59,11 @@
 	log.Fatalf("No HOME set in environment.")
 	panic("unreachable")
 }
+
+func mustCreateSecretClient() *secret.Client {
+	client, err := secret.NewClient()
+	if err != nil {
+		log.Fatalf("unable to create secret client %v", err)
+	}
+	return client
+}
diff --git a/maintner/godata/godata_test.go b/maintner/godata/godata_test.go
index 59c11e2..eca159d 100644
--- a/maintner/godata/godata_test.go
+++ b/maintner/godata/godata_test.go
@@ -14,9 +14,11 @@
 	"strings"
 	"sync"
 	"testing"
+	"time"
 
 	"cloud.google.com/go/compute/metadata"
 	"golang.org/x/build/gerrit"
+	"golang.org/x/build/internal/secret"
 	"golang.org/x/build/maintner"
 )
 
@@ -278,16 +280,24 @@
 	}
 }
 
+// getSecret retrieves a secret by name from the secret manager service.
+func getSecret(name string) (string, error) {
+	sc, err := secret.NewClient()
+	if err != nil {
+		return "", err
+	}
+	defer sc.Close()
+
+	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+	defer cancel()
+
+	return sc.Retrieve(ctx, name)
+}
+
 func getGerritAuth() (username string, password string, err error) {
 	var slurp string
 	if metadata.OnGCE() {
-		for _, key := range []string{"gopherbot-gerrit-token", "maintner-gerrit-token", "gobot-password"} {
-			slurp, err = metadata.ProjectAttributeValue(key)
-			if err != nil || slurp == "" {
-				continue
-			}
-			break
-		}
+		slurp, _ = getSecret(secret.NameGobotPassword)
 	}
 	if slurp == "" {
 		var ok bool
diff --git a/maintner/maintnerd/maintnerd.go b/maintner/maintnerd/maintnerd.go
index 7ae2bca..7f7c3a6 100644
--- a/maintner/maintnerd/maintnerd.go
+++ b/maintner/maintnerd/maintnerd.go
@@ -30,6 +30,7 @@
 	"cloud.google.com/go/storage"
 	"golang.org/x/build/autocertcache"
 	"golang.org/x/build/internal/gitauth"
+	"golang.org/x/build/internal/secret"
 	"golang.org/x/build/maintner"
 	"golang.org/x/build/maintner/godata"
 	"golang.org/x/build/maintner/maintnerd/apipb"
@@ -82,12 +83,13 @@
 
 func main() {
 	flag.Parse()
+	ctx := context.Background()
 
 	if *autocertDomain != "" {
 		if *autocertBucket == "" {
 			log.Fatalf("using --autocert requires --autocert-bucket.")
 		}
-		sc, err := storage.NewClient(context.Background())
+		sc, err := storage.NewClient(ctx)
 		if err != nil {
 			log.Fatalf("Creating autocert cache, storage.NewClient: %v", err)
 		}
@@ -128,7 +130,7 @@
 		}
 		log.Printf("Syncing from https://maintner.golang.org/logs to %s", dir)
 		mutSrc := maintner.NewNetworkMutationSource("https://maintner.golang.org/logs", dir)
-		for evt := range mutSrc.GetMutations(context.Background()) {
+		for evt := range mutSrc.GetMutations(ctx) {
 			if evt.Err != nil {
 				log.Fatal(evt.Err)
 			}
@@ -148,7 +150,7 @@
 		setGodataConfig()
 		var err error
 		log.Printf("Using godata corpus...")
-		corpus, err = godata.Get(context.Background())
+		corpus, err = godata.Get(ctx)
 		if err != nil {
 			log.Fatal(err)
 		}
@@ -193,7 +195,7 @@
 			if len(splits) != 2 || splits[1] == "" {
 				log.Fatalf("Invalid github repo: %s. Should be 'owner/repo,owner2/repo2'", pair)
 			}
-			token, err := getGithubToken()
+			token, err := getGithubToken(ctx)
 			if err != nil {
 				log.Fatalf("getting github token: %v", err)
 			}
@@ -362,13 +364,18 @@
 	*genMut = false
 }
 
-func getGithubToken() (string, error) {
+func getGithubToken(ctx context.Context) (string, error) {
 	if metadata.OnGCE() {
-		token, err := metadata.ProjectAttributeValue("maintner-github-token")
+		sc := mustCreateSecretClient()
+
+		ctxSc, cancel := context.WithTimeout(ctx, 10*time.Second)
+		defer cancel()
+
+		token, err := sc.Retrieve(ctxSc, secret.NameMaintnerGitHubToken)
 		if err == nil {
 			return token, nil
 		}
-		log.Printf("getting GCE metadata 'maintner-github-token': %v", err)
+		log.Printf("unable to retrieve secret manager %q: %v", secret.NameMaintnerGitHubToken, err)
 		log.Printf("falling back to github token from file.")
 	}
 
@@ -496,3 +503,11 @@
 		}
 	}
 }
+
+func mustCreateSecretClient() *secret.Client {
+	client, err := secret.NewClient()
+	if err != nil {
+		log.Fatalf("unable to create secret client %v", err)
+	}
+	return client
+}