fluent-plugin-jfrog-siem 0.1.4 → 0.1.9

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
2
  SHA256:
3
- metadata.gz: 7a6d55c86435d39f27aa0deaf46748366ac837ad4a2417f5a89bfe3711f62c3a
4
- data.tar.gz: 8fc1d3286dab511cd5b6c2cb5358f4edc782dc694d0da052c191858de42057d6
3
+ metadata.gz: e45847f8ff6faf6103f383101c21b8534f1b0bc7c9d8626e8f3a5a172631fb9e
4
+ data.tar.gz: 3f45070df06e498421d9e64ea25a793b700bb6efab6b7a5e878a206214927889
5
5
  SHA512:
6
- metadata.gz: 2fe48f82b2911228d5bf3073ed92d6d4991ee89a5e66c1d56516f6e63a8fe7b4037ec374cb4012b59630cb796435fb02db696582af472cb598ecdf304b670d4a
7
- data.tar.gz: 0c8fa4396ccba483ac3d8931cecbfb6996d65c847a7fdfac749de7156be6d0f2dda4cc8a0e51a6672d210c57d683a5b2cb6d787eb1646ecd1c7efc006e2bc3bd
6
+ metadata.gz: 69f51b464049166d1930578447cd7ca2dd5bd273e013ea94e1eb682b2e664e83e1694db11358c929fda408c714cf3f5c2d3d272aee5b4bee88104c55441e556e
7
+ data.tar.gz: 0a94d81ed3741bbbffd41aa47e5781becb956337675261bb00eea4f4de2c9bcc41809fe212c6abb21a817b5626f9ff03db5be07e262ce0dde9093efa9c68c17a
data/README.md CHANGED
@@ -68,13 +68,19 @@ Splunk:
68
68
 
69
69
  Splunk setup can be found at [README.](https://github.com/jfrog/log-analytics-splunk/blob/master/README.md)
70
70
  ````text
71
- wget https://raw.githubusercontent.com/jfrog/log-analytics/master/fluentd/plugins/input/fluent-plugin-jfrog-siem/splunk.conf
71
+ wget https://raw.githubusercontent.com/jfrog/log-analytics-splunk/master/siem/splunk_siem.conf
72
72
  ````
73
73
  Elasticsearch:
74
74
 
75
75
  Elasticsearch Kibana setup can be found at [README.](https://github.com/jfrog/log-analytics-elastic/blob/master/README.md)
76
76
  ````text
77
- wget https://raw.githubusercontent.com/jfrog/log-analytics/master/fluentd/plugins/input/fluent-plugin-jfrog-siem/elastic.conf
77
+ wget https://raw.githubusercontent.com/jfrog/log-analytics-elastic/master/siem/elastic_siem.conf
78
+ ````
79
+ Datadog:
80
+
81
+ Datadog setup can be found at [README.](https://github.com/jfrog/log-analytics-datadog/blob/master/README.md)
82
+ ````text
83
+ wget https://raw.githubusercontent.com/jfrog/log-analytics-datadog/master/siem/datadog_siem.conf
78
84
  ````
79
85
 
80
86
  #### Configuration parameters
@@ -3,7 +3,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
3
 
4
4
  Gem::Specification.new do |spec|
5
5
  spec.name = "fluent-plugin-jfrog-siem"
6
- spec.version = "0.1.4"
6
+ spec.version = "0.1.9"
7
7
  spec.authors = ["John Peterson", "Mahitha Byreddy"]
8
8
  spec.email = ["johnp@jfrog.com", "mahithab@jfrog.com"]
9
9
 
@@ -30,7 +30,8 @@ module Fluent
30
30
  # `:default` means that the parameter is optional.
31
31
  config_param :tag, :string, default: ""
32
32
  config_param :jpd_url, :string, default: ""
33
- config_param :access_token, :string, default: ""
33
+ config_param :username, :string, default: ""
34
+ config_param :apikey, :string, default: ""
34
35
  config_param :pos_file, :string, default: ""
35
36
  config_param :batch_size, :integer, default: 25
36
37
  config_param :thread_count, :integer, default: 5
@@ -50,8 +51,12 @@ module Fluent
50
51
  raise Fluent::ConfigError, "Must define the JPD URL to pull Xray SIEM violations."
51
52
  end
52
53
 
53
- if @access_token == ""
54
- raise Fluent::ConfigError, "Must define the access token to use for authentication."
54
+ if @username == ""
55
+ raise Fluent::ConfigError, "Must define the username to use for authentication."
56
+ end
57
+
58
+ if @apikey == ""
59
+ raise Fluent::ConfigError, "Must define the API Key to use for authentication."
55
60
  end
56
61
 
57
62
  if @pos_file == ""
@@ -89,7 +94,7 @@ module Fluent
89
94
 
90
95
 
91
96
  def run
92
- call_home(@jpd_url, @access_token)
97
+ call_home(@jpd_url)
93
98
  # runs the violation pull
94
99
  last_created_date_string = get_last_item_create_date()
95
100
  begin
@@ -99,11 +104,12 @@ module Fluent
99
104
  end
100
105
  offset_count=1
101
106
  left_violations=0
107
+ waiting_for_violations = false
102
108
  xray_json={"filters": { "created_from": last_created_date }, "pagination": {"order_by": "created","limit": @batch_size ,"offset": offset_count } }
103
109
 
104
110
  while true
105
111
  # Grab the batch of records
106
- resp=get_xray_violations(xray_json, @jpd_url, @access_token)
112
+ resp=get_xray_violations(xray_json, @jpd_url)
107
113
  number_of_violations = JSON.parse(resp)['total_violations']
108
114
  if left_violations <= 0
109
115
  left_violations = number_of_violations
@@ -120,8 +126,22 @@ module Fluent
120
126
 
121
127
  # Determine if we need to persist this record or not
122
128
  persistItem = true
123
- if created_date <= last_created_date
124
- persistItem = false
129
+ if waiting_for_violations
130
+ if created_date <= last_created_date
131
+ # "not persisting it - waiting for violations"
132
+ # waiting and same last timestamp (left violations in batch)
133
+ persistItem = false
134
+ end
135
+ if created_date > last_created_date
136
+ # new violation while waiting
137
+ persistItem = true
138
+ waiting_for_violations = false
139
+ end
140
+ else
141
+ if created_date < last_created_date
142
+ # "persisting everything"
143
+ persistItem = true
144
+ end
125
145
  end
126
146
 
127
147
  # Publish the record to fluentd
@@ -150,7 +170,7 @@ module Fluent
150
170
  thread_pool = Thread.pool(thread_count)
151
171
  thread_pool.process {
152
172
  for xray_violation_url in xray_violation_urls_list do
153
- pull_violation_details(xray_violation_url, @access_token)
173
+ pull_violation_details(xray_violation_url)
154
174
  end
155
175
  }
156
176
  thread_pool.shutdown
@@ -158,9 +178,11 @@ module Fluent
158
178
  # reduce left violations by jump size (not all batches have full item count??)
159
179
  left_violations = left_violations - @batch_size
160
180
  if left_violations <= 0
181
+ waiting_for_violations = true
161
182
  sleep(@wait_interval)
162
183
  else
163
184
  # Grab the next record to process for the violation details url
185
+ waiting_for_violations = false
164
186
  offset_count = offset_count + 1
165
187
  xray_json={"filters": { "created_from": last_created_date_string }, "pagination": {"order_by": "created","limit": @batch_size , "offset": offset_count } }
166
188
  end
@@ -177,48 +199,53 @@ module Fluent
177
199
  end
178
200
 
179
201
  #call home functionality
180
- def call_home(jpd_url, access_token)
202
+ def call_home(jpd_url)
181
203
  call_home_json = { "productId": "jfrogLogAnalytics/v0.5.1", "features": [ { "featureId": "Platform/Xray" }, { "featureId": "Channel/xrayeventsiem" } ] }
182
204
  response = RestClient::Request.new(
183
205
  :method => :post,
184
206
  :url => jpd_url + "/artifactory/api/system/usage",
185
207
  :payload => call_home_json.to_json,
186
- :headers => { :accept => :json, :content_type => :json, Authorization:'Bearer ' + access_token }
208
+ :user => @username,
209
+ :password => @apikey,
210
+ :headers => { :accept => :json, :content_type => :json}
187
211
  ).execute do |response, request, result|
188
212
  puts "Posting call home information"
189
213
  end
190
214
  end
191
215
 
192
216
  # queries the xray API for violations based upon the input json
193
- def get_xray_violations_detail(xray_violation_detail_url, access_token)
217
+ def get_xray_violations_detail(xray_violation_detail_url)
194
218
  response = RestClient::Request.new(
195
219
  :method => :get,
196
220
  :url => xray_violation_detail_url,
197
- headers: {Authorization:'Bearer ' + access_token}
221
+ :user => @username,
222
+ :password => @apikey
198
223
  ).execute do |response, request, result|
199
224
  case response.code
200
225
  when 200
201
226
  return response.to_str
202
227
  else
203
- raise Fluent::StandardError, "Cannot reach Artifactory URL to pull Xray SIEM violations."
228
+ raise Fluent::ConfigError, "Cannot reach Artifactory URL to pull Xray SIEM violations."
204
229
  end
205
230
  end
206
231
  end
207
232
 
208
233
 
209
234
  # queries the xray API for violations based upon the input json
210
- def get_xray_violations(xray_json, jpd_url, access_token)
235
+ def get_xray_violations(xray_json, jpd_url)
211
236
  response = RestClient::Request.new(
212
237
  :method => :post,
213
238
  :url => jpd_url + "/xray/api/v1/violations",
214
239
  :payload => xray_json.to_json,
215
- :headers => { :accept => :json, :content_type => :json, Authorization:'Bearer ' + access_token }
240
+ :user => @username,
241
+ :password => @apikey,
242
+ :headers => { :accept => :json, :content_type => :json}
216
243
  ).execute do |response, request, result|
217
244
  case response.code
218
245
  when 200
219
246
  return response.to_str
220
247
  else
221
- raise Fluent::StandardError, "Cannot reach Artifactory URL to pull Xray SIEM violations."
248
+ raise Fluent::ConfigError, "Cannot reach Artifactory URL to pull Xray SIEM violations."
222
249
  end
223
250
  end
224
251
  end
@@ -226,44 +253,72 @@ module Fluent
226
253
  # normalizes Xray data according to common information models for all log-vendors
227
254
  def data_normalization(detailResp)
228
255
  detailResp_json = JSON.parse(detailResp)
229
- properties = detailResp_json['properties']
230
256
  cve = []
231
257
  cvss_v2_list = []
232
258
  cvss_v3_list = []
233
- for index in 0..properties.length-1 do
234
- if properties[index].key?('cve')
235
- cve.push(properties[index]['cve'])
259
+ policy_list = []
260
+ rule_list = []
261
+ impacted_artifact_url_list = []
262
+ if detailResp_json.key?('properties')
263
+ properties = detailResp_json['properties']
264
+ for index in 0..properties.length-1 do
265
+ if properties[index].key?('cve')
266
+ cve.push(properties[index]['cve'])
267
+ end
268
+ if properties[index].key?('cvss_v2')
269
+ cvss_v2_list.push(properties[index]['cvss_v2'])
270
+ end
271
+ if properties[index].key?('cvss_v3')
272
+ cvss_v3_list.push(properties[index]['cvss_v3'])
273
+ end
236
274
  end
237
- if properties[index].key?('cvss_v2')
238
- cvss_v2_list.push(properties[index]['cvss_v2'])
275
+
276
+ detailResp_json["cve"] = cve.sort.reverse[0]
277
+ cvss_v2 = cvss_v2_list.sort.reverse[0]
278
+ cvss_v3 = cvss_v3_list.sort.reverse[0]
279
+ if !cvss_v3.nil?
280
+ cvss = cvss_v3
281
+ elsif !cvss_v2.nil?
282
+ cvss = cvss_v2
239
283
  end
240
- if properties[index].key?('cvss_v3')
241
- cvss_v3_list.push(properties[index]['cvss_v3'])
284
+ cvss_score = cvss[0..2]
285
+ cvss_version = cvss.split(':')[1][0..2]
286
+ detailResp_json["cvss_score"] = cvss_score
287
+ detailResp_json["cvss_version"] = cvss_version
288
+ end
289
+
290
+ if detailResp_json.key?('matched_policies')
291
+ matched_policies = detailResp_json['matched_policies']
292
+ for index in 0..matched_policies.length-1 do
293
+ if matched_policies[index].key?('policy')
294
+ policy_list.push(matched_policies[index]['policy'])
295
+ end
296
+ if matched_policies[index].key?('rule')
297
+ rule_list.push(matched_policies[index]['rule'])
298
+ end
242
299
  end
300
+ detailResp_json['policies'] = policy_list
301
+ detailResp_json['rules'] = rule_list
243
302
  end
244
- detailResp_json["cve"] = cve.sort.reverse[0]
245
- cvss_v2 = cvss_v2_list.sort.reverse[0]
246
- cvss_v3 = cvss_v3_list.sort.reverse[0]
247
- if cvss_v3.length() > 0
248
- cvss = cvss_v3
249
- elsif cvss_v2.length() > 0
250
- cvss = cvss_v2
303
+
304
+ impacted_artifacts = detailResp_json['impacted_artifacts']
305
+ for impacted_artifact in impacted_artifacts do
306
+ matchdata = impacted_artifact.match /default\/(?<repo_name>[^\/]*)\/(?<path>.*)/
307
+ impacted_artifact_url = matchdata['repo_name'] + ":" + matchdata['path'] + " "
308
+ impacted_artifact_url_list.append(impacted_artifact_url)
251
309
  end
252
- cvss_score = cvss[0..2]
253
- cvss_version = cvss.split(':')[1][0..2]
254
- detailResp_json["cvss_score"] = cvss_score
255
- detailResp_json["cvss_version"] = cvss_version
310
+ detailResp_json['impacted_artifacts_url'] = impacted_artifact_url_list
256
311
  return detailResp_json
257
312
  end
258
313
 
259
- def pull_violation_details(xray_violation_detail_url, access_token)
314
+ def pull_violation_details(xray_violation_detail_url)
260
315
  begin
261
- detailResp=get_xray_violations_detail(xray_violation_detail_url, access_token)
316
+ detailResp=get_xray_violations_detail(xray_violation_detail_url)
262
317
  time = Fluent::Engine.now
263
318
  detailResp_json = data_normalization(detailResp)
264
319
  router.emit(@tag, time, detailResp_json)
265
320
  rescue
266
- raise Fluent::StandardError, "Error pulling violation details url #{xray_violation_detail_url}"
321
+ raise Fluent::ConfigError, "Error pulling violation details url #{xray_violation_detail_url}"
267
322
  end
268
323
  end
269
324
 
@@ -13,8 +13,9 @@ class JfrogSiemInputTest < Test::Unit::TestCase
13
13
  # Default configuration for tests
14
14
  CONFIG = %[
15
15
  tag "test_tag"
16
- jpd_url <jpd_url>
17
- access_token <access_token>
16
+ jpd_url "http://dd-siem-unified-15-rt.jfrog.tech"
17
+ username "admin"
18
+ apikey "AKCp8jQ8tAb2tqC6jXH7J1qLShXnjorD5XhFkvqUhN78WMLmvfTx5GNuD9B8uEXnGyruBCzYk"
18
19
  pos_file "test_pos.txt"
19
20
  ]
20
21
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-jfrog-siem
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Peterson
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-02-02 00:00:00.000000000 Z
12
+ date: 2021-05-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler