Skip to content
Open
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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@ dev:

# test runs the tests
test:
@go test -timeout=240s ./... $(TESTARGS)
@go test -timeout=300s ./... $(TESTARGS)
.PHONY: test
70 changes: 62 additions & 8 deletions backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ import (
"sync"
"time"

"github.com/hashicorp/errwrap"
"github.com/hashicorp/go-gcp-common/gcputil"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/helper/pluginutil"
"github.com/hashicorp/vault/sdk/helper/useragent"
"github.com/hashicorp/vault/sdk/logical"
"github.com/patrickmn/go-cache"
"golang.org/x/oauth2/google"
"golang.org/x/oauth2/google/externalaccount"
"google.golang.org/api/option"

kmsapi "cloud.google.com/go/kms/apiv1"
Expand Down Expand Up @@ -182,20 +185,32 @@ func (b *backend) KMSClient(s logical.Storage) (*kmsapi.KeyManagementClient, fun
return nil, nil, err
}

// If credentials were provided, use those. Otherwise fall back to the
// default application credentials.
// If credentials were provided or workload identiy, use those.
// Otherwise fall back to the default application credentials.
var creds *google.Credentials
if config.Credentials != "" {
creds, err = google.CredentialsFromJSON(b.ctx, []byte(config.Credentials), config.Scopes...)
if err != nil {
b.kmsClientLock.Unlock()
return nil, nil, errwrap.Wrapf("failed to parse credentials: {{err}}", err)
return nil, nil, fmt.Errorf("failed to parse credentials: %w", err)
}
} else if config.IdentityTokenAudience != "" {
ts := &PluginIdentityTokenSupplier{
sys: b.System(),
logger: b.Logger(),
audience: config.IdentityTokenAudience,
ttl: config.IdentityTokenTTL,
}

creds, err = b.GetExternalAccountConfig(config, ts).GetExternalAccountCredentials(b.ctx)
if err != nil {
return nil, nil, fmt.Errorf("failed to fetch external account credentials: %w", err)
}
} else {
creds, err = google.FindDefaultCredentials(b.ctx, config.Scopes...)
if err != nil {
b.kmsClientLock.Unlock()
return nil, nil, errwrap.Wrapf("failed to get default token source: {{err}}", err)
return nil, nil, fmt.Errorf("failed to get default token source: %w", err)
}
}

Expand All @@ -207,7 +222,7 @@ func (b *backend) KMSClient(s logical.Storage) (*kmsapi.KeyManagementClient, fun
)
if err != nil {
b.kmsClientLock.Unlock()
return nil, nil, errwrap.Wrapf("failed to create KMS client: {{err}}", err)
return nil, nil, fmt.Errorf("failed to create KMS client: %w", err)
}

// Cache the client
Expand All @@ -228,14 +243,53 @@ func (b *backend) Config(ctx context.Context, s logical.Storage) (*Config, error

entry, err := s.Get(ctx, "config")
if err != nil {
return nil, errwrap.Wrapf("failed to get configuration from storage: {{err}}", err)
return nil, fmt.Errorf("failed to get configuration from storage: %w", err)
}
if entry == nil || len(entry.Value) == 0 {
return c, nil
}

if err := entry.DecodeJSON(&c); err != nil {
return nil, errwrap.Wrapf("failed to decode configuration: {{err}}", err)
return nil, fmt.Errorf("failed to decode configuration: %w", err)
}
return c, nil
}

func (b *backend) GetExternalAccountConfig(c *Config, ts *PluginIdentityTokenSupplier) *gcputil.ExternalAccountConfig {
b.Logger().Debug("adding web identity token fetcher")
cfg := &gcputil.ExternalAccountConfig{
ServiceAccountEmail: c.ServiceAccountEmail,
Audience: c.IdentityTokenAudience,
TTL: c.IdentityTokenTTL,
TokenSupplier: ts,
}

return cfg
}

type PluginIdentityTokenSupplier struct {
sys logical.SystemView
logger hclog.Logger
audience string
ttl time.Duration
}

var _ externalaccount.SubjectTokenSupplier = (*PluginIdentityTokenSupplier)(nil)

func (p *PluginIdentityTokenSupplier) SubjectToken(ctx context.Context, opts externalaccount.SupplierOptions) (string, error) {
p.logger.Info("fetching new plugin identity token")
resp, err := p.sys.GenerateIdentityToken(ctx, &pluginutil.IdentityTokenRequest{
Audience: p.audience,
TTL: p.ttl,
})
if err != nil {
return "", fmt.Errorf("failed to generate plugin identity token: %w", err)
}

if resp.TTL < p.ttl {
p.logger.Debug("generated plugin identity token has shorter TTL than requested",
"requested", p.ttl.Seconds(), "actual", resp.TTL)
}

return resp.Token.Token(), nil
}
40 changes: 7 additions & 33 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@
package gcpkms

import (
"strings"

"github.com/hashicorp/go-secure-stdlib/strutil"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/helper/automatedrotationutil"
"github.com/hashicorp/vault/sdk/helper/pluginidentityutil"
)

const (
Expand All @@ -16,8 +14,11 @@ const (

// Config is the stored configuration.
type Config struct {
Credentials string `json:"credentials"`
Scopes []string `json:"scopes"`
Credentials string `json:"credentials"`
Scopes []string `json:"scopes"`
ServiceAccountEmail string `json:"service_account_email"`
pluginidentityutil.PluginIdentityTokenParams
automatedrotationutil.AutomatedRotationParams
}

// DefaultConfig returns a config with the default values.
Expand All @@ -26,30 +27,3 @@ func DefaultConfig() *Config {
Scopes: []string{defaultScope},
}
}

// Update updates the configuration from the given field data.
func (c *Config) Update(d *framework.FieldData) (bool, error) {
if d == nil {
return false, nil
}

changed := false

if v, ok := d.GetOk("credentials"); ok {
nv := strings.TrimSpace(v.(string))
if nv != c.Credentials {
c.Credentials = nv
changed = true
}
}

if v, ok := d.GetOk("scopes"); ok {
nv := strutil.RemoveDuplicates(v.([]string), true)
if !strutil.EquivalentSlices(nv, c.Scopes) {
c.Scopes = nv
changed = true
}
}

return changed, nil
}
155 changes: 0 additions & 155 deletions config_test.go

This file was deleted.

1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
github.com/gammazero/workerpool v1.1.3
github.com/golang/protobuf v1.5.4
github.com/hashicorp/errwrap v1.1.0
github.com/hashicorp/go-gcp-common v0.9.2
github.com/hashicorp/go-hclog v1.6.3
github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brv
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-gcp-common v0.9.2 h1:hUZ46EdGwlbP+Ttrif6hlcfvtQGzJiS6FUbb649yAOQ=
github.com/hashicorp/go-gcp-common v0.9.2/go.mod h1:STcRASKUYdCtaKbZinoAR/URmkIUGIOTOHUNPrF9xOE=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-hmac-drbg v0.0.0-20210916214228-a6e5a68489f6 h1:kBoJV4Xl5FLtBfnBjDvBxeNSy2IRITSGs73HQsFUEjY=
Expand Down
Loading