diff --git a/changelog/29145.txt b/changelog/29145.txt new file mode 100644 index 0000000000..dc5a789446 --- /dev/null +++ b/changelog/29145.txt @@ -0,0 +1,4 @@ +```release-note:improvement +activity: Add a "local_mount" field to the Export API response. This field is true if the client is a token or created on a +local mount. +``` diff --git a/vault/activity_log.go b/vault/activity_log.go index 90ebffdd38..aa15828c62 100644 --- a/vault/activity_log.go +++ b/vault/activity_log.go @@ -336,6 +336,9 @@ type ActivityLogExportRecord struct { // MountPath is the path of the auth mount associated with the token used MountPath string `json:"mount_path" mapstructure:"mount_path"` + // LocalMount indicates if the mount only belongs to the current cluster + LocalMount bool `json:"local_mount" mapstructure:"local_mount"` + // Timestamp denotes the time at which the activity occurred formatted using RFC3339 Timestamp string `json:"timestamp" mapstructure:"timestamp"` @@ -916,7 +919,7 @@ func (a *ActivityLog) getLastSegmentNumberByEntityPath(ctx context.Context, enti } // WalkEntitySegments loads each of the entity segments for a particular start time -func (a *ActivityLog) WalkEntitySegments(ctx context.Context, startTime time.Time, hll *hyperloglog.Sketch, walkFn func(*activity.EntityActivityLog, time.Time, *hyperloglog.Sketch) error) error { +func (a *ActivityLog) WalkEntitySegments(ctx context.Context, startTime time.Time, hll *hyperloglog.Sketch, walkFn func(*activity.EntityActivityLog, time.Time, bool) error) error { baseGlobalPath := activityGlobalPathPrefix + activityEntityBasePath + fmt.Sprint(startTime.Unix()) + "/" baseLocalPath := activityLocalPathPrefix + activityEntityBasePath + fmt.Sprint(startTime.Unix()) + "/" @@ -940,7 +943,7 @@ func (a *ActivityLog) WalkEntitySegments(ctx context.Context, startTime time.Tim if err != nil { return fmt.Errorf("unable to parse segment %v%v: %w", basePath, path, err) } - err = walkFn(out, startTime, hll) + err = walkFn(out, startTime, basePath == baseLocalPath) if err != nil { return fmt.Errorf("unable to walk entities: %w", err) } @@ -3834,7 +3837,7 @@ func (a *ActivityLog) writeExport(ctx context.Context, rw http.ResponseWriter, f return err } - walkEntities := func(l *activity.EntityActivityLog, startTime time.Time, hll *hyperloglog.Sketch) error { + walkEntities := func(l *activity.EntityActivityLog, startTime time.Time, isLocal bool) error { for _, e := range l.Clients { if _, ok := dedupIDs[e.ClientID]; ok { continue @@ -3866,6 +3869,7 @@ func (a *ActivityLog) writeExport(ctx context.Context, rw http.ResponseWriter, f NamespacePath: nsDisplayPath, Timestamp: ts.UTC().Format(time.RFC3339), MountAccessor: e.MountAccessor, + LocalMount: isLocal, // Default following to empty versus nil, will be overwritten if necessary Policies: []string{}, @@ -4261,6 +4265,7 @@ func baseActivityExportCSVHeader() []string { "client_id", "client_type", "local_entity_alias", + "local_mount", "namespace_id", "namespace_path", "mount_accessor", diff --git a/vault/external_tests/activity_testonly/activity_testonly_test.go b/vault/external_tests/activity_testonly/activity_testonly_test.go index cd9dfb2157..4fcca08c04 100644 --- a/vault/external_tests/activity_testonly/activity_testonly_test.go +++ b/vault/external_tests/activity_testonly/activity_testonly_test.go @@ -1,7 +1,7 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: BUSL-1.1 -////go:build testonly +//go:build testonly package activity_testonly @@ -549,6 +549,7 @@ func getCSVExport(t *testing.T, client *api.Client, monthsPreviousTo int, now ti boolFields := map[string]struct{}{ "local_entity_alias": {}, + "local_mount": {}, } mapFields := map[string]struct{}{