Skip to content

Commit

Permalink
storageccl: support per-statement credentials param for GCS
Browse files Browse the repository at this point in the history
Previously, the options for GCS authentication for bulk IO were:

* set the value of `cloudstorage.gs.default.key` (`auth=default`)
* use the GCP SDK's implicit auth (`auth=implicit`)

This change adds the option `auth=specified`, allowing the JSON key object to
be sent in the new `credentials` query param, allowing for authentication on a
per-statement basis.

Fixes #31602

Release note (enterprise change): Adds the option to supply Google Cloud
Storage credentials on a per-statement basis with the query parameter
`credentials`.
  • Loading branch information
lucy-zhang committed Nov 21, 2018
1 parent d67ac45 commit 844cb6b
Show file tree
Hide file tree
Showing 4 changed files with 479 additions and 388 deletions.
32 changes: 29 additions & 3 deletions pkg/ccl/storageccl/export_storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"context"
"crypto/tls"
"crypto/x509"
"encoding/base64"
"fmt"
"hash/fnv"
"io"
Expand Down Expand Up @@ -66,9 +67,14 @@ const (

// AuthParam is the query parameter for the cluster settings named
// key in a URI.
AuthParam = "AUTH"
authParamImplicit = "implicit"
authParamDefault = "default"
AuthParam = "AUTH"
authParamImplicit = "implicit"
authParamDefault = "default"
authParamSpecified = "specified"

// CredentialsParam is the query parameter for the base64-encoded contents of
// the Google Application Credentials JSON file.
CredentialsParam = "CREDENTIALS"

cloudstoragePrefix = "cloudstorage"
cloudstorageGS = cloudstoragePrefix + ".gs"
Expand Down Expand Up @@ -125,6 +131,7 @@ func ExportStorageConfFromURI(path string) (roachpb.ExportStorage, error) {
Prefix: uri.Path,
Auth: uri.Query().Get(AuthParam),
BillingProject: uri.Query().Get(GoogleBillingProjectParam),
Credentials: uri.Query().Get(CredentialsParam),
}
conf.GoogleCloudConfig.Prefix = strings.TrimLeft(conf.GoogleCloudConfig.Prefix, "/")
case "azure":
Expand Down Expand Up @@ -667,6 +674,7 @@ func makeGCSStorage(
opts := []option.ClientOption{option.WithScopes(scope)}

// "default": only use the key in the settings; error if not present.
// "specified": the JSON object for authentication is given by the CREDENTIALS param.
// "implicit": only use the environment data.
// "": if default key is in the settings use it; otherwise use environment data.
switch conf.Auth {
Expand All @@ -686,6 +694,24 @@ func makeGCSStorage(
}
opts = append(opts, option.WithTokenSource(source.TokenSource(ctx)))
}
case authParamSpecified:
if conf.Credentials == "" {
return nil, errors.Errorf(
"%s is set to '%s', but %s is not set",
AuthParam,
authParamSpecified,
CredentialsParam,
)
}
decodedKey, err := base64.StdEncoding.DecodeString(conf.Credentials)
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("decoding value of %s", CredentialsParam))
}
source, err := google.JWTConfigFromJSON(decodedKey, scope)
if err != nil {
return nil, errors.Wrap(err, "creating GCS oauth token source from specified credentials")
}
opts = append(opts, option.WithTokenSource(source.TokenSource(ctx)))
case authParamImplicit:
// Do nothing; use implicit params:
// https://godoc.org/golang.org/x/oauth2/google#FindDefaultCredentials
Expand Down
19 changes: 19 additions & 0 deletions pkg/ccl/storageccl/export_storage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"bytes"
"context"
"crypto/rand"
"encoding/base64"
"encoding/pem"
"fmt"
"io"
Expand Down Expand Up @@ -458,6 +459,24 @@ func TestPutGoogleCloud(t *testing.T) {
t.Run("default", func(t *testing.T) {
testExportStore(t, fmt.Sprintf("gs://%s/%s?%s=%s", bucket, "backup-test-default", AuthParam, authParamDefault), false)
})
t.Run("specified", func(t *testing.T) {
credentials := os.Getenv("GS_JSONKEY")
if credentials == "" {
t.Skip("GS_JSONKEY env var must be set")
}
encoded := base64.StdEncoding.EncodeToString([]byte(credentials))
testExportStore(t,
fmt.Sprintf("gs://%s/%s?%s=%s&%s=%s",
bucket,
"backup-test-specified",
AuthParam,
authParamSpecified,
CredentialsParam,
url.QueryEscape(encoded),
),
false,
)
})
t.Run("implicit", func(t *testing.T) {
// Only test these if they exist.
if _, err := google.FindDefaultCredentials(context.TODO()); err != nil {
Expand Down
Loading

0 comments on commit 844cb6b

Please sign in to comment.