diff --git a/CHANGELOG.next.asciidoc b/CHANGELOG.next.asciidoc index 11f7da606a51..da2bf0bd43ee 100644 --- a/CHANGELOG.next.asciidoc +++ b/CHANGELOG.next.asciidoc @@ -128,6 +128,8 @@ https://github.com/elastic/beats/compare/v8.2.0\...main[Check the HEAD diff] *Auditbeat* +- Improve documentation for symlink handling behaviour in file integrity module. {pull}33430[33430] +- Ensure file integrity module watch paths are absolute. {pull}33430[33430] *Filebeat* diff --git a/auditbeat/docs/modules/file_integrity.asciidoc b/auditbeat/docs/modules/file_integrity.asciidoc index d3080c01f5cc..c26229286ccc 100644 --- a/auditbeat/docs/modules/file_integrity.asciidoc +++ b/auditbeat/docs/modules/file_integrity.asciidoc @@ -75,7 +75,12 @@ described later. *`paths`*:: A list of paths (directories or files) to watch. Globs are not supported. The specified paths should exist when the metricset is started. Paths should be absolute, although the file integrity module will attempt to -resolve relative path events to their absolute file path. +resolve relative path events to their absolute file path. Symbolic links will +be resolved on module start and the link target will be watched if link resolution +is successful. Changes to the symbolic link after module start will not change +the watch target. If the link does not resolve to a valid target, the symbolic +link itself will be watched; if the symlink target becomes valid after module +start up this will not be picked up by the file system watches. *`exclude_files`*:: A list of regular expressions used to filter out events for unwanted files. The expressions are matched against the full path of every diff --git a/auditbeat/module/file_integrity/_meta/docs.asciidoc b/auditbeat/module/file_integrity/_meta/docs.asciidoc index c32d8d6e62a5..4d9f25fb64b0 100644 --- a/auditbeat/module/file_integrity/_meta/docs.asciidoc +++ b/auditbeat/module/file_integrity/_meta/docs.asciidoc @@ -68,7 +68,12 @@ described later. *`paths`*:: A list of paths (directories or files) to watch. Globs are not supported. The specified paths should exist when the metricset is started. Paths should be absolute, although the file integrity module will attempt to -resolve relative path events to their absolute file path. +resolve relative path events to their absolute file path. Symbolic links will +be resolved on module start and the link target will be watched if link resolution +is successful. Changes to the symbolic link after module start will not change +the watch target. If the link does not resolve to a valid target, the symbolic +link itself will be watched; if the symlink target becomes valid after module +start up this will not be picked up by the file system watches. *`exclude_files`*:: A list of regular expressions used to filter out events for unwanted files. The expressions are matched against the full path of every diff --git a/auditbeat/module/file_integrity/config.go b/auditbeat/module/file_integrity/config.go index f1fa35ebdca0..909f9b050dd0 100644 --- a/auditbeat/module/file_integrity/config.go +++ b/auditbeat/module/file_integrity/config.go @@ -89,11 +89,19 @@ type Config struct { // Validate validates the config data and return an error explaining all the // problems with the config. This method modifies the given config. func (c *Config) Validate() error { - // Resolve symlinks. + // Resolve symlinks and make filepaths absolute if possible + // anything that does not resolve will be logged during + // scanning and metric set collection. for i, p := range c.Paths { - if evalPath, err := filepath.EvalSymlinks(p); err == nil { - c.Paths[i] = evalPath + p, err := filepath.EvalSymlinks(p) + if err != nil { + continue + } + p, err = filepath.Abs(p) + if err != nil { + continue } + c.Paths[i] = p } // Sort and deduplicate. sort.Strings(c.Paths) diff --git a/auditbeat/module/file_integrity/metricset.go b/auditbeat/module/file_integrity/metricset.go index 558bea96a5bc..bcada27db9f4 100644 --- a/auditbeat/module/file_integrity/metricset.go +++ b/auditbeat/module/file_integrity/metricset.go @@ -196,10 +196,15 @@ func (ms *MetricSet) findNewPaths() map[string]struct{} { newPaths := make(map[string]struct{}) for _, path := range ms.config.Paths { - // Resolve symlinks to ensure we have an absolute path. + // Resolve symlinks and ensure we have an absolute path. evalPath, err := filepath.EvalSymlinks(path) if err != nil { - ms.log.Warnw("Failed to resolve", "file_path", path, "error", err) + ms.log.Warnw("Failed to resolve symlink", "file_path", path, "error", err) + continue + } + evalPath, err = filepath.Abs(evalPath) + if err != nil { + ms.log.Warnw("Failed to resolve to absolute path", "file_path", path, "error", err) continue } diff --git a/auditbeat/module/file_integrity/scanner.go b/auditbeat/module/file_integrity/scanner.go index ac073e2affdd..3de4d59840a5 100644 --- a/auditbeat/module/file_integrity/scanner.go +++ b/auditbeat/module/file_integrity/scanner.go @@ -92,10 +92,15 @@ func (s *scanner) scan() { startTime := time.Now() for _, path := range s.config.Paths { - // Resolve symlinks to ensure we have an absolute path. + // Resolve symlinks and ensure we have an absolute path. evalPath, err := filepath.EvalSymlinks(path) if err != nil { - s.log.Warnw("Failed to scan", "file_path", path, "error", err) + s.log.Warnw("Failed to resolve symlink", "file_path", path, "error", err) + continue + } + evalPath, err = filepath.Abs(evalPath) + if err != nil { + s.log.Warnw("Failed to resolve to absolute path", "file_path", path, "error", err) continue }