diff --git a/CHANGELOG.md b/CHANGELOG.md index b88a895466..03c4a772a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,13 +28,17 @@ IMPROVEMENTS: BUG FIXES: + * auth/azure: Cache azure authorizer [15] + * auth/gcp: Remove explicit project for service account in GCE authorizer [58] * cli: Show correct stored keys/threshold for autoseals [GH-5910] * cli: Fix backwards compatibility fallback when listing plugins [GH-5913] * core: Fix upgrades when the seal config had been created on early versions of vault [GH-5956] * namespaces: Correctly reload the proper mount when tuning or reloading the mount [GH-5937] + * secret/azure: Cache azure authorizer [19] * secret/database: Strip empty statements on user input [GH-5955] + * secret/gcpkms: Add path for retrieving the public key [5] * secret/pki: Fix panic that could occur during tidy operation when malformed data was found [GH-5931] * secret/pki: Strip empty line in ca_chain output [GH-5779] diff --git a/vendor/github.com/hashicorp/vault-plugin-auth-azure/azure.go b/vendor/github.com/hashicorp/vault-plugin-auth-azure/azure.go index 179576537b..e1cdea328d 100644 --- a/vendor/github.com/hashicorp/vault-plugin-auth-azure/azure.go +++ b/vendor/github.com/hashicorp/vault-plugin-auth-azure/azure.go @@ -8,6 +8,7 @@ import ( "io/ioutil" "net/http" "os" + "sync" "time" "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2017-12-01/compute" @@ -20,6 +21,8 @@ import ( "golang.org/x/oauth2" ) +var authorizerLifetime = 30 * time.Minute + type computeClient interface { Get(ctx context.Context, resourceGroup, vmName string, instanceView compute.InstanceViewTypes) (compute.VirtualMachine, error) } @@ -39,9 +42,12 @@ type provider interface { } type azureProvider struct { - oidcVerifier *oidc.IDTokenVerifier - settings *azureSettings - httpClient *http.Client + oidcVerifier *oidc.IDTokenVerifier + settings *azureSettings + httpClient *http.Client + authorizer autorest.Authorizer + authorizerExpiration time.Time + lock sync.RWMutex } type oidcDiscoveryInfo struct { @@ -136,6 +142,23 @@ func (p *azureProvider) VMSSClient(subscriptionID string) (vmssClient, error) { } func (p *azureProvider) getAuthorizer() (autorest.Authorizer, error) { + p.lock.RLock() + unlockFunc := p.lock.RUnlock + defer func() { unlockFunc() }() + + if p.authorizer != nil && time.Now().Before(p.authorizerExpiration) { + return p.authorizer, nil + } + + // Upgrade lock + p.lock.RUnlock() + p.lock.Lock() + unlockFunc = p.lock.Unlock + + if p.authorizer != nil && time.Now().Before(p.authorizerExpiration) { + return p.authorizer, nil + } + // Create an OAuth2 client for retrieving VM data var authorizer autorest.Authorizer var err error @@ -158,6 +181,8 @@ func (p *azureProvider) getAuthorizer() (autorest.Authorizer, error) { return nil, err } } + p.authorizer = authorizer + p.authorizerExpiration = time.Now().Add(authorizerLifetime) return authorizer, nil } diff --git a/vendor/github.com/hashicorp/vault-plugin-auth-gcp/plugin/authorizer_gce.go b/vendor/github.com/hashicorp/vault-plugin-auth-gcp/plugin/authorizer_gce.go index d9346a9bbb..c0ce98de55 100644 --- a/vendor/github.com/hashicorp/vault-plugin-auth-gcp/plugin/authorizer_gce.go +++ b/vendor/github.com/hashicorp/vault-plugin-auth-gcp/plugin/authorizer_gce.go @@ -5,6 +5,7 @@ import ( "fmt" "strings" + "github.com/hashicorp/errwrap" "github.com/hashicorp/vault/helper/strutil" ) @@ -140,12 +141,11 @@ func AuthorizeGCE(ctx context.Context, i *AuthorizeGCEInput) error { // Verify instance is running under one of the allowed service accounts. if len(i.boundServiceAccounts) > 0 { // ServiceAccount wraps a call to the GCP IAM API to get a service account. - name := fmt.Sprintf("projects/%s/serviceAccounts/%s", i.project, i.serviceAccount) + name := fmt.Sprintf("projects/-/serviceAccounts/%s", i.serviceAccount) saId, saEmail, err := i.client.ServiceAccount(ctx, name) if err != nil { - return fmt.Errorf("could not find service account %q in project %q: %s", - i.serviceAccount, i.project, err) + return errwrap.Wrapf(fmt.Sprintf("could not find service account %q: {{err}}", i.serviceAccount), err) } if !(strutil.StrListContains(i.boundServiceAccounts, saEmail) || diff --git a/vendor/github.com/hashicorp/vault-plugin-auth-gcp/plugin/path_login.go b/vendor/github.com/hashicorp/vault-plugin-auth-gcp/plugin/path_login.go index 0ec624782a..39adbc7f51 100644 --- a/vendor/github.com/hashicorp/vault-plugin-auth-gcp/plugin/path_login.go +++ b/vendor/github.com/hashicorp/vault-plugin-auth-gcp/plugin/path_login.go @@ -442,7 +442,7 @@ func (b *GcpAuthBackend) pathGceLogin(ctx context.Context, req *logical.Request, metadata.ProjectId, metadata.Zone, metadata.InstanceName, err)), nil } - if err := b.authorizeGCEInstance(ctx, instance, req.Storage, role, loginInfo.EmailOrId); err != nil { + if err := b.authorizeGCEInstance(ctx, metadata.ProjectId, instance, req.Storage, role, loginInfo.EmailOrId); err != nil { return logical.ErrorResponse(err.Error()), nil } @@ -575,7 +575,7 @@ func (b *GcpAuthBackend) pathGceRenew(ctx context.Context, req *logical.Request, if !ok { return errors.New("invalid auth metadata: service_account_id not found") } - if err := b.authorizeGCEInstance(ctx, instance, req.Storage, role, serviceAccountId); err != nil { + if err := b.authorizeGCEInstance(ctx, meta.ProjectId, instance, req.Storage, role, serviceAccountId); err != nil { return fmt.Errorf("could not renew token for role %s: %v", roleName, err) } @@ -631,7 +631,7 @@ func getInstanceMetadataFromAuth(authMetadata map[string]string) (*gcputil.GCEId // authorizeGCEInstance returns an error if the given GCE instance is not // authorized for the role. -func (b *GcpAuthBackend) authorizeGCEInstance(ctx context.Context, instance *compute.Instance, s logical.Storage, role *gcpRole, serviceAccountId string) error { +func (b *GcpAuthBackend) authorizeGCEInstance(ctx context.Context, project string, instance *compute.Instance, s logical.Storage, role *gcpRole, serviceAccountId string) error { httpC, err := b.httpClient(ctx, s) if err != nil { return err @@ -652,8 +652,8 @@ func (b *GcpAuthBackend) authorizeGCEInstance(ctx context.Context, instance *com computeSvc: gceClient, iamSvc: iamClient, }, - serviceAccount: serviceAccountId, - + serviceAccount: serviceAccountId, + project: project, instanceLabels: instance.Labels, instanceSelfLink: instance.SelfLink, instanceZone: instance.Zone, diff --git a/vendor/github.com/hashicorp/vault-plugin-secrets-azure/backend.go b/vendor/github.com/hashicorp/vault-plugin-secrets-azure/backend.go index 1e451fad0f..8afadb3c12 100644 --- a/vendor/github.com/hashicorp/vault-plugin-secrets-azure/backend.go +++ b/vendor/github.com/hashicorp/vault-plugin-secrets-azure/backend.go @@ -14,6 +14,7 @@ type azureSecretBackend struct { *framework.Backend getProvider func(*clientSettings) (AzureProvider, error) + client *client settings *clientSettings lock sync.RWMutex @@ -61,14 +62,15 @@ func backend() *azureSecretBackend { return &b } -// reset clears the backend's Provider -// This is useful when the configuration changes and a new Provider should be +// reset clears the backend's cached client +// This is used when the configuration changes and a new client should be // created with the updated settings. func (b *azureSecretBackend) reset() { b.lock.Lock() defer b.lock.Unlock() b.settings = nil + b.client = nil } func (b *azureSecretBackend) invalidate(ctx context.Context, key string) { diff --git a/vendor/github.com/hashicorp/vault-plugin-secrets-azure/client.go b/vendor/github.com/hashicorp/vault-plugin-secrets-azure/client.go index f1e0f50cca..2ef161c71c 100644 --- a/vendor/github.com/hashicorp/vault-plugin-secrets-azure/client.go +++ b/vendor/github.com/hashicorp/vault-plugin-secrets-azure/client.go @@ -21,16 +21,23 @@ import ( ) const ( - appNamePrefix = "vault-" - retryTimeout = 80 * time.Second + appNamePrefix = "vault-" + retryTimeout = 80 * time.Second + clientLifetime = 30 * time.Minute ) // client offers higher level Azure operations that provide a simpler interface // for handlers. It in turn relies on a Provider interface to access the lower level // Azure Client SDK methods. type client struct { - provider AzureProvider - settings *clientSettings + provider AzureProvider + settings *clientSettings + expiration time.Time +} + +// Valid returns whether the client defined and not expired. +func (c *client) Valid() bool { + return c != nil && time.Now().Before(c.expiration) } func (b *azureSecretBackend) getClient(ctx context.Context, s logical.Storage) (*client, error) { @@ -38,28 +45,32 @@ func (b *azureSecretBackend) getClient(ctx context.Context, s logical.Storage) ( unlockFunc := b.lock.RUnlock defer func() { unlockFunc() }() + if b.client.Valid() { + return b.client, nil + } + + b.lock.RUnlock() + b.lock.Lock() + unlockFunc = b.lock.Unlock + + if b.client.Valid() { + return b.client, nil + } + if b.settings == nil { - // Upgrade lock - b.lock.RUnlock() - b.lock.Lock() - unlockFunc = b.lock.Unlock - - if b.settings == nil { - // Create a new client from the stored or empty config - config, err := b.getConfig(ctx, s) - if err != nil { - return nil, err - } - if config == nil { - config = new(azureConfig) - } - - settings, err := b.getClientSettings(ctx, config) - if err != nil { - return nil, err - } - b.settings = settings + config, err := b.getConfig(ctx, s) + if err != nil { + return nil, err } + if config == nil { + config = new(azureConfig) + } + + settings, err := b.getClientSettings(ctx, config) + if err != nil { + return nil, err + } + b.settings = settings } p, err := b.getProvider(b.settings) @@ -68,9 +79,11 @@ func (b *azureSecretBackend) getClient(ctx context.Context, s logical.Storage) ( } c := &client{ - provider: p, - settings: b.settings, + provider: p, + settings: b.settings, + expiration: time.Now().Add(clientLifetime), } + b.client = c return c, nil } diff --git a/vendor/github.com/hashicorp/vault-plugin-secrets-gcpkms/backend.go b/vendor/github.com/hashicorp/vault-plugin-secrets-gcpkms/backend.go index 75cd9b968e..c10ee9cc49 100644 --- a/vendor/github.com/hashicorp/vault-plugin-secrets-gcpkms/backend.go +++ b/vendor/github.com/hashicorp/vault-plugin-secrets-gcpkms/backend.go @@ -76,6 +76,7 @@ func Backend() *backend { b.pathDecrypt(), b.pathEncrypt(), + b.pathPubkey(), b.pathReencrypt(), b.pathSign(), b.pathVerify(), diff --git a/vendor/github.com/hashicorp/vault-plugin-secrets-gcpkms/path_pubkey.go b/vendor/github.com/hashicorp/vault-plugin-secrets-gcpkms/path_pubkey.go new file mode 100644 index 0000000000..37a5bee956 --- /dev/null +++ b/vendor/github.com/hashicorp/vault-plugin-secrets-gcpkms/path_pubkey.go @@ -0,0 +1,97 @@ +package gcpkms + +import ( + "context" + "fmt" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" + + kmspb "google.golang.org/genproto/googleapis/cloud/kms/v1" +) + +func (b *backend) pathPubkey() *framework.Path { + return &framework.Path{ + Pattern: "pubkey/" + framework.GenericNameRegex("key"), + + HelpSynopsis: "Retrieve the public key associated with the named key", + HelpDescription: ` +Retrieve the PEM-encoded Google Cloud KMS public key associated with the Vault +named key. The key will only be available if the key is asymmetric. +`, + + Fields: map[string]*framework.FieldSchema{ + "key": &framework.FieldSchema{ + Type: framework.TypeString, + Description: ` +Name of the key for which to get the public key. This key must already exist in +Vault and Google Cloud KMS. +`, + }, + + "key_version": &framework.FieldSchema{ + Type: framework.TypeInt, + Description: ` +Integer version of the crypto key version from which to exact the public key. +This field is required. +`, + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: withFieldValidator(b.pathPubkeyRead), + }, + } +} + +// pathPubkeyRead corresponds to GET gcpkms/pubkey/:key and is used to read the +// public key contents of the crypto key version. +func (b *backend) pathPubkeyRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + key := d.Get("key").(string) + keyVersion := d.Get("key_version").(int) + + if keyVersion == 0 { + return nil, errMissingFields("key_version") + } + + k, err := b.Key(ctx, req.Storage, key) + if err != nil { + if err == ErrKeyNotFound { + return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest + } + return nil, err + } + + if k.MinVersion > 0 && keyVersion < k.MinVersion { + resp := fmt.Sprintf("requested version %d is less than minimum allowed version of %d", + keyVersion, k.MinVersion) + return logical.ErrorResponse(resp), logical.ErrPermissionDenied + } + + if k.MaxVersion > 0 && keyVersion > k.MaxVersion { + resp := fmt.Sprintf("requested version %d is greater than maximum allowed version of %d", + keyVersion, k.MaxVersion) + return logical.ErrorResponse(resp), logical.ErrPermissionDenied + } + + kmsClient, closer, err := b.KMSClient(req.Storage) + if err != nil { + return nil, err + } + defer closer() + + pk, err := kmsClient.GetPublicKey(ctx, &kmspb.GetPublicKeyRequest{ + Name: fmt.Sprintf("%s/cryptoKeyVersions/%d", k.CryptoKeyID, keyVersion), + }) + if err != nil { + return nil, errwrap.Wrapf("failed to get public key: {{err}}", err) + } + + return &logical.Response{ + Data: map[string]interface{}{ + "pem": pk.Pem, + "algorithm": algorithmToString(pk.Algorithm), + }, + }, nil +} diff --git a/vendor/vendor.json b/vendor/vendor.json index b20e1b3645..40045db3df 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -1413,10 +1413,10 @@ "revisionTime": "2018-11-09T18:06:36Z" }, { - "checksumSHA1": "ojr0r/jmutGEhftDXiHthCCwpIA=", + "checksumSHA1": "Jj3mz58lSv0dsuXd6bVxGV4759w=", "path": "github.com/hashicorp/vault-plugin-auth-azure", - "revision": "d75e09c45e50144d92d5fa0d711996b4ac98c1e4", - "revisionTime": "2018-08-16T20:10:44Z" + "revision": "4c0b46069a2293d5a6ca7506c8d3e0c4a92f3dbc", + "revisionTime": "2018-12-07T23:25:28Z" }, { "checksumSHA1": "4Z/niOo76EcP8KpLdSL5GdDcy78=", @@ -1425,10 +1425,10 @@ "revisionTime": "2018-08-16T20:11:31Z" }, { - "checksumSHA1": "h7m+nCb1vdvcy5cUkCarix08yJI=", + "checksumSHA1": "llLHR3FVdqtuFgjIoL9GNN8zKKI=", "path": "github.com/hashicorp/vault-plugin-auth-gcp/plugin", - "revision": "0a3edf071747fcb84aa4f9d08a34d2c249e6228d", - "revisionTime": "2018-11-15T01:46:55Z" + "revision": "4d63bbfe6fcf0363a2ea2c273846e88b95d85089", + "revisionTime": "2018-12-10T20:01:33Z" }, { "checksumSHA1": "tt3FtyjXgdBI9Mb43UL4LtOZmAk=", @@ -1473,10 +1473,10 @@ "revisionTime": "2018-11-09T18:14:53Z" }, { - "checksumSHA1": "Zr5xVeEJxmlBLWgaUq5rRRIuryE=", + "checksumSHA1": "rgeBhrdLyF2orH3QA/H66ZSSbuo=", "path": "github.com/hashicorp/vault-plugin-secrets-azure", - "revision": "26e517ba4190bab20ebb28336921434f96093250", - "revisionTime": "2018-11-08T17:16:20Z" + "revision": "0087bdef705a9db855528525a6ede4d768a2639c", + "revisionTime": "2018-12-07T23:25:00Z" }, { "checksumSHA1": "tFP1EEyVlomSSx46NHDZWGPzUz0=", @@ -1497,10 +1497,10 @@ "revisionTime": "2018-09-21T17:32:00Z" }, { - "checksumSHA1": "mZTWeo/P2ZKbLHOjEqFUumNyEOo=", + "checksumSHA1": "TbPoZQkYZ7Bukdw6U+/GejbaZAs=", "path": "github.com/hashicorp/vault-plugin-secrets-gcpkms", - "revision": "a7d4151e40a5c1649d41440cadd1fe654df7e61c", - "revisionTime": "2018-10-19T21:34:31Z" + "revision": "6cd991800a6d7af69b1950ec4cbf402d021a099d", + "revisionTime": "2018-12-12T18:25:53Z" }, { "checksumSHA1": "0Uh543eKwac5M7mSsijM0GNekto=",