On lease deletion, also delete non-orphan batch token parent index (#11377)

This commit is contained in:
Nick Cabatoff
2021-04-16 17:03:22 -04:00
committed by GitHub
parent a8b0a583d3
commit 8e94ea963b
4 changed files with 71 additions and 29 deletions

3
changelog/11377.txt Normal file
View File

@@ -0,0 +1,3 @@
```release-note:bug
core: Fix storage entry leak when revoking leases created with non-orphan batch tokens.
```

View File

@@ -915,8 +915,24 @@ func (m *ExpirationManager) revokeCommon(ctx context.Context, leaseID string, fo
// Delete the secondary index, but only if it's a leased secret (not auth) // Delete the secondary index, but only if it's a leased secret (not auth)
if le.Secret != nil { if le.Secret != nil {
if err := m.removeIndexByToken(ctx, le); err != nil { var indexToken string
return err // Maintain secondary index by token, except for orphan batch tokens
switch le.ClientTokenType {
case logical.TokenTypeBatch:
te, err := m.tokenStore.lookupBatchTokenInternal(ctx, le.ClientToken)
if err != nil {
return err
}
// If it's a non-orphan batch token, assign the secondary index to its
// parent
indexToken = te.Parent
default:
indexToken = le.ClientToken
}
if indexToken != "" {
if err := m.removeIndexByToken(ctx, le, indexToken); err != nil {
return err
}
} }
} }
@@ -1364,6 +1380,17 @@ func (m *ExpirationManager) Register(ctx context.Context, req *logical.Request,
Version: 1, Version: 1,
} }
var indexToken string
// Maintain secondary index by token, except for orphan batch tokens
switch {
case te.Type != logical.TokenTypeBatch:
indexToken = le.ClientToken
case te.Parent != "":
// If it's a non-orphan batch token, assign the secondary index to its
// parent
indexToken = te.Parent
}
defer func() { defer func() {
// If there is an error we want to rollback as much as possible (note // If there is an error we want to rollback as much as possible (note
// that errors here are ignored to do as much cleanup as we can). We // that errors here are ignored to do as much cleanup as we can). We
@@ -1382,7 +1409,7 @@ func (m *ExpirationManager) Register(ctx context.Context, req *logical.Request,
retErr = multierror.Append(retErr, errwrap.Wrapf("an additional error was encountered deleting any lease associated with the newly-generated secret: {{err}}", err)) retErr = multierror.Append(retErr, errwrap.Wrapf("an additional error was encountered deleting any lease associated with the newly-generated secret: {{err}}", err))
} }
if err := m.removeIndexByToken(ctx, le); err != nil { if err := m.removeIndexByToken(ctx, le, indexToken); err != nil {
retErr = multierror.Append(retErr, errwrap.Wrapf("an additional error was encountered removing lease indexes associated with the newly-generated secret: {{err}}", err)) retErr = multierror.Append(retErr, errwrap.Wrapf("an additional error was encountered removing lease indexes associated with the newly-generated secret: {{err}}", err))
} }
} }
@@ -1408,16 +1435,8 @@ func (m *ExpirationManager) Register(ctx context.Context, req *logical.Request,
return "", err return "", err
} }
// Maintain secondary index by token, except for orphan batch tokens if indexToken != "" {
switch { if err := m.createIndexByToken(ctx, le, indexToken); err != nil {
case te.Type != logical.TokenTypeBatch:
if err := m.createIndexByToken(ctx, le, le.ClientToken); err != nil {
return "", err
}
case te.Parent != "":
// If it's a non-orphan batch token, assign the secondary index to its
// parent
if err := m.createIndexByToken(ctx, le, te.Parent); err != nil {
return "", err return "", err
} }
} }
@@ -1966,10 +1985,10 @@ func (m *ExpirationManager) indexByToken(ctx context.Context, le *leaseEntry) (*
} }
// removeIndexByToken removes the secondary index from the token to a lease entry // removeIndexByToken removes the secondary index from the token to a lease entry
func (m *ExpirationManager) removeIndexByToken(ctx context.Context, le *leaseEntry) error { func (m *ExpirationManager) removeIndexByToken(ctx context.Context, le *leaseEntry, token string) error {
tokenNS := namespace.RootNamespace tokenNS := namespace.RootNamespace
saltCtx := namespace.ContextWithNamespace(ctx, namespace.RootNamespace) saltCtx := namespace.ContextWithNamespace(ctx, namespace.RootNamespace)
_, nsID := namespace.SplitIDFromString(le.ClientToken) _, nsID := namespace.SplitIDFromString(token)
if nsID != "" { if nsID != "" {
var err error var err error
tokenNS, err = NamespaceByID(ctx, nsID, m.core) tokenNS, err = NamespaceByID(ctx, nsID, m.core)
@@ -1990,7 +2009,7 @@ func (m *ExpirationManager) removeIndexByToken(ctx context.Context, le *leaseEnt
} }
} }
saltedID, err := m.tokenStore.SaltID(saltCtx, le.ClientToken) saltedID, err := m.tokenStore.SaltID(saltCtx, token)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -677,7 +677,8 @@ func TestExpiration_Register(t *testing.T) {
} }
func TestExpiration_Register_BatchToken(t *testing.T) { func TestExpiration_Register_BatchToken(t *testing.T) {
exp := mockExpiration(t) c, _, rootToken := TestCoreUnsealed(t)
exp := c.expiration
noop := &NoopBackend{ noop := &NoopBackend{
RequestHandler: func(ctx context.Context, req *logical.Request) (*logical.Response, error) { RequestHandler: func(ctx context.Context, req *logical.Request) (*logical.Response, error) {
resp := &logical.Response{Secret: req.Secret} resp := &logical.Response{Secret: req.Secret}
@@ -685,15 +686,17 @@ func TestExpiration_Register_BatchToken(t *testing.T) {
return resp, nil return resp, nil
}, },
} }
_, barrier, _ := mockBarrier(t) {
view := NewBarrierView(barrier, "logical/") _, barrier, _ := mockBarrier(t)
meUUID, err := uuid.GenerateUUID() view := NewBarrierView(barrier, "logical/")
if err != nil { meUUID, err := uuid.GenerateUUID()
t.Fatal(err) if err != nil {
} t.Fatal(err)
err = exp.router.Mount(noop, "prod/aws/", &MountEntry{Path: "prod/aws/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor", namespace: namespace.RootNamespace}, view) }
if err != nil { err = exp.router.Mount(noop, "prod/aws/", &MountEntry{Path: "prod/aws/", Type: "noop", UUID: meUUID, Accessor: "noop-accessor", namespace: namespace.RootNamespace}, view)
t.Fatal(err) if err != nil {
t.Fatal(err)
}
} }
te := &logical.TokenEntry{ te := &logical.TokenEntry{
@@ -701,9 +704,10 @@ func TestExpiration_Register_BatchToken(t *testing.T) {
TTL: 1 * time.Second, TTL: 1 * time.Second,
NamespaceID: "root", NamespaceID: "root",
CreationTime: time.Now().Unix(), CreationTime: time.Now().Unix(),
Parent: rootToken,
} }
err = exp.tokenStore.create(context.Background(), te) err := exp.tokenStore.create(context.Background(), te)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -760,6 +764,13 @@ func TestExpiration_Register_BatchToken(t *testing.T) {
break break
} }
idEnts, err := exp.tokenView.List(context.Background(), "")
if err != nil {
t.Fatal(err)
}
if len(idEnts) != 0 {
t.Fatalf("expected no entries in sys/expire/token, got: %v", idEnts)
}
} }
func TestExpiration_RegisterAuth(t *testing.T) { func TestExpiration_RegisterAuth(t *testing.T) {

View File

@@ -1122,7 +1122,7 @@ func (ts *TokenStore) lookupTainted(ctx context.Context, id string) (*logical.To
return ts.lookupInternal(ctx, id, false, true) return ts.lookupInternal(ctx, id, false, true)
} }
func (ts *TokenStore) lookupBatchToken(ctx context.Context, id string) (*logical.TokenEntry, error) { func (ts *TokenStore) lookupBatchTokenInternal(ctx context.Context, id string) (*logical.TokenEntry, error) {
// Strip the b. from the front and namespace ID from the back // Strip the b. from the front and namespace ID from the back
bEntry, _ := namespace.SplitIDFromString(id[2:]) bEntry, _ := namespace.SplitIDFromString(id[2:])
@@ -1146,6 +1146,16 @@ func (ts *TokenStore) lookupBatchToken(ctx context.Context, id string) (*logical
return nil, err return nil, err
} }
te.ID = id
return te, nil
}
func (ts *TokenStore) lookupBatchToken(ctx context.Context, id string) (*logical.TokenEntry, error) {
te, err := ts.lookupBatchTokenInternal(ctx, id)
if err != nil {
return nil, err
}
if time.Now().After(time.Unix(te.CreationTime, 0).Add(te.TTL)) { if time.Now().After(time.Unix(te.CreationTime, 0).Add(te.TTL)) {
return nil, nil return nil, nil
} }
@@ -1160,7 +1170,6 @@ func (ts *TokenStore) lookupBatchToken(ctx context.Context, id string) (*logical
} }
} }
te.ID = id
return te, nil return te, nil
} }