fluent-plugin-masking 1.0.8 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: 02c98ca4f43cdef94bd6ec5615355f76601d5fa7ec28307ffc7c2748a629a0dd
4
- data.tar.gz: a25640c10af2bd1724acb5381cd512eeb129719376824a2be0f98aa3e3d6bd55
2
+ SHA1:
3
+ metadata.gz: 5b8b769887786df667374682f71ddbc61f6b575f
4
+ data.tar.gz: c143faea655e8ec4f621445d66525f827b26e9a0
5
5
  SHA512:
6
- metadata.gz: 77b885170c3d95b1abcb60df6e0a86958bce0e137718375179cbf17d6a824144034dfa4954c69397b9d1d8f127be5c218c81dc120340c0546def8cd5df27ceff
7
- data.tar.gz: 139d6cfec14a8e970653d44bbf85b5ef9de0765f03bd6b0d67ee3fb0c9da2b94f6635c7915e63c64cbb77a6d98e46ffed83821f9a340680e6d7d64bae75db988
6
+ metadata.gz: c964b4e42d7bbbe59fcaf570b1ac8281427ee7d15ea20cb8dcd9320343a306739571e25c2030e3f63cd2465daec6ec757ce7a57c68127c21e7acabba36b3243c
7
+ data.tar.gz: d9937e8bf71d1431cf9312134618d2bd5c842e203ce9d853cc4e8cb2a08b8c60cfea4b21105c3296ca35dedd2dc3a1cb1c61d871fe90dcf74abdfe64e0f73f29
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- fluent-plugin-masking (1.0.7)
4
+ fluent-plugin-masking (1.1.2)
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.2)
13
+ fluentd (1.8.0)
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)
@@ -18,7 +18,7 @@ GEM
18
18
  serverengine (>= 2.0.4, < 3.0.0)
19
19
  sigdump (~> 0.2.2)
20
20
  strptime (>= 0.2.2, < 1.0.0)
21
- tzinfo (~> 2.0)
21
+ tzinfo (>= 1.0, < 3.0)
22
22
  tzinfo-data (~> 1.0)
23
23
  yajl-ruby (~> 1.0)
24
24
  http_parser.rb (0.6.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.1.1)
29
+ serverengine (2.2.0)
30
30
  sigdump (~> 0.2.2)
31
31
  sigdump (0.2.4)
32
32
  strptime (0.2.3)
@@ -45,11 +45,11 @@ PLATFORMS
45
45
  ruby
46
46
 
47
47
  DEPENDENCIES
48
- bundler
48
+ bundler (= 1.17.3)
49
49
  fluent-plugin-masking!
50
50
  rake (~> 12.0)
51
51
  test-unit (>= 3.1.0)
52
52
  test-unit-rr
53
53
 
54
54
  BUNDLED WITH
55
- 2.0.2
55
+ 1.17.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
+ ```
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
21
21
  spec.required_ruby_version = '>= 2.1'
22
22
 
23
23
  spec.add_runtime_dependency "fluentd", ">= 0.14.0"
24
- spec.add_development_dependency "bundler"
24
+ spec.add_development_dependency "bundler", "1.17.3"
25
25
  spec.add_development_dependency "rake", "~> 12.0"
26
26
  spec.add_development_dependency "test-unit", ">= 3.1.0"
27
27
  spec.add_development_dependency "test-unit-rr"
@@ -1,8 +1,10 @@
1
1
  require 'fluent/filter'
2
+ require_relative './helpers.rb'
2
3
 
3
4
  module Fluent
4
5
  module Plugin
5
6
  class MaskingFilter < Filter
7
+ include Helpers
6
8
  Fluent::Plugin.register_filter("masking", self) # for "@type masking" in configuration
7
9
 
8
10
  MASK_STRING = "*******"
@@ -15,11 +17,23 @@ module Fluent
15
17
  # error safe method - if any error occurs the original record is returned
16
18
  def maskRecord(record)
17
19
  maskedRecord = record
18
-
20
+ excludedFields = []
21
+ begin
22
+ @fieldsToExcludeJSONPathsArray.each do | field |
23
+ field_value = myDig(record, field)
24
+ if field_value != nil
25
+ excludedFields = excludedFields + field_value.split(',')
26
+ end
27
+ end
28
+ rescue Exception => e
29
+ $log.error "Failed to find mask exclude record: #{e}"
30
+ end
19
31
  begin
20
32
  recordStr = record.to_s
21
33
  @fields_to_mask_regex.each do | fieldToMaskRegex, fieldToMaskRegexStringReplacement |
22
- recordStr = recordStr.gsub(fieldToMaskRegex, fieldToMaskRegexStringReplacement)
34
+ if !(excludedFields.include? @fields_to_mask_keys[fieldToMaskRegex])
35
+ recordStr = recordStr.gsub(fieldToMaskRegex, fieldToMaskRegexStringReplacement)
36
+ end
23
37
  end
24
38
 
25
39
  maskedRecord = strToHash(recordStr)
@@ -35,12 +49,27 @@ module Fluent
35
49
  super
36
50
  @fields_to_mask = []
37
51
  @fields_to_mask_regex = {}
52
+ @fields_to_mask_keys = {}
53
+ @fieldsToExcludeJSONPathsArray = []
38
54
  end
39
55
 
40
56
  # this method only called ones (on startup time)
41
57
  def configure(conf)
42
58
  super
43
59
  fieldsToMaskFilePath = conf['fieldsToMaskFilePath']
60
+ fieldsToExcludeJSONPaths = conf['fieldsToExcludeJSONPaths']
61
+
62
+ if fieldsToExcludeJSONPaths != nil && fieldsToExcludeJSONPaths.size() > 0
63
+ fieldsToExcludeJSONPaths.split(",").each do | field |
64
+ # To save splits we'll save the path as an array
65
+ splitArray = field.split(".")
66
+ symArray = []
67
+ splitArray.each do | pathPortion |
68
+ symArray.push(pathPortion.to_sym)
69
+ end
70
+ @fieldsToExcludeJSONPathsArray.push(symArray)
71
+ end
72
+ end
44
73
 
45
74
  File.open(fieldsToMaskFilePath, "r") do |f|
46
75
  f.each_line do |line|
@@ -54,10 +83,12 @@ module Fluent
54
83
  hashObjectRegex = Regexp.new(/(?::#{value}=>")(.*?)(?:")/m) # mask element in hash object
55
84
  hashObjectRegexStringReplacement = ":#{value}=>\"#{MASK_STRING}\""
56
85
  @fields_to_mask_regex[hashObjectRegex] = hashObjectRegexStringReplacement
86
+ @fields_to_mask_keys[hashObjectRegex] = value
57
87
 
58
88
  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
89
  innerJSONStringRegexStringReplacement = "\\1\"#{value}\\1\":\\1\"#{MASK_STRING}\\1\""
60
90
  @fields_to_mask_regex[innerJSONStringRegex] = innerJSONStringRegexStringReplacement
91
+ @fields_to_mask_keys[innerJSONStringRegex] = value
61
92
  end
62
93
  end
63
94
 
@@ -0,0 +1,17 @@
1
+ module Helpers
2
+ def myDig(input, path)
3
+ curr = input
4
+ for segment in path do
5
+ if curr != nil && curr.is_a?(Hash)
6
+ if curr[segment] == nil # segment is not a symbol
7
+ curr = curr[segment.to_s] # segment as string
8
+ else
9
+ curr = curr[segment] # segment as symbol
10
+ end
11
+ else
12
+ return nil
13
+ end
14
+ end
15
+ curr
16
+ end
17
+ end
@@ -1,3 +1,3 @@
1
1
  module FilterMasking
2
- VERSION = "1.0.8"
2
+ VERSION = "1.1.2"
3
3
  end
@@ -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 = CONFIG
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,49 @@ 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
135
+ test 'mask field in json string with exclude' do
136
+ conf = CONFIG
137
+ messages = [
138
+ { :body => "{\"first_name\":\"mickey\",\"last_name\":\"the-dog\", \"type\":\"puggle\"}", :excludedField=>"first_name" }
139
+ ]
140
+ expected = [
141
+ { :body => "{\"first_name\":\"mickey\",\"last_name\":\"*******\", \"type\":\"puggle\"}", :excludedField=>"first_name" }
142
+ ]
143
+ filtered_records = filter(conf, messages)
144
+ assert_equal(expected, filtered_records)
145
+ end
96
146
  end
97
147
  end
@@ -0,0 +1,42 @@
1
+ require "test/unit"
2
+ require "./lib/fluent/plugin/helpers.rb"
3
+
4
+ class HelpersTest < Test::Unit::TestCase
5
+ m = Class.new do
6
+ include Helpers
7
+ end.new
8
+ sub_test_case "myDig function" do
9
+ test "Call function with nil" do
10
+ t = m.myDig(nil ,[:a])
11
+ assert_equal(t, nil)
12
+ end
13
+ test "Not found" do
14
+ t = m.myDig({:b => "t"},[:a])
15
+ assert_equal(t, nil)
16
+ end
17
+ test "Found symbol" do
18
+ t = m.myDig({:a => "t"},[:a])
19
+ assert_equal(t, "t")
20
+ end
21
+ test "Found string when given symbol" do
22
+ t = m.myDig({"a" => "t"},[:a])
23
+ assert_equal(t, "t")
24
+ end
25
+ test "Found symbol nested" do
26
+ t = m.myDig({:a => {:b => "t"}},[:a, :b])
27
+ assert_equal(t, "t")
28
+ end
29
+ test "Found string when given symbol nested" do
30
+ t = m.myDig({"a" => {"b" => "t"}},[:a, :b])
31
+ assert_equal(t, "t")
32
+ end
33
+ test "Found hybrid string/symbol when given symbol nested" do
34
+ t = m.myDig({"a" => {:b => "t"}},[:a, :b])
35
+ assert_equal(t, "t")
36
+ end
37
+ test "Does not dig in string" do
38
+ t = m.myDig({"a" => {:b => "t"}},[:a, :b, :c])
39
+ assert_equal(t, nil)
40
+ end
41
+ end
42
+ 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.8
4
+ version: 1.1.2
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-09-22 00:00:00.000000000 Z
12
+ date: 2019-12-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: fluentd
@@ -29,16 +29,16 @@ dependencies:
29
29
  name: bundler
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - ">="
32
+ - - '='
33
33
  - !ruby/object:Gem::Version
34
- version: '0'
34
+ version: 1.17.3
35
35
  type: :development
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - ">="
39
+ - - '='
40
40
  - !ruby/object:Gem::Version
41
- version: '0'
41
+ version: 1.17.3
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: rake
44
44
  requirement: !ruby/object:Gem::Requirement
@@ -97,9 +97,11 @@ files:
97
97
  - Rakefile
98
98
  - fluent-plugin-masking.gemspec
99
99
  - lib/fluent/plugin/filter_masking.rb
100
+ - lib/fluent/plugin/helpers.rb
100
101
  - lib/fluent/plugin/version.rb
101
102
  - test/fields-to-mask
102
103
  - test/test_filter_masking.rb
104
+ - test/test_helpers.rb
103
105
  homepage: https://github.com/PayU/fluent-plugin-masking
104
106
  licenses:
105
107
  - Apache-2.0
@@ -119,7 +121,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
119
121
  - !ruby/object:Gem::Version
120
122
  version: '0'
121
123
  requirements: []
122
- rubygems_version: 3.0.4
124
+ rubyforge_project:
125
+ rubygems_version: 2.5.2.3
123
126
  signing_key:
124
127
  specification_version: 4
125
128
  summary: Fluentd filter plugin to mask sensitive or privacy records with `*******`
@@ -128,3 +131,4 @@ summary: Fluentd filter plugin to mask sensitive or privacy records with `******
128
131
  test_files:
129
132
  - test/fields-to-mask
130
133
  - test/test_filter_masking.rb
134
+ - test/test_helpers.rb