fluent-plugin-masking 1.0.8 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +3 -3
- data/README.md +15 -0
- data/lib/fluent/plugin/filter_masking.rb +28 -3
- data/lib/fluent/plugin/version.rb +1 -1
- data/test/test_filter_masking.rb +40 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '08a7033570c7aaca9dc0a4830f4550ef5e353b9e5195dc3cfcc79eb68880fcae'
|
4
|
+
data.tar.gz: '0845c7ee9ae72c13652cd9a517a71f0289c88f2144cf2afcad18370c1f1fa358'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 61a8a367ec559746eee72fd7e33a4d62b6f38777a18b3d5560c82dffcee5c65332ef8fbfd39e018b5dec34930e8a13cdbfa41356a796b4afc9c858eac7ce13d2
|
7
|
+
data.tar.gz: 92b95fad73c342b281ce44d451ce0d52ddcce490d1b0753498671320b38ffb840840b02a44a2ab184d7be0fc636aa2f78ba6dbed6e1a3e8c32f4ebcd71ebe3dd
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
fluent-plugin-masking (1.0
|
4
|
+
fluent-plugin-masking (1.1.0)
|
5
5
|
fluentd (>= 0.14.0)
|
6
6
|
|
7
7
|
GEM
|
@@ -10,7 +10,7 @@ GEM
|
|
10
10
|
concurrent-ruby (1.1.5)
|
11
11
|
cool.io (1.5.4)
|
12
12
|
dig_rb (1.0.1)
|
13
|
-
fluentd (1.7.
|
13
|
+
fluentd (1.7.4)
|
14
14
|
cool.io (>= 1.4.5, < 2.0.0)
|
15
15
|
dig_rb (~> 1.0.0)
|
16
16
|
http_parser.rb (>= 0.5.1, < 0.7.0)
|
@@ -26,7 +26,7 @@ GEM
|
|
26
26
|
power_assert (1.1.5)
|
27
27
|
rake (12.3.3)
|
28
28
|
rr (1.2.1)
|
29
|
-
serverengine (2.
|
29
|
+
serverengine (2.2.0)
|
30
30
|
sigdump (~> 0.2.2)
|
31
31
|
sigdump (0.2.4)
|
32
32
|
strptime (0.2.3)
|
data/README.md
CHANGED
@@ -19,11 +19,15 @@ Install with gem:
|
|
19
19
|
## Setup
|
20
20
|
In order to setup this plugin, the parameter `fieldsToMaskFilePath` needs to be a valid path to a file containing a list of all the fields to mask. The file should have a unique field on each line. These fields **are** case-sensitive (`Name` != `name`).
|
21
21
|
|
22
|
+
In addition, there's an optional parameter called `fieldsToExcludeJSONPaths` which receives as input a comma separated string of JSON fields that should be excluded in the masking procedure. Nested JSON fields are supported by `dot notation` (i.e: `path.to.excluded.field.in.record.nestedExcludedField`)
|
23
|
+
The JSON fields that are excluded are comma separated.
|
24
|
+
This can be used for logs of registration services or audit log entries which do not need to be masked.
|
22
25
|
This is configured as shown below:
|
23
26
|
```
|
24
27
|
<filter "**">
|
25
28
|
@type masking
|
26
29
|
fieldsToMaskFilePath "/path/to/fields-to-mask-file"
|
30
|
+
fieldsToExcludeJSONPaths "excludedField,exclude.path.nestedExcludedField"
|
27
31
|
</filter>
|
28
32
|
```
|
29
33
|
|
@@ -52,6 +56,7 @@ phone
|
|
52
56
|
<filter "**">
|
53
57
|
@type masking
|
54
58
|
fieldsToMaskFilePath "/path/to/fields-to-mask-file"
|
59
|
+
fieldsToExcludeJSONPaths "excludedField,exclude.path.nestedExcludedField"
|
55
60
|
</filter>
|
56
61
|
|
57
62
|
<match "**">
|
@@ -83,3 +88,13 @@ This sample result is created from the above configuration file `fluent.conf`. A
|
|
83
88
|
```
|
84
89
|
2019-09-15 16:12:50.359191000 +0300 maskme: {"message":"{ :body => \"{\\\"first_name\\\":\\\"*******\\\", \\\"type\\\":\\\"puggle\\\", \\\"last_name\\\":\\\"*******\\\", \\\"password\\\":\\\"*******\\\"}\"}"}
|
85
90
|
```
|
91
|
+
|
92
|
+
A sample with exclude in use:
|
93
|
+
```
|
94
|
+
fluentd -c fluent.conf
|
95
|
+
echo '{ :body => "{\"first_name\":\"mickey\", \"type\":\"puggle\", \"last_name\":\"the-dog\", \"password\":\"d0g43u39\"}", "excludeMaskFields"=>"first_name,last_name"}' > /tmp/test.log
|
96
|
+
```
|
97
|
+
|
98
|
+
```
|
99
|
+
2019-12-01 14:25:53.385681000 +0300 maskme: {"message":"{ :body => \"{\\\"first_name\\\":\\\"mickey\\\", \\\"type\\\":\\\"puggle\\\", \\\"last_name\\\":\\\"the-dog\\\", \\\"password\\\":\\\"*******\\\"}\"}"}
|
100
|
+
```
|
@@ -15,11 +15,19 @@ module Fluent
|
|
15
15
|
# error safe method - if any error occurs the original record is returned
|
16
16
|
def maskRecord(record)
|
17
17
|
maskedRecord = record
|
18
|
-
|
19
|
-
|
18
|
+
excludedFields = []
|
19
|
+
@fieldsToExcludeJSONPathsArray.each do | field |
|
20
|
+
field_value = record.dig(*field)
|
21
|
+
if field_value != nil
|
22
|
+
excludedFields = excludedFields + field_value.split(',')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
begin
|
20
26
|
recordStr = record.to_s
|
21
27
|
@fields_to_mask_regex.each do | fieldToMaskRegex, fieldToMaskRegexStringReplacement |
|
22
|
-
|
28
|
+
if !(excludedFields.include? @fields_to_mask_keys[fieldToMaskRegex])
|
29
|
+
recordStr = recordStr.gsub(fieldToMaskRegex, fieldToMaskRegexStringReplacement)
|
30
|
+
end
|
23
31
|
end
|
24
32
|
|
25
33
|
maskedRecord = strToHash(recordStr)
|
@@ -35,12 +43,27 @@ module Fluent
|
|
35
43
|
super
|
36
44
|
@fields_to_mask = []
|
37
45
|
@fields_to_mask_regex = {}
|
46
|
+
@fields_to_mask_keys = {}
|
47
|
+
@fieldsToExcludeJSONPathsArray = []
|
38
48
|
end
|
39
49
|
|
40
50
|
# this method only called ones (on startup time)
|
41
51
|
def configure(conf)
|
42
52
|
super
|
43
53
|
fieldsToMaskFilePath = conf['fieldsToMaskFilePath']
|
54
|
+
fieldsToExcludeJSONPaths = conf['fieldsToExcludeJSONPaths']
|
55
|
+
|
56
|
+
if fieldsToExcludeJSONPaths != nil && fieldsToExcludeJSONPaths.size() > 0
|
57
|
+
fieldsToExcludeJSONPaths.split(",").each do | field |
|
58
|
+
# To save splits we'll save the path as an array
|
59
|
+
splitArray = field.split(".")
|
60
|
+
symArray = []
|
61
|
+
splitArray.each do | pathPortion |
|
62
|
+
symArray.push(pathPortion.to_sym)
|
63
|
+
end
|
64
|
+
@fieldsToExcludeJSONPathsArray.push(symArray)
|
65
|
+
end
|
66
|
+
end
|
44
67
|
|
45
68
|
File.open(fieldsToMaskFilePath, "r") do |f|
|
46
69
|
f.each_line do |line|
|
@@ -54,10 +77,12 @@ module Fluent
|
|
54
77
|
hashObjectRegex = Regexp.new(/(?::#{value}=>")(.*?)(?:")/m) # mask element in hash object
|
55
78
|
hashObjectRegexStringReplacement = ":#{value}=>\"#{MASK_STRING}\""
|
56
79
|
@fields_to_mask_regex[hashObjectRegex] = hashObjectRegexStringReplacement
|
80
|
+
@fields_to_mask_keys[hashObjectRegex] = value
|
57
81
|
|
58
82
|
innerJSONStringRegex = Regexp.new(/(\\+)"#{value}\\+":\\+.+?((?=(})|,( *|)(\s|\\+)\")|(?=}"$))/m) # mask element in json string using capture groups that count the level of escaping inside the json string
|
59
83
|
innerJSONStringRegexStringReplacement = "\\1\"#{value}\\1\":\\1\"#{MASK_STRING}\\1\""
|
60
84
|
@fields_to_mask_regex[innerJSONStringRegex] = innerJSONStringRegexStringReplacement
|
85
|
+
@fields_to_mask_keys[innerJSONStringRegex] = value
|
61
86
|
end
|
62
87
|
end
|
63
88
|
|
data/test/test_filter_masking.rb
CHANGED
@@ -17,6 +17,12 @@ class YourOwnFilterTest < Test::Unit::TestCase
|
|
17
17
|
# default configuration for tests
|
18
18
|
CONFIG = %[
|
19
19
|
fieldsToMaskFilePath test/fields-to-mask
|
20
|
+
fieldsToExcludeJSONPaths excludedField,exclude.path.nestedExcludedField
|
21
|
+
]
|
22
|
+
|
23
|
+
# configuration for tests without exclude parameter
|
24
|
+
CONFIG_NO_EXCLUDE = %[
|
25
|
+
fieldsToMaskFilePath test/fields-to-mask
|
20
26
|
]
|
21
27
|
|
22
28
|
def create_driver(conf = CONFIG)
|
@@ -35,7 +41,7 @@ class YourOwnFilterTest < Test::Unit::TestCase
|
|
35
41
|
|
36
42
|
sub_test_case 'plugin will mask all fields that need masking' do
|
37
43
|
test 'mask field in hash object' do
|
38
|
-
conf =
|
44
|
+
conf = CONFIG_NO_EXCLUDE
|
39
45
|
messages = [
|
40
46
|
{:not_masked_field=>"mickey-the-dog", :email=>"mickey-the-dog@zooz.com"}
|
41
47
|
]
|
@@ -93,5 +99,38 @@ class YourOwnFilterTest < Test::Unit::TestCase
|
|
93
99
|
filtered_records = filter(conf, messages)
|
94
100
|
assert_equal(expected, filtered_records)
|
95
101
|
end
|
102
|
+
test 'mask field in hash object with exclude' do
|
103
|
+
conf = CONFIG
|
104
|
+
messages = [
|
105
|
+
{:not_masked_field=>"mickey-the-dog", :email=>"mickey-the-dog@zooz.com", :first_name=>"Micky", :excludedField=>"first_name"}
|
106
|
+
]
|
107
|
+
expected = [
|
108
|
+
{:not_masked_field=>"mickey-the-dog", :email=>MASK_STRING, :first_name=>"Micky", :excludedField=>"first_name"}
|
109
|
+
]
|
110
|
+
filtered_records = filter(conf, messages)
|
111
|
+
assert_equal(expected, filtered_records)
|
112
|
+
end
|
113
|
+
test 'mask field in hash object with nested exclude' do
|
114
|
+
conf = CONFIG
|
115
|
+
messages = [
|
116
|
+
{:not_masked_field=>"mickey-the-dog", :last_name=>"the dog", :email=>"mickey-the-dog@zooz.com", :first_name=>"Micky", :exclude=>{:path=>{:nestedExcludedField=>"first_name,last_name"}}}
|
117
|
+
]
|
118
|
+
expected = [
|
119
|
+
{:not_masked_field=>"mickey-the-dog", :last_name=>"the dog", :email=>MASK_STRING, :first_name=>"Micky", :exclude=>{:path=>{:nestedExcludedField=>"first_name,last_name"}}}
|
120
|
+
]
|
121
|
+
filtered_records = filter(conf, messages)
|
122
|
+
assert_equal(expected, filtered_records)
|
123
|
+
end
|
124
|
+
test 'mask field in hash object with base and nested exclude' do
|
125
|
+
conf = CONFIG
|
126
|
+
messages = [
|
127
|
+
{:not_masked_field=>"mickey-the-dog", :last_name=>"the dog", :email=>"mickey-the-dog@zooz.com", :first_name=>"Micky", :excludedField=>"first_name", :exclude=>{:path=>{:nestedExcludedField=>"last_name"}}}
|
128
|
+
]
|
129
|
+
expected = [
|
130
|
+
{:not_masked_field=>"mickey-the-dog", :last_name=>"the dog", :email=>MASK_STRING, :first_name=>"Micky", :excludedField=>"first_name", :exclude=>{:path=>{:nestedExcludedField=>"last_name"}}}
|
131
|
+
]
|
132
|
+
filtered_records = filter(conf, messages)
|
133
|
+
assert_equal(expected, filtered_records)
|
134
|
+
end
|
96
135
|
end
|
97
136
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-masking
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shai Moria
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2019-
|
12
|
+
date: 2019-12-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: fluentd
|
@@ -119,7 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
119
119
|
- !ruby/object:Gem::Version
|
120
120
|
version: '0'
|
121
121
|
requirements: []
|
122
|
-
rubygems_version: 3.0.
|
122
|
+
rubygems_version: 3.0.3
|
123
123
|
signing_key:
|
124
124
|
specification_version: 4
|
125
125
|
summary: Fluentd filter plugin to mask sensitive or privacy records with `*******`
|