2018-08-16 19:18:06 +00:00
|
|
|
package azuresecrets
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"strings"
|
|
|
|
"sync"
|
|
|
|
|
2018-10-19 23:15:31 +00:00
|
|
|
"github.com/hashicorp/vault/helper/locksutil"
|
2018-08-16 19:18:06 +00:00
|
|
|
"github.com/hashicorp/vault/logical"
|
|
|
|
"github.com/hashicorp/vault/logical/framework"
|
|
|
|
)
|
|
|
|
|
|
|
|
type azureSecretBackend struct {
|
|
|
|
*framework.Backend
|
|
|
|
|
|
|
|
getProvider func(*clientSettings) (AzureProvider, error)
|
2018-12-14 15:42:11 +00:00
|
|
|
client *client
|
2018-08-16 19:18:06 +00:00
|
|
|
settings *clientSettings
|
|
|
|
lock sync.RWMutex
|
2018-10-19 23:15:31 +00:00
|
|
|
|
|
|
|
// Creating/deleting passwords against a single Application is a PATCH
|
|
|
|
// operation that must be locked per Application Object ID.
|
|
|
|
appLocks []*locksutil.LockEntry
|
2018-08-16 19:18:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) {
|
|
|
|
b := backend()
|
|
|
|
if err := b.Setup(ctx, conf); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return b, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func backend() *azureSecretBackend {
|
|
|
|
var b = azureSecretBackend{}
|
|
|
|
|
|
|
|
b.Backend = &framework.Backend{
|
|
|
|
Help: strings.TrimSpace(backendHelp),
|
|
|
|
PathsSpecial: &logical.Paths{
|
|
|
|
SealWrapStorage: []string{
|
|
|
|
"config",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Paths: framework.PathAppend(
|
|
|
|
pathsRole(&b),
|
|
|
|
[]*framework.Path{
|
|
|
|
pathConfig(&b),
|
|
|
|
pathServicePrincipal(&b),
|
|
|
|
},
|
|
|
|
),
|
|
|
|
Secrets: []*framework.Secret{
|
|
|
|
secretServicePrincipal(&b),
|
2018-10-19 23:15:31 +00:00
|
|
|
secretStaticServicePrincipal(&b),
|
2018-08-16 19:18:06 +00:00
|
|
|
},
|
|
|
|
BackendType: logical.TypeLogical,
|
|
|
|
Invalidate: b.invalidate,
|
|
|
|
}
|
|
|
|
|
|
|
|
b.getProvider = newAzureProvider
|
2018-10-19 23:15:31 +00:00
|
|
|
b.appLocks = locksutil.CreateLocks()
|
2018-08-16 19:18:06 +00:00
|
|
|
|
|
|
|
return &b
|
|
|
|
}
|
|
|
|
|
2018-12-14 15:42:11 +00:00
|
|
|
// reset clears the backend's cached client
|
|
|
|
// This is used when the configuration changes and a new client should be
|
2018-08-16 19:18:06 +00:00
|
|
|
// created with the updated settings.
|
|
|
|
func (b *azureSecretBackend) reset() {
|
|
|
|
b.lock.Lock()
|
|
|
|
defer b.lock.Unlock()
|
|
|
|
|
|
|
|
b.settings = nil
|
2018-12-14 15:42:11 +00:00
|
|
|
b.client = nil
|
2018-08-16 19:18:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (b *azureSecretBackend) invalidate(ctx context.Context, key string) {
|
|
|
|
switch key {
|
|
|
|
case "config":
|
|
|
|
b.reset()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const backendHelp = `
|
|
|
|
The Azure secrets backend dynamically generates Azure service
|
|
|
|
principals. The SP credentials have a configurable lease and
|
|
|
|
are automatically revoked at the end of the lease.
|
|
|
|
|
|
|
|
After mounting this backend, credentials to manage Azure resources
|
|
|
|
must be configured with the "config/" endpoints and policies must be
|
|
|
|
written using the "roles/" endpoints before any credentials can be
|
|
|
|
generated.
|
|
|
|
`
|