-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
Auditbeat file module improvements #4636
Auditbeat file module improvements #4636
Conversation
Unify the behavior across operating systems. - Add tests. - Resolve UID/GID/SID into owner/group. - Log warning if a file watch cannot be added. Previously it would fail at startup. - Remove usage of fsevents on macOS and use kqueues instead. The data provided was inconsistent with the fsnotify. It was valuable data but the signal needs some refinement to make it consistent. The biggest issue is that multiple events are coalesced into one. Another issue is that the watches are recursive (this is great, but it's inconsistent) and we will need to allow a glob to be specified then match the incoming events against the glob (future enhancement). - Document hash fields - Initialize watches on Start() rather than at construction time. - Update data.json to include file owner and group names. - Add file type and symlink target path to the events. - Filter fsnotify events with empty paths (saw this once on Windows).
9c6d0d2
to
bb7e1dc
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Most comments are not directly related to this PR and things that popped up in my head when reading it.
auditbeat/module/audit/file/event.go
Outdated
} else { | ||
m["uid"] = info.UID | ||
m["gid"] = info.GID | ||
m["mode"] = fmt.Sprintf("%#o", uint32(info.Mode)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you use #
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will "add leading 0 for octal (%#o)". https://golang.org/pkg/fmt/
I was wanting something like 0644
, but maybe a different format string would be more appropriate because what I really want is a minimum of 4 octal digits.
} | ||
|
||
for _, p := range paths { | ||
if err := r.watcher.Add(p); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Every time I see this I'm thinking if we should add a new prospector type in filebeat based on inotify which only works with "most" OS. Could make to code a lot simpler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this fsnotify package seems to work pretty well. The only downside is that you can't do recursive monitoring. Recursive monitoring is supported by Windows but this isn't exposed by fsnotify (the other OSes don't support it).
|
||
func convertToFileEvent(e fsnotify.Event, maxFileSize int64) Event { | ||
event := Event{ | ||
Timestamp: time.Now().UTC(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should introduce a helper in common
to get time.Now()
that always includes UTC
. I think there are several places where it's missing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That reminds me, I think I will open a PR to automatically convert all time.Time objects to UTC during event normalization. Then we won't need a helper because it won't matter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I opened #4658.
if err != nil { | ||
return errors.Wrap(err, "failed to stat file") | ||
return nil, errors.Wrap(err, "failed to stat path") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be nice to include the "failed" path in the error
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Stat/Lstat return a *os.PathError
that includes the path already so it would be redundant.
} | ||
|
||
stat, ok := info.Sys().(*syscall.Stat_t) | ||
if !ok { | ||
return errors.Errorf("unexpected fileinfo sys type %T", info.Sys()) | ||
return nil, errors.Errorf("unexpected fileinfo sys type %T", info.Sys()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
perhaps also include the path?
GID: stat.Gid, | ||
Mode: info.Mode(), | ||
Size: info.Size(), | ||
ATime: time.Unix(0, stat.Atimespec.Nano()).UTC(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know it was in before, but I would assume Micro should be enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I follow... the time.Unix()
function accepts nanoseconds which is why I'm using Nano()
.
if err != nil { | ||
return errors.Wrap(err, "failed to stat file") | ||
return nil, errors.Wrap(err, "failed to stat path") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comments above for logging, also line 22.
} | ||
|
||
return nil | ||
switch { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like at least some of the code could be shared between linux and bsd (did not do the detailed comparison, devil is probably in the detail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It really could be, and I was debating this. The only difference between the BSD and Linux variants is that the stat_t
structs use different member names for the time values. I could create a fileinfo_posix.go that's common to BSD + Linux. Then have a fileinfo_linux.go and fileinfo_bsd.go that provide a helper method for reading the time values from the stat_t
objects. I'll try it out, but I'm kind of thinking that the complexity out weighs the value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed this to reduce duplication.
return | ||
} | ||
|
||
info1, err := os.Stat(f1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should you use LStat here? if one of the params is a symlink to the file, do you expect this check to return true or false?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, will fix.
- Change mode format to %#04o to always get a leading 0 and a minimum of 4 digits. - Change Stat of Lstat in assertSameFile - Reduce code duplication between linux and bsd platforms.
@ruflin I addressed the review feedback. |
Unify the behavior across operating systems.
And add a simple dashboard: