logstash-input-beats 2.1.4 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,102 @@
1
+ # encoding: utf-8
2
+ require "logstash/inputs/beats"
3
+ require "logstash/json"
4
+ require "fileutils"
5
+ require_relative "../support/flores_extensions"
6
+ require_relative "../support/file_helpers"
7
+ require_relative "../support/integration_shared_context"
8
+ require_relative "../support/client_process_helpers"
9
+ require "spec_helper"
10
+
11
+ LSF_BINARY = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "vendor", "logstash-forwarder", "logstash-forwarder"))
12
+
13
+ xdescribe "Logstash-Forwarder", :integration => true do
14
+ include ClientProcessHelpers
15
+
16
+ before :all do
17
+ unless File.exist?(LSF_BINARY)
18
+ raise "Cannot find `logstash-forwarder` binary in `vendor/logstash-forwarder` Did you run `bundle exec rake test:integration:setup` before running the integration suite?"
19
+ end
20
+ end
21
+
22
+ let(:client_wait_time) { 5 }
23
+ include FileHelpers
24
+ include_context "beats configuration"
25
+
26
+ # Filebeat related variables
27
+ let(:cmd) { [lsf_exec, "-config", lsf_config_path] }
28
+
29
+ let(:lsf_exec) { LSF_BINARY }
30
+ let(:registry_file) { File.expand_path(File.join(File.dirname(__FILE__), "..", "..", ".logstash-forwarder")) }
31
+ let_tmp_file(:lsf_config_path) { lsf_config }
32
+ let(:log_file) { f = Stud::Temporary.file; f.close; f.path }
33
+ let(:lsf_config) do
34
+ <<-CONFIG
35
+ {
36
+ "network": {
37
+ "servers": [ "#{host}:#{port}" ],
38
+ "ssl ca": "#{certificate_authorities}"
39
+ },
40
+ "files": [
41
+ { "paths": [ "#{log_file}" ] }
42
+ ]
43
+ }
44
+ CONFIG
45
+ end
46
+ #
47
+
48
+ before :each do
49
+ FileUtils.rm_rf(registry_file) # ensure clean state between runs
50
+ start_client
51
+ sleep(1)
52
+ # let LSF start and than write the logs
53
+ File.open(log_file, "a") do |f|
54
+ f.write(events.join("\n") + "\n")
55
+ end
56
+ end
57
+
58
+ after :each do
59
+ stop_client
60
+ end
61
+
62
+ context "Plain TCP" do
63
+ include ClientProcessHelpers
64
+ let(:certificate_authorities) { "" }
65
+
66
+ it "should not send any events" do
67
+ expect(queue.size).to eq(0), @execution_output
68
+ end
69
+ end
70
+
71
+ context "TLS" do
72
+ context "Server Verification" do
73
+ let(:input_config) do
74
+ super.merge({
75
+ "ssl" => true,
76
+ "ssl_certificate" => certificate_file,
77
+ "ssl_key" => certificate_key_file,
78
+ "target_field_for_codec" => "line"
79
+ })
80
+ end
81
+
82
+ let(:certificate_data) { Flores::PKI.generate }
83
+ let_tmp_file(:certificate_file) { certificate_data.first }
84
+ let_tmp_file(:certificate_key_file) { certificate_data.last }
85
+ let(:certificate_authorities) { certificate_file }
86
+
87
+ context "self signed certificate" do
88
+ include_examples "send events" do
89
+ end
90
+ end
91
+
92
+ context "invalid CA on the client" do
93
+ let(:invalid_data) { Flores::PKI.generate }
94
+ let(:certificate_authorities) { invalid_data.first }
95
+
96
+ it "should not send any events" do
97
+ expect(queue.size).to eq(0), @execution_output
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -6,27 +6,47 @@ require "flores/pki"
6
6
  require "fileutils"
7
7
  require "thread"
8
8
  require "spec_helper"
9
+ require_relative "./support/file_helpers"
10
+ require_relative "./support/flores_extensions"
9
11
 
10
12
  Thread.abort_on_exception = true
11
13
  describe "A client" do
14
+ include FileHelpers
15
+
12
16
  let(:certificate) { Flores::PKI.generate }
13
- let(:certificate_file_crt) { "certificate.crt" }
14
- let(:certificate_file_key) { "certificate.key" }
17
+ let(:certificate_file_crt) do
18
+ p = Stud::Temporary.file
19
+ p.write(certificate.first.to_s)
20
+ p.close
21
+ p.path
22
+ end
23
+
24
+ let(:certificate_file_key) do
25
+ p = Stud::Temporary.file
26
+ p.write(certificate.last.to_s)
27
+ p.close
28
+ p.path
29
+ end
15
30
  let(:port) { Flores::Random.integer(1024..65335) }
16
31
  let(:tcp_port) { port + 1 }
17
32
  let(:host) { "127.0.0.1" }
18
33
  let(:queue) { [] }
34
+ let(:config_ssl) do
35
+ {
36
+ :port => port,
37
+ :address => host,
38
+ :ssl_certificate => certificate_file_crt,
39
+ :ssl_key => certificate_file_key
40
+ }
41
+ end
19
42
 
20
- before :each do
21
- expect(File).to receive(:read).at_least(1).with(certificate_file_crt) { certificate.first.to_s }
22
- expect(File).to receive(:read).at_least(1).with(certificate_file_key) { certificate.last.to_s }
23
-
24
- tcp_server = Lumberjack::Beats::Server.new(:port => tcp_port, :address => host, :ssl => false)
43
+ let(:config_tcp) do
44
+ { :port => tcp_port, :address => host, :ssl => false }
45
+ end
25
46
 
26
- ssl_server = Lumberjack::Beats::Server.new(:port => port,
27
- :address => host,
28
- :ssl_certificate => certificate_file_crt,
29
- :ssl_key => certificate_file_key)
47
+ before :each do
48
+ tcp_server = Lumberjack::Beats::Server.new(config_tcp)
49
+ ssl_server = Lumberjack::Beats::Server.new(config_ssl)
30
50
 
31
51
  @tcp_server = Thread.new do
32
52
  tcp_server.run { |data, identity_stream| queue << [data, identity_stream] }
@@ -42,7 +62,7 @@ describe "A client" do
42
62
  # parser for TCP based server trip.
43
63
  # Connection is closed by Server connection object
44
64
  end
45
- end
65
+ end
46
66
  end
47
67
  end
48
68
 
@@ -160,62 +180,334 @@ describe "A client" do
160
180
  end
161
181
  end
162
182
 
163
- context "using ssl encrypted connection" do
164
- context "with a valid certificate" do
165
- it "successfully connect to the server" do
166
- expect {
167
- Lumberjack::Beats::Client.new(:port => port,
168
- :host => host,
169
- :addresses => host,
170
- :ssl_certificate => certificate_file_crt)
171
- }.not_to raise_error
183
+ context "using TLS/SSL encrypted connection" do
184
+ context "without a ca chain" do
185
+ context "with a valid certificate" do
186
+ it "successfully connect to the server" do
187
+ expect {
188
+ Lumberjack::Beats::Client.new(:port => port,
189
+ :host => host,
190
+ :addresses => host,
191
+ :ssl_certificate_authorities => certificate_file_crt)
192
+ }.not_to raise_error
193
+ end
194
+
195
+ it "should fail connecting to plain tcp server" do
196
+ expect {
197
+ Lumberjack::Beats::Client.new(:port => tcp_port,
198
+ :host => host,
199
+ :addresses => host,
200
+ :ssl_certificate_authorities => certificate_file_crt)
201
+ }.to raise_error(OpenSSL::SSL::SSLError)
202
+ end
172
203
  end
173
204
 
174
- it "should fail connecting to plain tcp server" do
175
- expect {
176
- Lumberjack::Beats::Client.new(:port => tcp_port,
177
- :host => host,
178
- :addresses => host,
179
- :ssl_certificate => certificate_file_crt)
180
- }.to raise_error(OpenSSL::SSL::SSLError)
181
- end
182
- end
205
+ context "with an invalid certificate" do
206
+ let(:invalid_certificate) { Flores::PKI.generate }
207
+ let(:invalid_certificate_file) { Stud::Temporary.file.path }
183
208
 
184
- context "with an invalid certificate" do
185
- let(:invalid_certificate) { Flores::PKI.generate }
186
- let(:invalid_certificate_file) { "invalid.crt" }
209
+ it "should refuse to connect" do
210
+ expect {
211
+ Lumberjack::Beats::Client.new(:port => port,
212
+ :host => host,
213
+ :addresses => host,
214
+ :ssl_certificate_authorities => invalid_certificate_file)
187
215
 
188
- before do
189
- expect(File).to receive(:read).with(invalid_certificate_file) { invalid_certificate.first.to_s }
216
+ }.to raise_error(OpenSSL::SSL::SSLError, /certificate verify failed/)
217
+ end
190
218
  end
191
219
 
192
- it "should refuse to connect" do
193
- expect {
220
+ context "When transmitting a payload" do
221
+ let(:client) do
194
222
  Lumberjack::Beats::Client.new(:port => port,
195
223
  :host => host,
196
224
  :addresses => host,
197
- :ssl_certificate => invalid_certificate_file)
225
+ :ssl_certificate_authorities => certificate_file_crt)
226
+ end
227
+
228
+ context "json" do
229
+ let(:options) { super.merge({ :json => true }) }
230
+ include_examples "transmit payloads"
231
+ end
198
232
 
199
- }.to raise_error(OpenSSL::SSL::SSLError, /certificate verify failed/)
233
+ context "v1 frame" do
234
+ include_examples "transmit payloads"
235
+ end
200
236
  end
201
237
  end
238
+ end
202
239
 
203
- context "When transmitting a payload" do
204
- let(:client) do
205
- Lumberjack::Beats::Client.new(:port => port,
206
- :host => host,
207
- :addresses => host,
208
- :ssl_certificate => certificate_file_crt)
240
+ def write_to_tmp_file(content)
241
+ file = Stud::Temporary.file
242
+ file.write(content.to_s)
243
+ file.close
244
+ file.path
245
+ end
246
+
247
+ context "Mutual validation" do
248
+ let(:host) { "localhost" }
249
+ let(:certificate_duration) { Flores::Random.number(1000..2000) }
250
+ let(:client) { Lumberjack::Beats::Client.new(options) }
251
+ let(:options) { { :ssl => true, :port => port, :addresses => host } }
252
+ let(:config_ssl) do
253
+ {
254
+ :port => port,
255
+ :address => host,
256
+ :ssl => true,
257
+ :ssl_verify_mode => "force_peer"
258
+ }
259
+ end
260
+
261
+ context "with a self signed certificate" do
262
+ let(:certificate) { Flores::PKI.generate }
263
+ let_tmp_file(:certificate_file) { certificate.first }
264
+ let_tmp_file(:certificate_key_file) { certificate.last }
265
+ let(:options) do
266
+ super.merge({ :ssl_certificate => certificate_file,
267
+ :ssl_certificate_key => certificate_key_file,
268
+ :ssl_certificate_authorities => certificate_file })
209
269
  end
210
270
 
211
- context "json" do
212
- let(:options) { super.merge({ :json => true }) }
271
+ let(:config_ssl) do
272
+ super.merge({ :ssl_certificate_authorities => certificate_file,
273
+ :ssl_certificate => certificate_file,
274
+ :ssl_key => certificate_key_file })
275
+ end
276
+
277
+ include_examples "transmit payloads"
278
+ end
279
+
280
+ context "with certificate authorities" do
281
+ let(:keysize) { 1024 }
282
+ let(:exponent) { 65537 }
283
+ let(:root_ca) { Flores::PKI.generate("CN=root.logstash") }
284
+ let(:root_ca_certificate) { root_ca.first }
285
+ let(:root_ca_key) { root_ca.last }
286
+ let_tmp_file(:root_ca_certificate_file) { root_ca_certificate }
287
+
288
+ context "directly signing a certificate" do
289
+ let(:client_certificate_key) { OpenSSL::PKey::RSA.generate(keysize, exponent) }
290
+ let_tmp_file(:client_certificate_key_file) { client_certificate_key }
291
+ let(:client_certificate) do
292
+ csr = Flores::PKI::CertificateSigningRequest.new
293
+ csr.start_time = Time.now
294
+ csr.expire_time = csr.start_time + certificate_duration
295
+ csr.public_key = client_certificate_key.public_key
296
+ csr.subject = "CN=localhost"
297
+ csr.signing_key = root_ca_key
298
+ csr.signing_certificate = root_ca_certificate
299
+ csr.want_signature_ability = false
300
+ csr.create
301
+ end
302
+ let_tmp_file(:client_certificate_file) { client_certificate }
303
+
304
+ let(:server_certificate_key) { OpenSSL::PKey::RSA.generate(keysize, exponent) }
305
+ let(:server_certificate_key_file) { write_to_tmp_file(server_certificate_key) }
306
+ let(:server_certificate) do
307
+ csr = Flores::PKI::CertificateSigningRequest.new
308
+ csr.start_time = Time.now
309
+ csr.expire_time = csr.start_time + certificate_duration
310
+ csr.public_key = server_certificate_key.public_key
311
+ csr.subject = "CN=localhost"
312
+ csr.signing_key = root_ca_key
313
+ csr.signing_certificate = root_ca_certificate
314
+ csr.want_signature_ability = false
315
+ csr.create
316
+ end
317
+ let_tmp_file(:server_certificate_file) { server_certificate }
318
+
319
+ let(:options) do
320
+ super.merge({ :ssl_certificate => client_certificate_file,
321
+ :ssl_certificate_key => client_certificate_key_file,
322
+ :ssl_certificate_authorities => root_ca_certificate_file })
323
+ end
324
+
325
+ let(:config_ssl) do
326
+ super.merge({ :ssl_certificate_authorities => root_ca_certificate_file,
327
+ :ssl_certificate => server_certificate_file,
328
+ :ssl_key => server_certificate_key_file,
329
+ :verify_mode => :force_peer })
330
+ end
331
+
213
332
  include_examples "transmit payloads"
214
333
  end
215
334
 
216
- context "v1 frame" do
335
+ # Doesnt work because of this issues in `jruby-openssl`
336
+ # https://github.com/jruby/jruby-openssl/issues/84
337
+ xcontext "CA given with client providing intermediate and client certificate" do
338
+ let(:intermediate_certificate_key) { OpenSSL::PKey::RSA.generate(keysize, exponent) }
339
+ let_tmp_file(:intermediate_certificate_key_file) { intermediate_certificate_key }
340
+ let(:intermediate_certificate) do
341
+ csr = Flores::PKI::CertificateSigningRequest.new
342
+ csr.start_time = Time.now
343
+ csr.expire_time = csr.start_time + certificate_duration
344
+ csr.public_key = intermediate_certificate_key.public_key
345
+ csr.subject = "CN=intermediate 1"
346
+ csr.signing_key = root_ca_key
347
+ csr.signing_certificate = root_ca_certificate
348
+ csr.want_signature_ability = true
349
+ csr.create
350
+ end
351
+ let_tmp_file(:intermediate_certificate_file) { intermediate_certificate }
352
+ let(:client_certificate_key) { OpenSSL::PKey::RSA.generate(keysize, exponent) }
353
+ let_tmp_file(:client_certificate_key_file) { client_certificate_key }
354
+ let(:client_certificate) do
355
+ csr = Flores::PKI::CertificateSigningRequest.new
356
+ csr.start_time = Time.now
357
+ csr.expire_time = csr.start_time + certificate_duration
358
+ csr.public_key = client_certificate_key.public_key
359
+ csr.subject = "CN=localhost"
360
+ csr.signing_key = intermediate_certificate_key
361
+ csr.signing_certificate = intermediate_certificate
362
+ csr.want_signature_ability = false
363
+ csr.create
364
+ end
365
+ let_tmp_file(:client_certificate_file) { client_certificate }
366
+
367
+ let(:server_certificate_key) { OpenSSL::PKey::RSA.generate(keysize, exponent) }
368
+ let_tmp_file(:server_certificate_key_file) { server_certificate_key }
369
+ let(:server_certificate) do
370
+ csr = Flores::PKI::CertificateSigningRequest.new
371
+ csr.start_time = Time.now
372
+ csr.expire_time = csr.start_time + certificate_duration
373
+ csr.public_key = server_certificate_key.public_key
374
+ csr.subject = "CN=localhost"
375
+ csr.signing_key = intermediate_certificate_key
376
+ csr.signing_certificate = intermediate_certificate
377
+ csr.want_signature_ability = false
378
+ csr.create
379
+ end
380
+ let_tmp_file(:server_certificate_file) { server_certificate }
381
+ let_tmp_file(:certificate_chain_file) { Flores::PKI.chain_certificates(root_ca_certificate, intermediate_certificate) }
382
+
383
+ let(:options) do
384
+ super.merge({ :ssl_certificate => client_certificate_file,
385
+ :ssl_certificate_key => client_certificate_key_file,
386
+ :ssl_certificate_authorities => certificate_chain_file })
387
+ end
388
+
389
+ let(:config_ssl) do
390
+ super.merge({ :ssl_certificate_authorities => certificate_chain_file,
391
+ :ssl_certificate => server_certificate_file,
392
+ :ssl_key => server_certificate_key_file,
393
+ :verify_mode => :force_peer })
394
+
395
+
396
+ end
397
+
217
398
  include_examples "transmit payloads"
218
399
  end
400
+
401
+ context "Mutiple CA different clients" do
402
+ let(:secondary_root_ca) { Flores::PKI.generate("CN=secondary.root.logstash") }
403
+ let(:secondary_root_ca_certificate) { root_ca.first }
404
+ let(:secondary_root_ca_key) { root_ca.last }
405
+ let_tmp_file(:secondary_root_ca_certificate_file) { root_ca_certificate }
406
+
407
+ let(:secondary_client_certificate_key) { OpenSSL::PKey::RSA.generate(keysize, exponent) }
408
+ let(:secondary_client_certificate_key_file) { write_to_tmp_file(secondary_client_certificate_key) }
409
+ let(:secondary_client_certificate) do
410
+ csr = Flores::PKI::CertificateSigningRequest.new
411
+ csr.start_time = Time.now
412
+ csr.expire_time = csr.start_time + certificate_duration
413
+ csr.public_key = secondary_client_certificate_key.public_key
414
+ csr.subject = "CN=localhost"
415
+ csr.signing_key = secondary_root_ca_key
416
+ csr.signing_certificate = secondary_root_ca_certificate
417
+ csr.want_signature_ability = false
418
+ csr.create
419
+ end
420
+ let_tmp_file(:secondary_client_certificate_file) { secondary_client_certificate }
421
+ let(:client_certificate_key) { OpenSSL::PKey::RSA.generate(keysize, exponent) }
422
+ let_tmp_file(:client_certificate_key_file) { client_certificate_key }
423
+ let(:client_certificate) do
424
+ csr = Flores::PKI::CertificateSigningRequest.new
425
+ csr.start_time = Time.now
426
+ csr.expire_time = csr.start_time + certificate_duration
427
+ csr.public_key = client_certificate_key.public_key
428
+ csr.subject = "CN=localhost"
429
+ csr.signing_key = root_ca_key
430
+ csr.signing_certificate = root_ca_certificate
431
+ csr.want_signature_ability = false
432
+ csr.create
433
+ end
434
+ let_tmp_file(:client_certificate_file) { client_certificate }
435
+
436
+ let(:server_certificate_key) { OpenSSL::PKey::RSA.generate(keysize, exponent) }
437
+ let_tmp_file(:server_certificate_key_file) { server_certificate_key }
438
+ let(:server_certificate) do
439
+ csr = Flores::PKI::CertificateSigningRequest.new
440
+ csr.start_time = Time.now
441
+ csr.expire_time = csr.start_time + certificate_duration
442
+ csr.public_key = server_certificate_key.public_key
443
+ csr.subject = "CN=localhost"
444
+ csr.signing_key = root_ca_key
445
+ csr.signing_certificate = root_ca_certificate
446
+ csr.want_signature_ability = false
447
+ csr.create
448
+ end
449
+ let_tmp_file(:server_certificate_file) { server_certificate }
450
+
451
+ shared_examples "multiples client" do
452
+ context "client from primary CA" do
453
+ let(:options) do
454
+ super.merge({ :ssl_certificate => client_certificate_file,
455
+ :ssl_certificate_key => client_certificate_key_file,
456
+ :ssl_certificate_authorities => [root_ca_certificate_file] })
457
+ end
458
+
459
+ include_examples "transmit payloads"
460
+ end
461
+
462
+ context "client from secondary CA" do
463
+ let(:options) do
464
+ super.merge({ :ssl_certificate => secondary_client_certificate_file,
465
+ :ssl_certificate_key => secondary_client_certificate_key_file,
466
+ :ssl_certificate_authorities => [root_ca_certificate_file] })
467
+ end
468
+
469
+ include_examples "transmit payloads"
470
+ end
471
+ end
472
+
473
+ context "when the CA are defined individually in the configuration" do
474
+ let(:config_ssl) do
475
+ super.merge({ :ssl_certificate_authorities => [secondary_root_ca_certificate_file, root_ca_certificate_file],
476
+ :ssl_certificate => server_certificate_file,
477
+ :ssl_key => server_certificate_key_file,
478
+ :verify_mode => "force_peer" })
479
+ end
480
+
481
+ include_examples "multiples client"
482
+ end
483
+
484
+ context "when the CA are defined by a path in the configuration" do
485
+ let(:ca_path) do
486
+ p = Stud::Temporary.directory
487
+
488
+ # Doing this here make sure the path is populated when the server
489
+ # is started in the main before block
490
+ FileUtils.mkdir_p(p)
491
+ FileUtils.cp(secondary_root_ca_certificate_file, p)
492
+ FileUtils.cp(root_ca_certificate_file, p)
493
+
494
+ p
495
+ end
496
+
497
+ after :each do
498
+ FileUtils.rm_rf(ca_path)
499
+ end
500
+
501
+ let(:config_ssl) do
502
+ super.merge({ :ssl_certificate_authorities => ca_path,
503
+ :ssl_certificate => server_certificate_file,
504
+ :ssl_key => server_certificate_key_file,
505
+ :verify_mode => "force_peer" })
506
+ end
507
+
508
+ include_examples "multiples client"
509
+ end
510
+ end
219
511
  end
220
512
  end
221
513
  end