Don't use leases on the generic backend...with a caveat.
You can now turn on and off the lease behavior in the generic backend by using one of two factories. Core uses the normal one if it's not already set, so unit tests can use the custom one and all stay working. This also adds logic into core to check, when the response is coming from a generic backend, whether that backend has leases enabled. This adds some slight overhead.
This commit is contained in:
parent
a5f52f43b1
commit
47e8c0070a
|
@ -350,7 +350,10 @@ func NewCore(conf *CoreConfig) (*Core, error) {
|
|||
for k, f := range conf.LogicalBackends {
|
||||
logicalBackends[k] = f
|
||||
}
|
||||
logicalBackends["generic"] = PassthroughBackendFactory
|
||||
_, ok := logicalBackends["generic"]
|
||||
if !ok {
|
||||
logicalBackends["generic"] = PassthroughBackendFactory
|
||||
}
|
||||
logicalBackends["cubbyhole"] = CubbyholeBackendFactory
|
||||
logicalBackends["system"] = func(config *logical.BackendConfig) (logical.Backend, error) {
|
||||
return NewSystemBackend(c, config), nil
|
||||
|
@ -503,15 +506,36 @@ func (c *Core) handleRequest(req *logical.Request) (retResp *logical.Response, r
|
|||
resp.Secret.TTL = maxTTL
|
||||
}
|
||||
|
||||
// Register the lease
|
||||
leaseID, err := c.expiration.Register(req, resp)
|
||||
if err != nil {
|
||||
c.logger.Printf(
|
||||
"[ERR] core: failed to register lease "+
|
||||
"(request: %#v, response: %#v): %v", req, resp, err)
|
||||
mountEntry := c.router.MatchingMountEntry(req.Path)
|
||||
if mountEntry == nil {
|
||||
c.logger.Println("[ERR] core: unable to retrieve generic mount entry from router")
|
||||
return nil, auth, ErrInternalError
|
||||
}
|
||||
resp.Secret.LeaseID = leaseID
|
||||
|
||||
// Generic mounts should return the TTL but not register
|
||||
// for a lease as this provides a massive slowdown
|
||||
registerLease := true
|
||||
if mountEntry.Type == "generic" {
|
||||
backend := c.router.MatchingBackend(req.Path)
|
||||
if backend == nil {
|
||||
c.logger.Println("[ERR] core: unable to retrieve generic backend from router")
|
||||
return nil, auth, ErrInternalError
|
||||
}
|
||||
if !backend.(*PassthroughBackend).GeneratesLeases() {
|
||||
registerLease = false
|
||||
resp.Secret.Renewable = false
|
||||
}
|
||||
}
|
||||
if registerLease {
|
||||
leaseID, err := c.expiration.Register(req, resp)
|
||||
if err != nil {
|
||||
c.logger.Printf(
|
||||
"[ERR] core: failed to register lease "+
|
||||
"(request: %#v, response: %#v): %v", req, resp, err)
|
||||
return nil, auth, ErrInternalError
|
||||
}
|
||||
resp.Secret.LeaseID = leaseID
|
||||
}
|
||||
}
|
||||
|
||||
// Only the token store is allowed to return an auth block, for any
|
||||
|
|
|
@ -43,6 +43,9 @@ func TestCore_Init(t *testing.T) {
|
|||
conf := &CoreConfig{
|
||||
Physical: inm,
|
||||
DisableMlock: true,
|
||||
LogicalBackends: map[string]logical.Factory{
|
||||
"generic": LeasedPassthroughBackendFactory,
|
||||
},
|
||||
}
|
||||
c, err := NewCore(conf)
|
||||
if err != nil {
|
||||
|
|
|
@ -10,9 +10,23 @@ import (
|
|||
"github.com/hashicorp/vault/logical/framework"
|
||||
)
|
||||
|
||||
// logical.Factory
|
||||
// PassthroughBackendFactory returns a PassthroughBackend
|
||||
// with leases switched off
|
||||
func PassthroughBackendFactory(conf *logical.BackendConfig) (logical.Backend, error) {
|
||||
return LeaseSwitchedPassthroughBackend(conf, false)
|
||||
}
|
||||
|
||||
// PassthroughBackendWithLeasesFactory returns a PassthroughBackend
|
||||
// with leases switched on
|
||||
func LeasedPassthroughBackendFactory(conf *logical.BackendConfig) (logical.Backend, error) {
|
||||
return LeaseSwitchedPassthroughBackend(conf, true)
|
||||
}
|
||||
|
||||
// LeaseSwitchedPassthroughBackendFactory returns a PassthroughBackend
|
||||
// with leases switched on or off
|
||||
func LeaseSwitchedPassthroughBackend(conf *logical.BackendConfig, leases bool) (logical.Backend, error) {
|
||||
var b PassthroughBackend
|
||||
b.generateLeases = leases
|
||||
b.Backend = &framework.Backend{
|
||||
Help: strings.TrimSpace(passthroughHelp),
|
||||
|
||||
|
@ -42,15 +56,17 @@ func PassthroughBackendFactory(conf *logical.BackendConfig) (logical.Backend, er
|
|||
HelpDescription: strings.TrimSpace(passthroughHelpDescription),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
Secrets: []*framework.Secret{
|
||||
if b.generateLeases {
|
||||
b.Backend.Secrets = []*framework.Secret{
|
||||
&framework.Secret{
|
||||
Type: "generic",
|
||||
|
||||
Renew: b.handleRead,
|
||||
Revoke: b.handleRevoke,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if conf == nil {
|
||||
|
@ -58,7 +74,7 @@ func PassthroughBackendFactory(conf *logical.BackendConfig) (logical.Backend, er
|
|||
}
|
||||
b.Backend.Setup(conf)
|
||||
|
||||
return b, nil
|
||||
return &b, nil
|
||||
}
|
||||
|
||||
// PassthroughBackend is used storing secrets directly into the physical
|
||||
|
@ -67,6 +83,7 @@ func PassthroughBackendFactory(conf *logical.BackendConfig) (logical.Backend, er
|
|||
// fancy.
|
||||
type PassthroughBackend struct {
|
||||
*framework.Backend
|
||||
generateLeases bool
|
||||
}
|
||||
|
||||
func (b *PassthroughBackend) handleRevoke(
|
||||
|
@ -94,9 +111,17 @@ func (b *PassthroughBackend) handleRead(
|
|||
return nil, fmt.Errorf("json decoding failed: %v", err)
|
||||
}
|
||||
|
||||
// Generate the response
|
||||
resp := b.Secret("generic").Response(rawData, nil)
|
||||
resp.Secret.Renewable = false
|
||||
var resp *logical.Response
|
||||
if b.generateLeases {
|
||||
// Generate the response
|
||||
resp = b.Secret("generic").Response(rawData, nil)
|
||||
resp.Secret.Renewable = false
|
||||
} else {
|
||||
resp = &logical.Response{
|
||||
Secret: &logical.Secret{},
|
||||
Data: rawData,
|
||||
}
|
||||
}
|
||||
|
||||
// Check if there is a ttl key
|
||||
var ttl string
|
||||
|
@ -105,14 +130,21 @@ func (b *PassthroughBackend) handleRead(
|
|||
ttl, _ = rawData["ttl"].(string)
|
||||
}
|
||||
|
||||
var ttlDuration time.Duration
|
||||
if len(ttl) != 0 {
|
||||
ttlDuration, err := time.ParseDuration(ttl)
|
||||
if err == nil {
|
||||
resp.Secret.Renewable = true
|
||||
resp.Secret.TTL = ttlDuration
|
||||
ttlDuration, err = time.ParseDuration(ttl)
|
||||
if err != nil {
|
||||
return logical.ErrorResponse("failed to parse ttl for entry"), nil
|
||||
}
|
||||
if b.generateLeases {
|
||||
resp.Secret.Renewable = true
|
||||
}
|
||||
} else {
|
||||
ttlDuration = b.System().DefaultLeaseTTL()
|
||||
}
|
||||
|
||||
resp.Secret.TTL = ttlDuration
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
|
@ -163,6 +195,10 @@ func (b *PassthroughBackend) handleList(
|
|||
return logical.ListResponse(keys), nil
|
||||
}
|
||||
|
||||
func (b *PassthroughBackend) GeneratesLeases() bool {
|
||||
return b.generateLeases
|
||||
}
|
||||
|
||||
const passthroughHelp = `
|
||||
The generic backend reads and writes arbitrary secrets to the backend.
|
||||
The secrets are encrypted/decrypted by Vault: they are never stored
|
||||
|
|
|
@ -39,7 +39,7 @@ func TestPassthroughBackend_Write(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPassthroughBackend_Read_Lease(t *testing.T) {
|
||||
b := testPassthroughBackend()
|
||||
b := testPassthroughLeasedBackend()
|
||||
req := logical.TestRequest(t, logical.WriteOperation, "foo")
|
||||
req.Data["raw"] = "test"
|
||||
req.Data["lease"] = "1h"
|
||||
|
@ -78,7 +78,7 @@ func TestPassthroughBackend_Read_Lease(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPassthroughBackend_Read_TTL(t *testing.T) {
|
||||
b := testPassthroughBackend()
|
||||
b := testPassthroughLeasedBackend()
|
||||
req := logical.TestRequest(t, logical.WriteOperation, "foo")
|
||||
req.Data["raw"] = "test"
|
||||
req.Data["ttl"] = "1h"
|
||||
|
@ -185,3 +185,14 @@ func testPassthroughBackend() logical.Backend {
|
|||
})
|
||||
return b
|
||||
}
|
||||
|
||||
func testPassthroughLeasedBackend() logical.Backend {
|
||||
b, _ := LeasedPassthroughBackendFactory(&logical.BackendConfig{
|
||||
Logger: nil,
|
||||
System: logical.StaticSystemView{
|
||||
DefaultLeaseTTLVal: time.Hour * 24,
|
||||
MaxLeaseTTLVal: time.Hour * 24 * 30,
|
||||
},
|
||||
})
|
||||
return b
|
||||
}
|
||||
|
|
|
@ -76,6 +76,7 @@ func TestCore(t *testing.T) *Core {
|
|||
for backendName, backendFactory := range noopBackends {
|
||||
logicalBackends[backendName] = backendFactory
|
||||
}
|
||||
logicalBackends["generic"] = LeasedPassthroughBackendFactory
|
||||
for backendName, backendFactory := range testLogicalBackends {
|
||||
logicalBackends[backendName] = backendFactory
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue