Update plugins

This commit is contained in:
Jeff Mitchell 2018-12-14 10:42:11 -05:00
parent b128fedea8
commit 18e014ee93
9 changed files with 193 additions and 51 deletions

View File

@ -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]

View File

@ -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
}

View File

@ -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) ||

View File

@ -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,

View File

@ -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) {

View File

@ -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
}

View File

@ -76,6 +76,7 @@ func Backend() *backend {
b.pathDecrypt(),
b.pathEncrypt(),
b.pathPubkey(),
b.pathReencrypt(),
b.pathSign(),
b.pathVerify(),

View File

@ -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
}

24
vendor/vendor.json vendored
View File

@ -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=",