Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backport of Fix misattribution of activity log entries to incorrect auth methods into release/1.14.x #22507

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelog/18809.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
activity (enterprise): Fix misattribution of entities to no or child namespace auth methods
```
28 changes: 17 additions & 11 deletions vault/activity_log.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,6 @@ type segmentInfo struct {
tokenCount *activity.TokenCount
}

type clients struct {
distinctEntities uint64
distinctNonEntities uint64
}

// ActivityLog tracks unique entity counts and non-entity token counts.
// It handles assembling log fragments (and sending them to the active
// node), writing log segments, and precomputing queries.
Expand Down Expand Up @@ -1912,39 +1907,50 @@ func (a *ActivityLog) loadConfigOrDefault(ctx context.Context) (activityConfig,

// HandleTokenUsage adds the TokenEntry to the current fragment of the activity log
// This currently occurs on token usage only.
func (a *ActivityLog) HandleTokenUsage(ctx context.Context, entry *logical.TokenEntry, clientID string, isTWE bool) {
func (a *ActivityLog) HandleTokenUsage(ctx context.Context, entry *logical.TokenEntry, clientID string, isTWE bool) error {
// First, check if a is enabled, so as to avoid the cost of creating an ID for
// tokens without entities in the case where it not.
a.fragmentLock.RLock()
if !a.enabled {
a.fragmentLock.RUnlock()
return
return nil
}
a.fragmentLock.RUnlock()

// Do not count wrapping tokens in client count
if IsWrappingToken(entry) {
return
return nil
}

// Do not count root tokens in client count.
if entry.IsRoot() {
return
return nil
}

// Tokens created for the purpose of Link should bypass counting for billing purposes
if entry.InternalMeta != nil && entry.InternalMeta[IgnoreForBilling] == "true" {
return
return nil
}

// Look up the mount accessor of the auth method that issued the token, taking care to resolve the token path
// against the token namespace, which may not be the same as the request namespace!
tokenNS, err := NamespaceByID(ctx, entry.NamespaceID, a.core)
if err != nil {
return err
}
if tokenNS == nil {
return namespace.ErrNoNamespace
}
tokenCtx := namespace.ContextWithNamespace(ctx, tokenNS)
mountAccessor := ""
mountEntry := a.core.router.MatchingMountEntry(ctx, entry.Path)
mountEntry := a.core.router.MatchingMountEntry(tokenCtx, entry.Path)
if mountEntry != nil {
mountAccessor = mountEntry.Accessor
}

// Parse an entry's client ID and add it to the activity log
a.AddClientToFragment(clientID, entry.NamespaceID, entry.CreationTime, isTWE, mountAccessor)
return nil
}

func (a *ActivityLog) namespaceToLabel(ctx context.Context, nsID string) string {
Expand Down
24 changes: 18 additions & 6 deletions vault/activity_log_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,10 @@ func TestActivityLog_Creation_WrappingTokens(t *testing.T) {
}

id, isTWE := te.CreateClientID()
a.HandleTokenUsage(context.Background(), te, id, isTWE)
err := a.HandleTokenUsage(context.Background(), te, id, isTWE)
if err != nil {
t.Fatal(err)
}

a.fragmentLock.Lock()
if a.fragment != nil {
Expand All @@ -153,7 +156,10 @@ func TestActivityLog_Creation_WrappingTokens(t *testing.T) {
}

id, isTWE = teNew.CreateClientID()
a.HandleTokenUsage(context.Background(), teNew, id, isTWE)
err = a.HandleTokenUsage(context.Background(), teNew, id, isTWE)
if err != nil {
t.Fatal(err)
}

a.fragmentLock.Lock()
if a.fragment != nil {
Expand Down Expand Up @@ -380,18 +386,24 @@ func TestActivityLog_SaveTokensToStorageDoesNotUpdateTokenCount(t *testing.T) {
tokenPath := fmt.Sprintf("%sdirecttokens/%d/0", ActivityLogPrefix, a.GetStartTimestamp())
clientPath := fmt.Sprintf("sys/counters/activity/log/entity/%d/0", a.GetStartTimestamp())
// Create some entries without entityIDs
tokenEntryOne := logical.TokenEntry{NamespaceID: "ns1_id", Policies: []string{"hi"}}
entityEntry := logical.TokenEntry{EntityID: "foo", NamespaceID: "ns1_id", Policies: []string{"hi"}}
tokenEntryOne := logical.TokenEntry{NamespaceID: namespace.RootNamespaceID, Policies: []string{"hi"}}
entityEntry := logical.TokenEntry{EntityID: "foo", NamespaceID: namespace.RootNamespaceID, Policies: []string{"hi"}}

idNonEntity, isTWE := tokenEntryOne.CreateClientID()

for i := 0; i < 3; i++ {
a.HandleTokenUsage(ctx, &tokenEntryOne, idNonEntity, isTWE)
err := a.HandleTokenUsage(ctx, &tokenEntryOne, idNonEntity, isTWE)
if err != nil {
t.Fatal(err)
}
}

idEntity, isTWE := entityEntry.CreateClientID()
for i := 0; i < 2; i++ {
a.HandleTokenUsage(ctx, &entityEntry, idEntity, isTWE)
err := a.HandleTokenUsage(ctx, &entityEntry, idEntity, isTWE)
if err != nil {
t.Fatal(err)
}
}
err := a.saveCurrentSegmentToStorage(ctx, false)
if err != nil {
Expand Down
9 changes: 6 additions & 3 deletions vault/request_handling.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,12 +271,12 @@ func (c *Core) CheckToken(ctx context.Context, req *logical.Request, unauth bool
var te *logical.TokenEntry
var entity *identity.Entity
var identityPolicies map[string][]string
var err error

// Even if unauth, if a token is provided, there's little reason not to
// gather as much info as possible for the audit log and to e.g. control
// trace mode for EGPs.
if !unauth || (unauth && req.ClientToken != "") {
var err error
acl, te, entity, identityPolicies, err = c.fetchACLTokenEntryAndEntity(ctx, req)
// In the unauth case we don't want to fail the command, since it's
// unauth, we just have no information to attach to the request, so
Expand Down Expand Up @@ -438,9 +438,12 @@ func (c *Core) CheckToken(ctx context.Context, req *logical.Request, unauth bool
c.activityLogLock.RLock()
activityLog := c.activityLog
c.activityLogLock.RUnlock()
// If it is an authenticated ( i.e with vault token ) request, increment client count
// If it is an authenticated ( i.e. with vault token ) request, increment client count
if !unauth && activityLog != nil {
activityLog.HandleTokenUsage(ctx, te, clientID, isTWE)
err := c.activityLog.HandleTokenUsage(ctx, te, clientID, isTWE)
if err != nil {
return auth, te, err
}
}
return auth, te, nil
}
Expand Down