debian-forge-composer/internal/cloud/gcp/gcp.go
Tomas Hozza 249661a948 worker: rework GCP credentials handling
Refactor the handling of GCP credentials in the worker to be equivalent
to what is done for AWS. The main idea is that the code decides which
credentials to use when processing each job. This change will allow
preferring credentials passed via upload `TargetOptions` with the job,
over the credentials configured in worker's configuration or the default
way of authenticating implemented by the Google library.

Move loading of GCP credentials to the internal `gcp` library into
`NewFromFile()` function accepting path to the file with credentials.

Signed-off-by: Tomas Hozza <thozza@redhat.com>
2022-04-14 19:07:31 +01:00

95 lines
2.7 KiB
Go

package gcp
import (
"context"
"fmt"
"io/ioutil"
"os"
cloudbuild "cloud.google.com/go/cloudbuild/apiv1"
compute "cloud.google.com/go/compute/apiv1"
"cloud.google.com/go/storage"
"golang.org/x/oauth2/google"
)
// GCPCredentialsEnvName contains name of the environment variable used
// to specify the path to file with CGP service account credentials
const (
GCPCredentialsEnvName string = "GOOGLE_APPLICATION_CREDENTIALS"
)
// GCP structure holds necessary information to authenticate and interact with GCP.
type GCP struct {
creds *google.Credentials
}
// New returns an authenticated GCP instance, allowing to interact with GCP API.
func New(credentials []byte) (*GCP, error) {
scopes := []string{storage.ScopeReadWrite} // file upload
scopes = append(scopes, compute.DefaultAuthScopes()...) // permissions to image
scopes = append(scopes, cloudbuild.DefaultAuthScopes()...) // image import
var getCredsFunc func() (*google.Credentials, error)
if credentials != nil {
getCredsFunc = func() (*google.Credentials, error) {
return google.CredentialsFromJSON(
context.Background(),
credentials,
scopes...,
)
}
} else {
getCredsFunc = func() (*google.Credentials, error) {
return google.FindDefaultCredentials(
context.Background(),
scopes...,
)
}
}
creds, err := getCredsFunc()
if err != nil {
return nil, fmt.Errorf("failed to get Google credentials: %v", err)
}
return &GCP{creds}, nil
}
// NewFromFile loads the credentials from a file and returns an authenticated
// *GCP object instance.
func NewFromFile(path string) (*GCP, error) {
gcpCredentials, err := ioutil.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("cannot load GCP credentials from file %q: %v", path, err)
}
return New(gcpCredentials)
}
// GetCredentialsFromEnv reads the service account credentials JSON file from
// the path pointed to by the environment variable name stored in
// 'GCPCredentialsEnvName'. If the content of the JSON file was read successfully,
// its content is returned as []byte, otherwise nil is returned with proper error.
func GetCredentialsFromEnv() ([]byte, error) {
credsPath, exists := os.LookupEnv(GCPCredentialsEnvName)
if !exists {
return nil, fmt.Errorf("'%s' env variable is not set", GCPCredentialsEnvName)
}
if credsPath == "" {
return nil, fmt.Errorf("'%s' env variable is empty", GCPCredentialsEnvName)
}
var err error
credentials, err := ioutil.ReadFile(credsPath)
if err != nil {
return nil, fmt.Errorf("Error while reading credentials file: %s", err)
}
return credentials, nil
}
// GetProjectID returns a string with the Project ID of the project, used for
// all GCP operations.
func (g *GCP) GetProjectID() string {
return g.creds.ProjectID
}