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>
This commit is contained in:
Tomas Hozza 2022-03-07 14:29:38 +01:00 committed by Tom Gundersen
parent 29174bfbef
commit 249661a948
3 changed files with 47 additions and 11 deletions

View file

@ -33,7 +33,7 @@ type OSBuildJobImpl struct {
Store string
Output string
KojiServers map[string]koji.GSSAPICredentials
GCPCreds []byte
GCPCreds string
AzureCreds *azure.Credentials
AWSCreds string
AWSBucket string
@ -63,6 +63,37 @@ func (impl *OSBuildJobImpl) getAWSForEndpoint(endpoint, region, accessId, secret
return nil, fmt.Errorf("no credentials found")
}
// getGCP returns an *gcp.GCP object using credentials based on the following
// predefined preference:
//
// 1. If the provided `credentials` parameter is not `nil`, it is used to
// authenticate with GCP.
//
// 2. If a path to GCP credentials file was provided in the worker's
// configuration, it is used to authenticate with GCP.
//
// 3. Use Application Default Credentials from the Google library, which tries
// to automatically find a way to authenticate using the following options:
//
// 3a. If `GOOGLE_APPLICATION_CREDENTIALS` environment variable is set, it
// tries to load and use credentials form the file pointed to by the
// variable.
//
// 3b. It tries to authenticate using the service account attached to the
// resource which is running the code (e.g. Google Compute Engine VM).
func (impl *OSBuildJobImpl) getGCP(credentials []byte) (*gcp.GCP, error) {
if credentials != nil {
logrus.Info("[GCP] 🔑 using credentials provided with the job request")
return gcp.New(credentials)
} else if impl.GCPCreds != "" {
logrus.Info("[GCP] 🔑 using credentials from the worker configuration")
return gcp.NewFromFile(impl.GCPCreds)
} else {
logrus.Info("[GCP] 🔑 using Application Default Credentials via Google library")
return gcp.New(nil)
}
}
func validateResult(result *worker.OSBuildJobResult, jobID string) {
logWithId := logrus.WithField("jobId", jobID)
if result.JobError != nil {
@ -434,7 +465,7 @@ func (impl *OSBuildJobImpl) Run(job worker.Job) error {
case *target.GCPTargetOptions:
ctx := context.Background()
g, err := gcp.New(impl.GCPCreds)
g, err := impl.getGCP(nil)
if err != nil {
osbuildJobResult.JobError = clienterrors.WorkerClientError(clienterrors.ErrorInvalidConfig, err.Error())
return nil

View file

@ -287,16 +287,11 @@ func main() {
}
}
// Check if the credentials file was provided in the worker configuration,
// and load it early to prevent potential failure due to issues with the file.
// Note that the content validity of the provided file is not checked and
// can not be reasonable checked with GCP other than by making real API calls.
var gcpCredentials []byte
// If the credentials are not provided in the configuration, then the
// worker will rely on the GCP library to authenticate using default means.
var gcpCredentials string
if config.GCP != nil {
gcpCredentials, err = ioutil.ReadFile(config.GCP.Credentials)
if err != nil {
logrus.Fatalf("cannot load GCP credentials: %v", err)
}
gcpCredentials = config.GCP.Credentials
}
// If the credentials are not provided in the configuration, then the

View file

@ -55,6 +55,16 @@ func New(credentials []byte) (*GCP, error) {
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,