github.com/myhau/pulumi/pkg/v3@v3.70.2-0.20221116134521-f2775972e587/authhelpers/gcpauth.go (about)

     1  package authhelpers
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"os"
     8  
     9  	"cloud.google.com/go/storage"
    10  	"golang.org/x/oauth2/google"
    11  
    12  	"gocloud.dev/blob/gcsblob"
    13  
    14  	"gocloud.dev/blob"
    15  	"gocloud.dev/gcp"
    16  )
    17  
    18  type GoogleCredentials struct {
    19  	PrivateKeyID string `json:"private_key_id"`
    20  	PrivateKey   string `json:"private_key"`
    21  	ClientEmail  string `json:"client_email"`
    22  	ClientID     string `json:"client_id"`
    23  }
    24  
    25  // ResolveGoogleCredentials loads the google credentials using the pulumi-specific
    26  // logic first, falling back to the DefaultCredentials resoulution after.
    27  func ResolveGoogleCredentials(ctx context.Context, scope string) (*google.Credentials, error) {
    28  	// GOOGLE_CREDENTIALS aren't part of the gcloud standard authorization variables
    29  	// but the GCP terraform provider uses this variable to allow users to authenticate
    30  	// with the contents of a credentials.json file instead of just a file path.
    31  	// https://www.terraform.io/docs/backends/types/gcs.html
    32  	if creds := os.Getenv("GOOGLE_CREDENTIALS"); creds != "" {
    33  		// We try $GOOGLE_CREDENTIALS before gcp.DefaultCredentials
    34  		// so that users can override the default creds
    35  		credentials, err := google.CredentialsFromJSON(ctx, []byte(creds), scope)
    36  		if err != nil {
    37  			return nil, fmt.Errorf("unable to parse credentials from $GOOGLE_CREDENTIALS: %w", err)
    38  		}
    39  		return credentials, nil
    40  	}
    41  
    42  	// DefaultCredentials will attempt to load creds in the following order:
    43  	// 1. a file located at $GOOGLE_APPLICATION_CREDENTIALS
    44  	// 2. application_default_credentials.json file in ~/.config/gcloud or $APPDATA\gcloud
    45  	credentials, err := gcp.DefaultCredentials(ctx)
    46  	if err != nil {
    47  		return nil, fmt.Errorf("unable to find gcp credentials: %w", err)
    48  	}
    49  	return credentials, nil
    50  }
    51  
    52  func GoogleCredentialsMux(ctx context.Context) (*blob.URLMux, error) {
    53  	credentials, err := ResolveGoogleCredentials(ctx, storage.ScopeReadWrite)
    54  	if err != nil {
    55  		return nil, fmt.Errorf("missing google credentials: %w", err)
    56  	}
    57  
    58  	client, err := gcp.NewHTTPClient(gcp.DefaultTransport(), credentials.TokenSource)
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  
    63  	options := gcsblob.Options{}
    64  	account := GoogleCredentials{}
    65  	err = json.Unmarshal(credentials.JSON, &account)
    66  	if err == nil && account.ClientEmail != "" && account.PrivateKey != "" {
    67  		options.GoogleAccessID = account.ClientEmail
    68  		options.PrivateKey = []byte(account.PrivateKey)
    69  	}
    70  
    71  	blobmux := &blob.URLMux{}
    72  	blobmux.RegisterBucket(gcsblob.Scheme, &gcsblob.URLOpener{
    73  		Client:  client,
    74  		Options: options,
    75  	})
    76  
    77  	return blobmux, nil
    78  }