Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions plugin/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
"sync"
"time"

gauth "cloud.google.com/go/auth/credentials"
"cloud.google.com/go/auth/oauth2adapt"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/go-cleanhttp"
"github.com/hashicorp/go-gcp-common/gcputil"
Expand Down Expand Up @@ -142,8 +144,18 @@ func (b *backend) IAMAdminClient(s logical.Storage) (*iam.Service, error) {
return nil, errwrap.Wrapf("failed to create IAM HTTP client: {{err}}", err)
}

ctx := context.Background()

cfg, err := getConfig(ctx, s)
if err != nil {
return nil, err
}
if cfg == nil {
cfg = &config{}
}

client, err := b.cache.Fetch("iam", cacheTime, func() (interface{}, error) {
client, err := iam.NewService(context.Background(), option.WithHTTPClient(httpClient))
client, err := iam.NewService(context.Background(), option.WithHTTPClient(httpClient), option.WithUniverseDomain(cfg.UniverseDomain))
if err != nil {
return nil, errwrap.Wrapf("failed to create IAM client: {{err}}", err)
}
Expand Down Expand Up @@ -203,10 +215,16 @@ func (b *backend) credentials(s logical.Storage) (*google.Credentials, error) {
// default application credentials.
var creds *google.Credentials
if len(credBytes) > 0 {
creds, err = google.CredentialsFromJSON(ctx, credBytes, iam.CloudPlatformScope)
scopes := []string{"openid", "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/cloud-platform", "https://www.googleapis.com/auth/appengine.admin", "https://www.googleapis.com/auth/sqlservice.login", "https://www.googleapis.com/auth/compute"}
gcred, err := gauth.DetectDefault(&gauth.DetectOptions{
Scopes: scopes,
CredentialsJSON: credBytes,
UseSelfSignedJWT: true,
UniverseDomain: cfg.UniverseDomain})
if err != nil {
return nil, errwrap.Wrapf("failed to parse credentials: {{err}}", err)
}
creds = oauth2adapt.Oauth2CredentialsFromAuthCredentials(gcred)
} else if cfg.IdentityTokenAudience != "" {
ts := &PluginIdentityTokenSupplier{
sys: b.System(),
Expand Down
17 changes: 17 additions & 0 deletions plugin/path_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import (
"github.com/hashicorp/vault/sdk/rotation"
)

const DefaultUniverseDomain = "googleapis.com"

func pathConfig(b *backend) *framework.Path {
p := &framework.Path{
Pattern: "config",
Expand All @@ -43,6 +45,12 @@ func pathConfig(b *backend) *framework.Path {
Type: framework.TypeString,
Description: `Email ID for the Service Account to impersonate for Workload Identity Federation.`,
},
"universe_domain": {
Type: framework.TypeString,
Required: false,
Default: "googleapis.com",
Description: `universe_domain specifies the Google Cloud environment a client connects to, enabling specialized offerings and sovereign controls beyond the default googleapis.com`,
},
},

Operations: map[logical.Operation]framework.OperationHandler{
Expand Down Expand Up @@ -86,6 +94,7 @@ func (b *backend) pathConfigRead(ctx context.Context, req *logical.Request, data
"ttl": int64(cfg.TTL / time.Second),
"max_ttl": int64(cfg.MaxTTL / time.Second),
"service_account_email": cfg.ServiceAccountEmail,
"universe_domain": cfg.UniverseDomain,
}

cfg.PopulatePluginIdentityTokenData(configData)
Expand Down Expand Up @@ -200,6 +209,13 @@ func (b *backend) pathConfigWrite(ctx context.Context, req *logical.Request, dat
return logical.ErrorResponse("error registering rotation job: %s", err), nil
}
}
// Update Universe-Domain.
UniverseDomainRaw, ok := data.GetOk("universe_domain")
if ok {
cfg.UniverseDomain = UniverseDomainRaw.(string)
} else {
cfg.UniverseDomain = DefaultUniverseDomain
}

entry, err := logical.StorageEntryJSON("config", cfg)
if err != nil {
Expand Down Expand Up @@ -234,6 +250,7 @@ type config struct {
ServiceAccountEmail string
pluginidentityutil.PluginIdentityTokenParams
automatedrotationutil.AutomatedRotationParams
UniverseDomain string
}

func getConfig(ctx context.Context, s logical.Storage) (*config, error) {
Expand Down
1 change: 1 addition & 0 deletions plugin/path_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ func TestConfig(t *testing.T) {
"rotation_period": float64(0),
"rotation_schedule": "",
"disable_automated_rotation": false,
"universe_domain": "googleapis.com",
}

testConfigRead(t, b, reqStorage, expected)
Expand Down
12 changes: 9 additions & 3 deletions plugin/secrets_access_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ import (
"encoding/base64"
"time"

gauth "cloud.google.com/go/auth/credentials"
"cloud.google.com/go/auth/oauth2adapt"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/logical"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
)

func (b *backend) secretAccessTokenResponse(ctx context.Context, s logical.Storage, tokenGen *TokenGenerator) (*logical.Response, error) {
Expand Down Expand Up @@ -40,12 +41,17 @@ func (tg *TokenGenerator) getAccessToken(ctx context.Context) (*oauth2.Token, er
return nil, errwrap.Wrapf("could not b64-decode key data: {{err}}", err)
}

cfg, err := google.JWTConfigFromJSON(jsonBytes, tg.Scopes...)
gcred, err := gauth.DetectDefault(&gauth.DetectOptions{
Scopes: tg.Scopes,
CredentialsJSON: jsonBytes,
UseSelfSignedJWT: true,
})
if err != nil {
return nil, errwrap.Wrapf("could not generate token JWT config: {{err}}", err)
}
cfg := oauth2adapt.Oauth2CredentialsFromAuthCredentials(gcred)

tkn, err := cfg.TokenSource(ctx).Token()
tkn, err := cfg.TokenSource.Token()
if err != nil {
return nil, errwrap.Wrapf("got error while creating OAuth2 token: {{err}}", err)
}
Expand Down