cmd/{genbuilderkey,retrybuilds}: get key from secret manager first

Now that secret manager exists and provides an ability for us to store
and access secrets securely and conveniently, update these commands to
prefer fetching the secret from there (rather than from local disk).

For golang/go#34744.

Change-Id: I6a003936665091088cdbd856aa5586351c39f569
Reviewed-on: https://go-review.googlesource.com/c/build/+/336212
Run-TryBot: Dmitri Shuralyov <dmitshur@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Alexander Rakoczy <alex@golang.org>
Trust: Alexander Rakoczy <alex@golang.org>
Trust: Dmitri Shuralyov <dmitshur@golang.org>
diff --git a/cmd/genbuilderkey/genbuilderkey.go b/cmd/genbuilderkey/genbuilderkey.go
index 37d220f..8d7d710 100644
--- a/cmd/genbuilderkey/genbuilderkey.go
+++ b/cmd/genbuilderkey/genbuilderkey.go
@@ -19,21 +19,25 @@
 	"os"
 	"path/filepath"
 	"strings"
-	"time"
 
+	"golang.org/x/build/buildenv"
 	"golang.org/x/build/internal/secret"
 )
 
 func usage() {
 	fmt.Fprintln(os.Stderr, "Usage: genbuilderkey <Host Type>")
+	fmt.Fprintln(os.Stderr)
 	fmt.Fprintln(os.Stderr, "Master builder key should be available to genbuilderkey by either:")
-	fmt.Fprintln(os.Stderr, " - File: $HOME/keys/gobuilder-master.key")
 	fmt.Fprintln(os.Stderr, " - Secret Management: executing genbuilderkey with access to secret management")
+	fmt.Fprintln(os.Stderr, " - File: $HOME/keys/gobuilder-master.key")
+	fmt.Fprintln(os.Stderr)
+	fmt.Fprintln(os.Stderr, "Flags:")
 	flag.PrintDefaults()
 }
 
 func main() {
 	flag.Usage = usage
+	buildenv.RegisterStagingFlag()
 	flag.Parse()
 	if flag.NArg() != 1 {
 		flag.Usage()
@@ -61,17 +65,13 @@
 	panic("not reachable")
 }
 
-// getMasterKeyFromSecretManager retrieves the master key from the secret
-// manager service.
+// getMasterKeyFromSecretManager retrieves the master key
+// from the secret manager service.
 func getMasterKeyFromSecretManager() (string, error) {
-	sc, err := secret.NewClient()
+	sc, err := secret.NewClientInProject(buildenv.FromFlags().ProjectName)
 	if err != nil {
 		return "", err
 	}
 	defer sc.Close()
-
-	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
-	defer cancel()
-
-	return sc.Retrieve(ctx, secret.NameBuilderMasterKey)
+	return sc.Retrieve(context.Background(), secret.NameBuilderMasterKey)
 }
diff --git a/cmd/retrybuilds/retrybuilds.go b/cmd/retrybuilds/retrybuilds.go
index 3f84f89..4e5676f 100644
--- a/cmd/retrybuilds/retrybuilds.go
+++ b/cmd/retrybuilds/retrybuilds.go
@@ -35,7 +35,9 @@
 	"sync"
 	"time"
 
+	"golang.org/x/build/buildenv"
 	"golang.org/x/build/cmd/coordinator/protos"
+	"golang.org/x/build/internal/secret"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/credentials"
@@ -65,6 +67,7 @@
 }
 
 func main() {
+	buildenv.RegisterStagingFlag()
 	flag.Parse()
 	*builderPrefix = strings.TrimSuffix(*builderPrefix, "/")
 	cl := client{}
@@ -315,21 +318,33 @@
 }
 
 func builderKeyFromMaster(builder string) (key string, ok bool) {
-	if *masterKeyFile == "" {
-		return
-	}
-	slurp, err := ioutil.ReadFile(*masterKeyFile)
+	masterKey, err := getMasterKeyFromSecretManager()
 	if err != nil {
-		return
+		slurp, err := ioutil.ReadFile(*masterKeyFile)
+		if err != nil {
+			return "", false
+		}
+		masterKey = string(bytes.TrimSpace(slurp))
 	}
 	if *sendMasterKey {
-		return string(slurp), true
+		return masterKey, true
 	}
-	h := hmac.New(md5.New, bytes.TrimSpace(slurp))
+	h := hmac.New(md5.New, []byte(masterKey))
 	h.Write([]byte(builder))
 	return fmt.Sprintf("%x", h.Sum(nil)), true
 }
 
+// getMasterKeyFromSecretManager retrieves the master key
+// from the secret manager service.
+func getMasterKeyFromSecretManager() (string, error) {
+	sc, err := secret.NewClientInProject(buildenv.FromFlags().ProjectName)
+	if err != nil {
+		return "", err
+	}
+	defer sc.Close()
+	return sc.Retrieve(context.Background(), secret.NameBuilderMasterKey)
+}
+
 var (
 	failMu    sync.Mutex
 	failCache []Failure
diff --git a/internal/secret/gcp_secret_manager.go b/internal/secret/gcp_secret_manager.go
index 5d1ec82..4b6dc57 100644
--- a/internal/secret/gcp_secret_manager.go
+++ b/internal/secret/gcp_secret_manager.go
@@ -71,10 +71,11 @@
 // Client is used to interact with the GCP Secret Management service.
 type Client struct {
 	client    secretClient
-	projectID string
+	projectID string // projectID specifies the ID of the GCP project where secrets are retreived from.
 }
 
-// NewClient instantiates an instance of the Secret Manager Client.
+// NewClient creates a Secret Manager Client
+// that targets the current GCP instance's project ID.
 func NewClient() (*Client, error) {
 	projectID, err := metadata.ProjectID()
 	if err != nil {
@@ -95,6 +96,19 @@
 	}, nil
 }
 
+// NewClientInProject creates a Secret Manager Client
+// that targets the specified GCP project ID.
+func NewClientInProject(projectID string) (*Client, error) {
+	client, err := secretmanager.NewClient(context.Background())
+	if err != nil {
+		return nil, err
+	}
+	return &Client{
+		client:    client,
+		projectID: projectID,
+	}, nil
+}
+
 // Retrieve the named secret from the Secret Management service.
 func (smc *Client) Retrieve(ctx context.Context, name string) (string, error) {
 	r, err := smc.client.AccessSecretVersion(ctx, &secretmanagerpb.AccessSecretVersionRequest{