From 15f23ee9457e4450bb5e0779d860d545fe4bbd11 Mon Sep 17 00:00:00 2001 From: hisagar <32439113+Hisagar@users.noreply.github.com> Date: Mon, 31 Jan 2022 22:46:33 +0530 Subject: [PATCH 01/12] private_key_path, private_key_passphrase, allow_self_signed_cert, fqdn and tls_version config_param added for mutual_tls auth --- lib/fluent/plugin/out_syslog_rfc5424.rb | 16 ++++++++- test/plugin/out_syslog_rfc5424_spec.rb | 45 ++++++++++++++++++++----- 2 files changed, 52 insertions(+), 9 deletions(-) diff --git a/lib/fluent/plugin/out_syslog_rfc5424.rb b/lib/fluent/plugin/out_syslog_rfc5424.rb index 49c3ce1..c6e8add 100644 --- a/lib/fluent/plugin/out_syslog_rfc5424.rb +++ b/lib/fluent/plugin/out_syslog_rfc5424.rb @@ -13,6 +13,11 @@ class OutSyslogRFC5424 < Output config_param :transport, :string, default: "tls" config_param :insecure, :bool, default: false config_param :trusted_ca_path, :string, default: nil + config_param :private_key_path, :string, default: nil + config_param :private_key_passphrase, :string, default: nil + config_param :allow_self_signed_cert, :string, default: false + config_param :fqdn, :string, default: nil + config_param :tls_version, :string, default: "TLSv1_2" config_section :format do config_set_default :@type, DEFAULT_FORMATTER end @@ -62,7 +67,16 @@ def socket_options { connect: true } elsif @transport == 'tls' # TODO: make timeouts configurable - { insecure: @insecure, verify_fqdn: !@insecure, cert_paths: @trusted_ca_path } #, connect_timeout: 1, send_timeout: 1, recv_timeout: 1, linger_timeout: 1 } + { + insecure: @insecure, + verify_fqdn: !@insecure, + cert_paths: @trusted_ca_path, + private_key_path: @private_key_path, + private_key_passphrase: @private_key_passphrase, + allow_self_signed_cert: @allow_self_signed_cert, + fqdn: @fqdn, + tls_version: @tls_version, + } #, connect_timeout: 1, send_timeout: 1, recv_timeout: 1, linger_timeout: 1 } else {} end diff --git a/test/plugin/out_syslog_rfc5424_spec.rb b/test/plugin/out_syslog_rfc5424_spec.rb index 684aa26..fb149e1 100644 --- a/test/plugin/out_syslog_rfc5424_spec.rb +++ b/test/plugin/out_syslog_rfc5424_spec.rb @@ -35,9 +35,9 @@ def test_sends_a_message stub(socket).close stub(IO).select(nil, [socket], nil, 1) { ["not an error"] } - + any_instance_of(Fluent::Plugin::OutSyslogRFC5424) do |fluent_plugin| - mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>nil}).returns(socket) + mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :tls_version=>"TLSv1_2"}).returns(socket) end output_driver.run do @@ -55,7 +55,7 @@ def test_reconnects bad_socket = Object.new mock(bad_socket).write_nonblock(@formatted_log) stub(bad_socket).close - + good_socket = Object.new mock(good_socket).write_nonblock(@formatted_log) stub(good_socket).close @@ -64,8 +64,8 @@ def test_reconnects mock(IO).select(nil, [good_socket], nil, 1) { ["not an error"] } any_instance_of(Fluent::Plugin::OutSyslogRFC5424) do |fluent_plugin| - mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>nil}).returns(bad_socket) - mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>nil}).returns(good_socket) + mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :tls_version=>"TLSv1_2"}).returns(bad_socket) + mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :tls_version=>"TLSv1_2"}).returns(good_socket) end output_driver.run(shutdown: false, force_flush_retry: true) do @@ -112,7 +112,7 @@ def test_insecure_tls stub(IO).select(nil, [socket], nil, 1) { ["not an error"] } any_instance_of(Fluent::Plugin::OutSyslogRFC5424) do |fluent_plugin| - mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>true, :verify_fqdn=>false, :cert_paths=>nil}).returns(socket) + mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>true, :verify_fqdn=>false, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :tls_version=>"TLSv1_2"}).returns(socket) end output_driver.run do @@ -136,7 +136,36 @@ def test_secure_tls stub(IO).select(nil, [socket], nil, 1) { ["not an error"] } any_instance_of(Fluent::Plugin::OutSyslogRFC5424) do |fluent_plugin| - mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>"supertrustworthy"}).returns(socket) + mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>"supertrustworthy", :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :tls_version=>"TLSv1_2"}).returns(socket) + end + + output_driver.run do + output_driver.feed("tag", @time, {"log" => "hi"}) + end + end + + def test_secure_mutual_tls + output_driver = create_driver %( + @type syslog_rfc5424 + host example.com + port 123 + transport tls + trusted_ca_path supertrustworthy + private_key_path supertrustworthykey + private_key_passphrase supertrustworthypassphrase + allow_self_signed_cert false + fqdn supertrustworthyfqdn + tls_version "TLSv1_2" + ) + + socket = Object.new + mock(socket).write_nonblock(@formatted_log) + stub(socket).close + + stub(IO).select(nil, [socket], nil, 1) { ["not an error"] } + + any_instance_of(Fluent::Plugin::OutSyslogRFC5424) do |fluent_plugin| + mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>"supertrustworthy", :private_key_path=>"supertrustworthykey", :private_key_passphrase=>"supertrustworthypassphrase", :allow_self_signed_cert=>false, :fqdn=>"supertrustworthyfqdn", :tls_version=>"TLSv1_2"}).returns(socket) end output_driver.run do @@ -158,7 +187,7 @@ def test_close_is_called_on_sockets stub(IO).select(nil, [socket], nil, 1) { ["not an error"] } any_instance_of(Fluent::Plugin::OutSyslogRFC5424) do |fluent_plugin| - mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>nil}).returns(socket) + mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :tls_version=>"TLSv1_2"}).returns(socket) end output_driver.run do From 0edc702e651320e346312ab72abe347840984156 Mon Sep 17 00:00:00 2001 From: hisagar <32439113+Hisagar@users.noreply.github.com> Date: Mon, 31 Jan 2022 22:54:00 +0530 Subject: [PATCH 02/12] tls_version name updated to version --- lib/fluent/plugin/out_syslog_rfc5424.rb | 4 ++-- test/plugin/out_syslog_rfc5424_spec.rb | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/fluent/plugin/out_syslog_rfc5424.rb b/lib/fluent/plugin/out_syslog_rfc5424.rb index c6e8add..54f23f2 100644 --- a/lib/fluent/plugin/out_syslog_rfc5424.rb +++ b/lib/fluent/plugin/out_syslog_rfc5424.rb @@ -17,7 +17,7 @@ class OutSyslogRFC5424 < Output config_param :private_key_passphrase, :string, default: nil config_param :allow_self_signed_cert, :string, default: false config_param :fqdn, :string, default: nil - config_param :tls_version, :string, default: "TLSv1_2" + config_param :version, :string, default: "TLSv1_2" config_section :format do config_set_default :@type, DEFAULT_FORMATTER end @@ -75,7 +75,7 @@ def socket_options private_key_passphrase: @private_key_passphrase, allow_self_signed_cert: @allow_self_signed_cert, fqdn: @fqdn, - tls_version: @tls_version, + version: @version, } #, connect_timeout: 1, send_timeout: 1, recv_timeout: 1, linger_timeout: 1 } else {} diff --git a/test/plugin/out_syslog_rfc5424_spec.rb b/test/plugin/out_syslog_rfc5424_spec.rb index fb149e1..53fe5fe 100644 --- a/test/plugin/out_syslog_rfc5424_spec.rb +++ b/test/plugin/out_syslog_rfc5424_spec.rb @@ -37,7 +37,7 @@ def test_sends_a_message stub(IO).select(nil, [socket], nil, 1) { ["not an error"] } any_instance_of(Fluent::Plugin::OutSyslogRFC5424) do |fluent_plugin| - mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :tls_version=>"TLSv1_2"}).returns(socket) + mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :version=>"TLSv1_2"}).returns(socket) end output_driver.run do @@ -64,8 +64,8 @@ def test_reconnects mock(IO).select(nil, [good_socket], nil, 1) { ["not an error"] } any_instance_of(Fluent::Plugin::OutSyslogRFC5424) do |fluent_plugin| - mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :tls_version=>"TLSv1_2"}).returns(bad_socket) - mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :tls_version=>"TLSv1_2"}).returns(good_socket) + mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :version=>"TLSv1_2"}).returns(bad_socket) + mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :version=>"TLSv1_2"}).returns(good_socket) end output_driver.run(shutdown: false, force_flush_retry: true) do @@ -112,7 +112,7 @@ def test_insecure_tls stub(IO).select(nil, [socket], nil, 1) { ["not an error"] } any_instance_of(Fluent::Plugin::OutSyslogRFC5424) do |fluent_plugin| - mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>true, :verify_fqdn=>false, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :tls_version=>"TLSv1_2"}).returns(socket) + mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>true, :verify_fqdn=>false, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :version=>"TLSv1_2"}).returns(socket) end output_driver.run do @@ -136,7 +136,7 @@ def test_secure_tls stub(IO).select(nil, [socket], nil, 1) { ["not an error"] } any_instance_of(Fluent::Plugin::OutSyslogRFC5424) do |fluent_plugin| - mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>"supertrustworthy", :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :tls_version=>"TLSv1_2"}).returns(socket) + mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>"supertrustworthy", :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :version=>"TLSv1_2"}).returns(socket) end output_driver.run do @@ -155,7 +155,7 @@ def test_secure_mutual_tls private_key_passphrase supertrustworthypassphrase allow_self_signed_cert false fqdn supertrustworthyfqdn - tls_version "TLSv1_2" + version "TLSv1_2" ) socket = Object.new @@ -165,7 +165,7 @@ def test_secure_mutual_tls stub(IO).select(nil, [socket], nil, 1) { ["not an error"] } any_instance_of(Fluent::Plugin::OutSyslogRFC5424) do |fluent_plugin| - mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>"supertrustworthy", :private_key_path=>"supertrustworthykey", :private_key_passphrase=>"supertrustworthypassphrase", :allow_self_signed_cert=>false, :fqdn=>"supertrustworthyfqdn", :tls_version=>"TLSv1_2"}).returns(socket) + mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>"supertrustworthy", :private_key_path=>"supertrustworthykey", :private_key_passphrase=>"supertrustworthypassphrase", :allow_self_signed_cert=>false, :fqdn=>"supertrustworthyfqdn", :version=>"TLSv1_2"}).returns(socket) end output_driver.run do @@ -187,7 +187,7 @@ def test_close_is_called_on_sockets stub(IO).select(nil, [socket], nil, 1) { ["not an error"] } any_instance_of(Fluent::Plugin::OutSyslogRFC5424) do |fluent_plugin| - mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :tls_version=>"TLSv1_2"}).returns(socket) + mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :version=>"TLSv1_2"}).returns(socket) end output_driver.run do From 6903f0b5c9bfeb16e911ac3f1c4281c083c9fd5a Mon Sep 17 00:00:00 2001 From: hisagar <32439113+Hisagar@users.noreply.github.com> Date: Mon, 31 Jan 2022 23:33:40 +0530 Subject: [PATCH 03/12] allow_self_signed_cert type updated --- lib/fluent/plugin/out_syslog_rfc5424.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/fluent/plugin/out_syslog_rfc5424.rb b/lib/fluent/plugin/out_syslog_rfc5424.rb index 54f23f2..23233c8 100644 --- a/lib/fluent/plugin/out_syslog_rfc5424.rb +++ b/lib/fluent/plugin/out_syslog_rfc5424.rb @@ -15,7 +15,7 @@ class OutSyslogRFC5424 < Output config_param :trusted_ca_path, :string, default: nil config_param :private_key_path, :string, default: nil config_param :private_key_passphrase, :string, default: nil - config_param :allow_self_signed_cert, :string, default: false + config_param :allow_self_signed_cert, :bool, default: false config_param :fqdn, :string, default: nil config_param :version, :string, default: "TLSv1_2" config_section :format do From f5c972d3fd29ba5b9df6cdd2bc95c2a2c562b68b Mon Sep 17 00:00:00 2001 From: hisagar <32439113+Hisagar@users.noreply.github.com> Date: Wed, 2 Feb 2022 19:35:56 +0530 Subject: [PATCH 04/12] version string converted to symbol --- lib/fluent/plugin/out_syslog_rfc5424.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/fluent/plugin/out_syslog_rfc5424.rb b/lib/fluent/plugin/out_syslog_rfc5424.rb index 23233c8..34862eb 100644 --- a/lib/fluent/plugin/out_syslog_rfc5424.rb +++ b/lib/fluent/plugin/out_syslog_rfc5424.rb @@ -75,7 +75,7 @@ def socket_options private_key_passphrase: @private_key_passphrase, allow_self_signed_cert: @allow_self_signed_cert, fqdn: @fqdn, - version: @version, + version: @version.to_sym, } #, connect_timeout: 1, send_timeout: 1, recv_timeout: 1, linger_timeout: 1 } else {} From ef800ecd2cc115dd7b91dd5b43e401e4909d5558 Mon Sep 17 00:00:00 2001 From: Sagar Wankhade <32439113+Hisagar@users.noreply.github.com> Date: Thu, 3 Feb 2022 13:09:04 +0530 Subject: [PATCH 05/12] Update lib/fluent/plugin/out_syslog_rfc5424.rb Co-authored-by: Alex Szasz --- lib/fluent/plugin/out_syslog_rfc5424.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/fluent/plugin/out_syslog_rfc5424.rb b/lib/fluent/plugin/out_syslog_rfc5424.rb index 34862eb..f5461e1 100644 --- a/lib/fluent/plugin/out_syslog_rfc5424.rb +++ b/lib/fluent/plugin/out_syslog_rfc5424.rb @@ -13,6 +13,8 @@ class OutSyslogRFC5424 < Output config_param :transport, :string, default: "tls" config_param :insecure, :bool, default: false config_param :trusted_ca_path, :string, default: nil + config_param :verify_fqdn, :bool, default: nil + config_param :verify_peer, :bool, default: nil config_param :private_key_path, :string, default: nil config_param :private_key_passphrase, :string, default: nil config_param :allow_self_signed_cert, :bool, default: false From f99d37f8c39b29146c57edcda6279fcd12d498d5 Mon Sep 17 00:00:00 2001 From: Sagar Wankhade <32439113+Hisagar@users.noreply.github.com> Date: Thu, 3 Feb 2022 13:09:17 +0530 Subject: [PATCH 06/12] Update lib/fluent/plugin/out_syslog_rfc5424.rb Co-authored-by: Alex Szasz --- lib/fluent/plugin/out_syslog_rfc5424.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/fluent/plugin/out_syslog_rfc5424.rb b/lib/fluent/plugin/out_syslog_rfc5424.rb index f5461e1..9fba61d 100644 --- a/lib/fluent/plugin/out_syslog_rfc5424.rb +++ b/lib/fluent/plugin/out_syslog_rfc5424.rb @@ -70,8 +70,8 @@ def socket_options elsif @transport == 'tls' # TODO: make timeouts configurable { - insecure: @insecure, - verify_fqdn: !@insecure, + insecure: @verify_peer.nil? ? @insecure : @verify_peer, + verify_fqdn: @verify_fqdn.nil? ? !@insecure : @verify_fqdn, cert_paths: @trusted_ca_path, private_key_path: @private_key_path, private_key_passphrase: @private_key_passphrase, From 4186724da3819764f4bed84c2393122455795248 Mon Sep 17 00:00:00 2001 From: hisagar <32439113+Hisagar@users.noreply.github.com> Date: Sun, 6 Feb 2022 18:41:56 +0530 Subject: [PATCH 07/12] tls_socket.rb patch added to allow self_signed_certificate --- lib/fluent/plugin/out_syslog_rfc5424.rb | 9 +- lib/fluent/plugin/tls_socket.rb | 178 ++++++++++++++++++++++++ test/plugin/out_syslog_rfc5424_spec.rb | 16 ++- 3 files changed, 194 insertions(+), 9 deletions(-) create mode 100644 lib/fluent/plugin/tls_socket.rb diff --git a/lib/fluent/plugin/out_syslog_rfc5424.rb b/lib/fluent/plugin/out_syslog_rfc5424.rb index 9fba61d..11b665c 100644 --- a/lib/fluent/plugin/out_syslog_rfc5424.rb +++ b/lib/fluent/plugin/out_syslog_rfc5424.rb @@ -16,7 +16,7 @@ class OutSyslogRFC5424 < Output config_param :verify_fqdn, :bool, default: nil config_param :verify_peer, :bool, default: nil config_param :private_key_path, :string, default: nil - config_param :private_key_passphrase, :string, default: nil + config_param :private_key_passphrase, :string, default: nil, secret: true config_param :allow_self_signed_cert, :bool, default: false config_param :fqdn, :string, default: nil config_param :version, :string, default: "TLSv1_2" @@ -61,7 +61,11 @@ def find_or_create_socket(transport, host, port) socket = find_socket(transport, host, port) return socket if socket - @sockets[socket_key(transport, host, port)] = socket_create(transport.to_sym, host, port, socket_options) + if transport == 'tls' + @sockets[socket_key(transport, host, port)] = create_tls_socket(host, port, socket_options) + else + @sockets[socket_key(transport, host, port)] = socket_create(transport.to_sym, host, port, socket_options) + end end def socket_options @@ -72,6 +76,7 @@ def socket_options { insecure: @verify_peer.nil? ? @insecure : @verify_peer, verify_fqdn: @verify_fqdn.nil? ? !@insecure : @verify_fqdn, + veify_peer: @verify_peer, cert_paths: @trusted_ca_path, private_key_path: @private_key_path, private_key_passphrase: @private_key_passphrase, diff --git a/lib/fluent/plugin/tls_socket.rb b/lib/fluent/plugin/tls_socket.rb new file mode 100644 index 0000000..dd41123 --- /dev/null +++ b/lib/fluent/plugin/tls_socket.rb @@ -0,0 +1,178 @@ +require 'socket' +require 'ipaddr' +require 'openssl' + +def create_tls_socket( + host, port, + version: Fluent::TLS::DEFAULT_VERSION, min_version: nil, max_version: nil, ciphers: Fluent::TLS::CIPHERS_DEFAULT, insecure: false, verify_fqdn: true, verify_peer: true, fqdn: nil, + enable_system_cert_store: true, allow_self_signed_cert: false, cert_paths: nil, + cert_path: nil, private_key_path: nil, private_key_passphrase: nil, + cert_thumbprint: nil, cert_logical_store_name: nil, cert_use_enterprise_store: true, + connect_timeout: nil, + **kwargs, &block) + + host_is_ipaddress = IPAddr.new(host) rescue false + fqdn ||= host unless host_is_ipaddress + + context = OpenSSL::SSL::SSLContext.new + + if insecure + log.trace "setting TLS verify_mode NONE" + context.verify_mode = OpenSSL::SSL::VERIFY_NONE + else + cert_store = OpenSSL::X509::Store.new + if allow_self_signed_cert && OpenSSL::X509.const_defined?('V_FLAG_CHECK_SS_SIGNATURE') + cert_store.flags = OpenSSL::X509::V_FLAG_CHECK_SS_SIGNATURE + end + begin + if enable_system_cert_store + if Fluent.windows? && cert_logical_store_name + log.trace "loading Windows system certificate store" + loader = Certstore::OpenSSL::Loader.new(log, cert_store, cert_logical_store_name, + enterprise: cert_use_enterprise_store) + loader.load_cert_store + cert_store = loader.cert_store + context.cert = loader.get_certificate(cert_thumbprint) if cert_thumbprint + end + log.trace "loading system default certificate store" + cert_store.set_default_paths + end + rescue OpenSSL::X509::StoreError + log.warn "failed to load system default certificate store", error: e + end + if cert_paths + if cert_paths.respond_to?(:each) + cert_paths.each do |cert_path| + log.trace "adding CA cert", path: cert_path + cert_store.add_file(cert_path) + end + else + cert_path = cert_paths + log.trace "adding CA cert", path: cert_path + cert_store.add_file(cert_path) + end + end + + log.trace "setting TLS context", mode: "peer", ciphers: ciphers + context.set_params({}) + context.ciphers = ciphers + + if verify_peer + context.verify_mode = OpenSSL::SSL::VERIFY_PEER + else + context.verify_mode = OpenSSL::SSL::VERIFY_NONE + end + + context.cert_store = cert_store + context.verify_hostname = verify_fqdn && fqdn + context.key = OpenSSL::PKey::read(File.read(private_key_path), private_key_passphrase) if private_key_path + + if cert_path + certs = socket_certificates_from_file(cert_path) + context.cert = certs.shift + unless certs.empty? + context.extra_chain_cert = certs + end + end + end + Fluent::TLS.set_version_to_context(context, version, min_version, max_version) + + tcpsock = socket_create_tcp(host, port, connect_timeout: connect_timeout, **kwargs) + sock = WrappedSocket::TLS.new(tcpsock, context) + sock.sync_close = true + sock.hostname = fqdn if verify_fqdn && fqdn && sock.respond_to?(:hostname=) + + log.trace "entering TLS handshake" + if connect_timeout + begin + Timeout.timeout(connect_timeout) { sock.connect } + rescue Timeout::Error + log.warn "timeout while connecting tls session", host: host + sock.close rescue nil + raise + end + else + sock.connect + end + + begin + if verify_fqdn + log.trace "checking peer's certificate", subject: sock.peer_cert.subject + sock.post_connection_check(fqdn) + verify = sock.verify_result + if verify != OpenSSL::X509::V_OK + err_name = tls_verify_result_name(verify) + log.warn "BUG: failed to verify certification while connecting (but not raised, why?)", host: host, fqdn: fqdn, error: err_name + raise RuntimeError, "BUG: failed to verify certification and to handle it correctly while connecting host #{host} as #{fqdn}" + end + end + rescue OpenSSL::SSL::SSLError => e + log.warn "failed to verify certification while connecting tls session", host: host, fqdn: fqdn, error: e + raise + end + + if block + begin + block.call(sock) + ensure + sock.close rescue nil + end + else + sock + end +end + +def tls_verify_result_name(code) + case code + when OpenSSL::X509::V_OK then 'V_OK' + when OpenSSL::X509::V_ERR_AKID_SKID_MISMATCH then 'V_ERR_AKID_SKID_MISMATCH' + when OpenSSL::X509::V_ERR_APPLICATION_VERIFICATION then 'V_ERR_APPLICATION_VERIFICATION' + when OpenSSL::X509::V_ERR_CERT_CHAIN_TOO_LONG then 'V_ERR_CERT_CHAIN_TOO_LONG' + when OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED then 'V_ERR_CERT_HAS_EXPIRED' + when OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID then 'V_ERR_CERT_NOT_YET_VALID' + when OpenSSL::X509::V_ERR_CERT_REJECTED then 'V_ERR_CERT_REJECTED' + when OpenSSL::X509::V_ERR_CERT_REVOKED then 'V_ERR_CERT_REVOKED' + when OpenSSL::X509::V_ERR_CERT_SIGNATURE_FAILURE then 'V_ERR_CERT_SIGNATURE_FAILURE' + when OpenSSL::X509::V_ERR_CERT_UNTRUSTED then 'V_ERR_CERT_UNTRUSTED' + when OpenSSL::X509::V_ERR_CRL_HAS_EXPIRED then 'V_ERR_CRL_HAS_EXPIRED' + when OpenSSL::X509::V_ERR_CRL_NOT_YET_VALID then 'V_ERR_CRL_NOT_YET_VALID' + when OpenSSL::X509::V_ERR_CRL_SIGNATURE_FAILURE then 'V_ERR_CRL_SIGNATURE_FAILURE' + when OpenSSL::X509::V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT then 'V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT' + when OpenSSL::X509::V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD then 'V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD' + when OpenSSL::X509::V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD then 'V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD' + when OpenSSL::X509::V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD then 'V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD' + when OpenSSL::X509::V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD then 'V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD' + when OpenSSL::X509::V_ERR_INVALID_CA then 'V_ERR_INVALID_CA' + when OpenSSL::X509::V_ERR_INVALID_PURPOSE then 'V_ERR_INVALID_PURPOSE' + when OpenSSL::X509::V_ERR_KEYUSAGE_NO_CERTSIGN then 'V_ERR_KEYUSAGE_NO_CERTSIGN' + when OpenSSL::X509::V_ERR_OUT_OF_MEM then 'V_ERR_OUT_OF_MEM' + when OpenSSL::X509::V_ERR_PATH_LENGTH_EXCEEDED then 'V_ERR_PATH_LENGTH_EXCEEDED' + when OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN then 'V_ERR_SELF_SIGNED_CERT_IN_CHAIN' + when OpenSSL::X509::V_ERR_SUBJECT_ISSUER_MISMATCH then 'V_ERR_SUBJECT_ISSUER_MISMATCH' + when OpenSSL::X509::V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY then 'V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY' + when OpenSSL::X509::V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE then 'V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY' + when OpenSSL::X509::V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE then 'V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE' + when OpenSSL::X509::V_ERR_UNABLE_TO_GET_CRL then 'V_ERR_UNABLE_TO_GET_CRL' + when OpenSSL::X509::V_ERR_UNABLE_TO_GET_ISSUER_CERT then 'V_ERR_UNABLE_TO_GET_ISSUER_CERT' + when OpenSSL::X509::V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY then 'V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY' + when OpenSSL::X509::V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE then 'V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE' + end +end + +module WrappedSocket + class TCP < ::TCPSocket + def remote_addr; peeraddr[3]; end + def remote_host; peeraddr[2]; end + def remote_port; peeraddr[1]; end + end + class UDP < ::UDPSocket + def remote_addr; peeraddr[3]; end + def remote_host; peeraddr[2]; end + def remote_port; peeraddr[1]; end + end + class TLS < OpenSSL::SSL::SSLSocket + def remote_addr; peeraddr[3]; end + def remote_host; peeraddr[2]; end + def remote_port; peeraddr[1]; end + end +end diff --git a/test/plugin/out_syslog_rfc5424_spec.rb b/test/plugin/out_syslog_rfc5424_spec.rb index 53fe5fe..e4972a9 100644 --- a/test/plugin/out_syslog_rfc5424_spec.rb +++ b/test/plugin/out_syslog_rfc5424_spec.rb @@ -37,7 +37,7 @@ def test_sends_a_message stub(IO).select(nil, [socket], nil, 1) { ["not an error"] } any_instance_of(Fluent::Plugin::OutSyslogRFC5424) do |fluent_plugin| - mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :version=>"TLSv1_2"}).returns(socket) + mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :verify_peer=>true, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :version=>"TLSv1_2"}).returns(socket) end output_driver.run do @@ -64,8 +64,8 @@ def test_reconnects mock(IO).select(nil, [good_socket], nil, 1) { ["not an error"] } any_instance_of(Fluent::Plugin::OutSyslogRFC5424) do |fluent_plugin| - mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :version=>"TLSv1_2"}).returns(bad_socket) - mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :version=>"TLSv1_2"}).returns(good_socket) + mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :verify_peer=>true, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :version=>"TLSv1_2"}).returns(bad_socket) + mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :verify_peer=>true, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :version=>"TLSv1_2"}).returns(good_socket) end output_driver.run(shutdown: false, force_flush_retry: true) do @@ -112,7 +112,7 @@ def test_insecure_tls stub(IO).select(nil, [socket], nil, 1) { ["not an error"] } any_instance_of(Fluent::Plugin::OutSyslogRFC5424) do |fluent_plugin| - mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>true, :verify_fqdn=>false, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :version=>"TLSv1_2"}).returns(socket) + mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>true, :verify_fqdn=>false, :verify_peer=>true, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :version=>"TLSv1_2"}).returns(socket) end output_driver.run do @@ -136,7 +136,7 @@ def test_secure_tls stub(IO).select(nil, [socket], nil, 1) { ["not an error"] } any_instance_of(Fluent::Plugin::OutSyslogRFC5424) do |fluent_plugin| - mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>"supertrustworthy", :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :version=>"TLSv1_2"}).returns(socket) + mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :verify_peer=>true, :cert_paths=>"supertrustworthy", :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :version=>"TLSv1_2"}).returns(socket) end output_driver.run do @@ -150,6 +150,8 @@ def test_secure_mutual_tls host example.com port 123 transport tls + verify_fqdn true + verify_peer true trusted_ca_path supertrustworthy private_key_path supertrustworthykey private_key_passphrase supertrustworthypassphrase @@ -165,7 +167,7 @@ def test_secure_mutual_tls stub(IO).select(nil, [socket], nil, 1) { ["not an error"] } any_instance_of(Fluent::Plugin::OutSyslogRFC5424) do |fluent_plugin| - mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>"supertrustworthy", :private_key_path=>"supertrustworthykey", :private_key_passphrase=>"supertrustworthypassphrase", :allow_self_signed_cert=>false, :fqdn=>"supertrustworthyfqdn", :version=>"TLSv1_2"}).returns(socket) + mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :verify_peer=>true, :cert_paths=>"supertrustworthy", :private_key_path=>"supertrustworthykey", :private_key_passphrase=>"supertrustworthypassphrase", :allow_self_signed_cert=>false, :fqdn=>"supertrustworthyfqdn", :version=>"TLSv1_2"}).returns(socket) end output_driver.run do @@ -187,7 +189,7 @@ def test_close_is_called_on_sockets stub(IO).select(nil, [socket], nil, 1) { ["not an error"] } any_instance_of(Fluent::Plugin::OutSyslogRFC5424) do |fluent_plugin| - mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :version=>"TLSv1_2"}).returns(socket) + mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :verify_peer=>true, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :version=>"TLSv1_2"}).returns(socket) end output_driver.run do From 89b65e655c3ca72f9e779bca5cb0eb704729a0da Mon Sep 17 00:00:00 2001 From: hisagar <32439113+Hisagar@users.noreply.github.com> Date: Sun, 6 Feb 2022 20:02:39 +0530 Subject: [PATCH 08/12] tls_socket.rb patch added to allow self_signed_certificate --- lib/fluent/plugin/out_syslog_rfc5424.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/fluent/plugin/out_syslog_rfc5424.rb b/lib/fluent/plugin/out_syslog_rfc5424.rb index 11b665c..20a7b11 100644 --- a/lib/fluent/plugin/out_syslog_rfc5424.rb +++ b/lib/fluent/plugin/out_syslog_rfc5424.rb @@ -76,7 +76,7 @@ def socket_options { insecure: @verify_peer.nil? ? @insecure : @verify_peer, verify_fqdn: @verify_fqdn.nil? ? !@insecure : @verify_fqdn, - veify_peer: @verify_peer, + verify_peer: @verify_peer, cert_paths: @trusted_ca_path, private_key_path: @private_key_path, private_key_passphrase: @private_key_passphrase, From ba14fa2cf8d4447ee48ca028f0a16b3d3e8f311b Mon Sep 17 00:00:00 2001 From: hisagar <32439113+Hisagar@users.noreply.github.com> Date: Sun, 6 Feb 2022 20:39:43 +0530 Subject: [PATCH 09/12] require_relative added --- lib/fluent/plugin/out_syslog_rfc5424.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/fluent/plugin/out_syslog_rfc5424.rb b/lib/fluent/plugin/out_syslog_rfc5424.rb index 20a7b11..14fe948 100644 --- a/lib/fluent/plugin/out_syslog_rfc5424.rb +++ b/lib/fluent/plugin/out_syslog_rfc5424.rb @@ -1,4 +1,5 @@ require 'fluent/plugin/output' +require_relative 'tls_socket' module Fluent module Plugin @@ -76,7 +77,7 @@ def socket_options { insecure: @verify_peer.nil? ? @insecure : @verify_peer, verify_fqdn: @verify_fqdn.nil? ? !@insecure : @verify_fqdn, - verify_peer: @verify_peer, + verify_peer: @verify_peer.nil? ? !@insecure : @verify_peer, cert_paths: @trusted_ca_path, private_key_path: @private_key_path, private_key_passphrase: @private_key_passphrase, From 65f4aa209e643631704d3cd49dae23669bd5d6de Mon Sep 17 00:00:00 2001 From: hisagar <32439113+Hisagar@users.noreply.github.com> Date: Sun, 6 Feb 2022 21:42:09 +0530 Subject: [PATCH 10/12] require_relative added --- lib/fluent/plugin/out_syslog_rfc5424.rb | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/fluent/plugin/out_syslog_rfc5424.rb b/lib/fluent/plugin/out_syslog_rfc5424.rb index 14fe948..6b6c8a8 100644 --- a/lib/fluent/plugin/out_syslog_rfc5424.rb +++ b/lib/fluent/plugin/out_syslog_rfc5424.rb @@ -61,12 +61,7 @@ def close def find_or_create_socket(transport, host, port) socket = find_socket(transport, host, port) return socket if socket - - if transport == 'tls' - @sockets[socket_key(transport, host, port)] = create_tls_socket(host, port, socket_options) - else - @sockets[socket_key(transport, host, port)] = socket_create(transport.to_sym, host, port, socket_options) - end + @sockets[socket_key(transport, host, port)] = create_tls_socket(host, port, socket_options) end def socket_options From 333679f85d4e5ffcc0ba5136335b36dae80655c3 Mon Sep 17 00:00:00 2001 From: hisagar <32439113+Hisagar@users.noreply.github.com> Date: Sun, 6 Feb 2022 23:08:13 +0530 Subject: [PATCH 11/12] turnary operator added --- lib/fluent/plugin/out_syslog_rfc5424.rb | 3 ++- lib/fluent/plugin/tls_socket.rb | 8 +------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/lib/fluent/plugin/out_syslog_rfc5424.rb b/lib/fluent/plugin/out_syslog_rfc5424.rb index 6b6c8a8..a875618 100644 --- a/lib/fluent/plugin/out_syslog_rfc5424.rb +++ b/lib/fluent/plugin/out_syslog_rfc5424.rb @@ -61,7 +61,8 @@ def close def find_or_create_socket(transport, host, port) socket = find_socket(transport, host, port) return socket if socket - @sockets[socket_key(transport, host, port)] = create_tls_socket(host, port, socket_options) + @sockets[socket_key(transport, host, port)] = (transport == :tls) ? create_tls_socket(host, port, socket_options) : + socket_create(transport.to_sym, host, port, socket_options) end def socket_options diff --git a/lib/fluent/plugin/tls_socket.rb b/lib/fluent/plugin/tls_socket.rb index dd41123..d989f1a 100644 --- a/lib/fluent/plugin/tls_socket.rb +++ b/lib/fluent/plugin/tls_socket.rb @@ -56,13 +56,7 @@ def create_tls_socket( log.trace "setting TLS context", mode: "peer", ciphers: ciphers context.set_params({}) context.ciphers = ciphers - - if verify_peer - context.verify_mode = OpenSSL::SSL::VERIFY_PEER - else - context.verify_mode = OpenSSL::SSL::VERIFY_NONE - end - + context.verify_mode = verify_peer ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE context.cert_store = cert_store context.verify_hostname = verify_fqdn && fqdn context.key = OpenSSL::PKey::read(File.read(private_key_path), private_key_passphrase) if private_key_path From 095de132e500ebae6dd6e97a4c5445325e7e40f2 Mon Sep 17 00:00:00 2001 From: hisagar <32439113+Hisagar@users.noreply.github.com> Date: Mon, 7 Feb 2022 20:50:56 +0530 Subject: [PATCH 12/12] updated param for syslog plugin with mutual tls --- lib/fluent/plugin/out_syslog_rfc5424.rb | 17 +-- lib/fluent/plugin/tls_socket.rb | 172 ------------------------ test/plugin/out_syslog_rfc5424_spec.rb | 21 +-- 3 files changed, 20 insertions(+), 190 deletions(-) delete mode 100644 lib/fluent/plugin/tls_socket.rb diff --git a/lib/fluent/plugin/out_syslog_rfc5424.rb b/lib/fluent/plugin/out_syslog_rfc5424.rb index a875618..7281b3e 100644 --- a/lib/fluent/plugin/out_syslog_rfc5424.rb +++ b/lib/fluent/plugin/out_syslog_rfc5424.rb @@ -1,5 +1,4 @@ require 'fluent/plugin/output' -require_relative 'tls_socket' module Fluent module Plugin @@ -15,10 +14,11 @@ class OutSyslogRFC5424 < Output config_param :insecure, :bool, default: false config_param :trusted_ca_path, :string, default: nil config_param :verify_fqdn, :bool, default: nil - config_param :verify_peer, :bool, default: nil + config_param :client_cert_path, :string, default: nil config_param :private_key_path, :string, default: nil config_param :private_key_passphrase, :string, default: nil, secret: true config_param :allow_self_signed_cert, :bool, default: false + config_param :enable_system_cert_store, :bool, default: true config_param :fqdn, :string, default: nil config_param :version, :string, default: "TLSv1_2" config_section :format do @@ -61,8 +61,8 @@ def close def find_or_create_socket(transport, host, port) socket = find_socket(transport, host, port) return socket if socket - @sockets[socket_key(transport, host, port)] = (transport == :tls) ? create_tls_socket(host, port, socket_options) : - socket_create(transport.to_sym, host, port, socket_options) + + @sockets[socket_key(transport, host, port)] = socket_create(transport.to_sym, host, port, socket_options) end def socket_options @@ -71,15 +71,16 @@ def socket_options elsif @transport == 'tls' # TODO: make timeouts configurable { - insecure: @verify_peer.nil? ? @insecure : @verify_peer, + insecure: @insecure, verify_fqdn: @verify_fqdn.nil? ? !@insecure : @verify_fqdn, - verify_peer: @verify_peer.nil? ? !@insecure : @verify_peer, - cert_paths: @trusted_ca_path, + cert_paths: [@trusted_ca_path], + cert_path: @client_cert_path, private_key_path: @private_key_path, private_key_passphrase: @private_key_passphrase, allow_self_signed_cert: @allow_self_signed_cert, + enable_system_cert_store: @enable_system_cert_store, fqdn: @fqdn, - version: @version.to_sym, + version: @version.to_sym } #, connect_timeout: 1, send_timeout: 1, recv_timeout: 1, linger_timeout: 1 } else {} diff --git a/lib/fluent/plugin/tls_socket.rb b/lib/fluent/plugin/tls_socket.rb deleted file mode 100644 index d989f1a..0000000 --- a/lib/fluent/plugin/tls_socket.rb +++ /dev/null @@ -1,172 +0,0 @@ -require 'socket' -require 'ipaddr' -require 'openssl' - -def create_tls_socket( - host, port, - version: Fluent::TLS::DEFAULT_VERSION, min_version: nil, max_version: nil, ciphers: Fluent::TLS::CIPHERS_DEFAULT, insecure: false, verify_fqdn: true, verify_peer: true, fqdn: nil, - enable_system_cert_store: true, allow_self_signed_cert: false, cert_paths: nil, - cert_path: nil, private_key_path: nil, private_key_passphrase: nil, - cert_thumbprint: nil, cert_logical_store_name: nil, cert_use_enterprise_store: true, - connect_timeout: nil, - **kwargs, &block) - - host_is_ipaddress = IPAddr.new(host) rescue false - fqdn ||= host unless host_is_ipaddress - - context = OpenSSL::SSL::SSLContext.new - - if insecure - log.trace "setting TLS verify_mode NONE" - context.verify_mode = OpenSSL::SSL::VERIFY_NONE - else - cert_store = OpenSSL::X509::Store.new - if allow_self_signed_cert && OpenSSL::X509.const_defined?('V_FLAG_CHECK_SS_SIGNATURE') - cert_store.flags = OpenSSL::X509::V_FLAG_CHECK_SS_SIGNATURE - end - begin - if enable_system_cert_store - if Fluent.windows? && cert_logical_store_name - log.trace "loading Windows system certificate store" - loader = Certstore::OpenSSL::Loader.new(log, cert_store, cert_logical_store_name, - enterprise: cert_use_enterprise_store) - loader.load_cert_store - cert_store = loader.cert_store - context.cert = loader.get_certificate(cert_thumbprint) if cert_thumbprint - end - log.trace "loading system default certificate store" - cert_store.set_default_paths - end - rescue OpenSSL::X509::StoreError - log.warn "failed to load system default certificate store", error: e - end - if cert_paths - if cert_paths.respond_to?(:each) - cert_paths.each do |cert_path| - log.trace "adding CA cert", path: cert_path - cert_store.add_file(cert_path) - end - else - cert_path = cert_paths - log.trace "adding CA cert", path: cert_path - cert_store.add_file(cert_path) - end - end - - log.trace "setting TLS context", mode: "peer", ciphers: ciphers - context.set_params({}) - context.ciphers = ciphers - context.verify_mode = verify_peer ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE - context.cert_store = cert_store - context.verify_hostname = verify_fqdn && fqdn - context.key = OpenSSL::PKey::read(File.read(private_key_path), private_key_passphrase) if private_key_path - - if cert_path - certs = socket_certificates_from_file(cert_path) - context.cert = certs.shift - unless certs.empty? - context.extra_chain_cert = certs - end - end - end - Fluent::TLS.set_version_to_context(context, version, min_version, max_version) - - tcpsock = socket_create_tcp(host, port, connect_timeout: connect_timeout, **kwargs) - sock = WrappedSocket::TLS.new(tcpsock, context) - sock.sync_close = true - sock.hostname = fqdn if verify_fqdn && fqdn && sock.respond_to?(:hostname=) - - log.trace "entering TLS handshake" - if connect_timeout - begin - Timeout.timeout(connect_timeout) { sock.connect } - rescue Timeout::Error - log.warn "timeout while connecting tls session", host: host - sock.close rescue nil - raise - end - else - sock.connect - end - - begin - if verify_fqdn - log.trace "checking peer's certificate", subject: sock.peer_cert.subject - sock.post_connection_check(fqdn) - verify = sock.verify_result - if verify != OpenSSL::X509::V_OK - err_name = tls_verify_result_name(verify) - log.warn "BUG: failed to verify certification while connecting (but not raised, why?)", host: host, fqdn: fqdn, error: err_name - raise RuntimeError, "BUG: failed to verify certification and to handle it correctly while connecting host #{host} as #{fqdn}" - end - end - rescue OpenSSL::SSL::SSLError => e - log.warn "failed to verify certification while connecting tls session", host: host, fqdn: fqdn, error: e - raise - end - - if block - begin - block.call(sock) - ensure - sock.close rescue nil - end - else - sock - end -end - -def tls_verify_result_name(code) - case code - when OpenSSL::X509::V_OK then 'V_OK' - when OpenSSL::X509::V_ERR_AKID_SKID_MISMATCH then 'V_ERR_AKID_SKID_MISMATCH' - when OpenSSL::X509::V_ERR_APPLICATION_VERIFICATION then 'V_ERR_APPLICATION_VERIFICATION' - when OpenSSL::X509::V_ERR_CERT_CHAIN_TOO_LONG then 'V_ERR_CERT_CHAIN_TOO_LONG' - when OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED then 'V_ERR_CERT_HAS_EXPIRED' - when OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID then 'V_ERR_CERT_NOT_YET_VALID' - when OpenSSL::X509::V_ERR_CERT_REJECTED then 'V_ERR_CERT_REJECTED' - when OpenSSL::X509::V_ERR_CERT_REVOKED then 'V_ERR_CERT_REVOKED' - when OpenSSL::X509::V_ERR_CERT_SIGNATURE_FAILURE then 'V_ERR_CERT_SIGNATURE_FAILURE' - when OpenSSL::X509::V_ERR_CERT_UNTRUSTED then 'V_ERR_CERT_UNTRUSTED' - when OpenSSL::X509::V_ERR_CRL_HAS_EXPIRED then 'V_ERR_CRL_HAS_EXPIRED' - when OpenSSL::X509::V_ERR_CRL_NOT_YET_VALID then 'V_ERR_CRL_NOT_YET_VALID' - when OpenSSL::X509::V_ERR_CRL_SIGNATURE_FAILURE then 'V_ERR_CRL_SIGNATURE_FAILURE' - when OpenSSL::X509::V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT then 'V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT' - when OpenSSL::X509::V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD then 'V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD' - when OpenSSL::X509::V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD then 'V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD' - when OpenSSL::X509::V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD then 'V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD' - when OpenSSL::X509::V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD then 'V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD' - when OpenSSL::X509::V_ERR_INVALID_CA then 'V_ERR_INVALID_CA' - when OpenSSL::X509::V_ERR_INVALID_PURPOSE then 'V_ERR_INVALID_PURPOSE' - when OpenSSL::X509::V_ERR_KEYUSAGE_NO_CERTSIGN then 'V_ERR_KEYUSAGE_NO_CERTSIGN' - when OpenSSL::X509::V_ERR_OUT_OF_MEM then 'V_ERR_OUT_OF_MEM' - when OpenSSL::X509::V_ERR_PATH_LENGTH_EXCEEDED then 'V_ERR_PATH_LENGTH_EXCEEDED' - when OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN then 'V_ERR_SELF_SIGNED_CERT_IN_CHAIN' - when OpenSSL::X509::V_ERR_SUBJECT_ISSUER_MISMATCH then 'V_ERR_SUBJECT_ISSUER_MISMATCH' - when OpenSSL::X509::V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY then 'V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY' - when OpenSSL::X509::V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE then 'V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY' - when OpenSSL::X509::V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE then 'V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE' - when OpenSSL::X509::V_ERR_UNABLE_TO_GET_CRL then 'V_ERR_UNABLE_TO_GET_CRL' - when OpenSSL::X509::V_ERR_UNABLE_TO_GET_ISSUER_CERT then 'V_ERR_UNABLE_TO_GET_ISSUER_CERT' - when OpenSSL::X509::V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY then 'V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY' - when OpenSSL::X509::V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE then 'V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE' - end -end - -module WrappedSocket - class TCP < ::TCPSocket - def remote_addr; peeraddr[3]; end - def remote_host; peeraddr[2]; end - def remote_port; peeraddr[1]; end - end - class UDP < ::UDPSocket - def remote_addr; peeraddr[3]; end - def remote_host; peeraddr[2]; end - def remote_port; peeraddr[1]; end - end - class TLS < OpenSSL::SSL::SSLSocket - def remote_addr; peeraddr[3]; end - def remote_host; peeraddr[2]; end - def remote_port; peeraddr[1]; end - end -end diff --git a/test/plugin/out_syslog_rfc5424_spec.rb b/test/plugin/out_syslog_rfc5424_spec.rb index e4972a9..230703f 100644 --- a/test/plugin/out_syslog_rfc5424_spec.rb +++ b/test/plugin/out_syslog_rfc5424_spec.rb @@ -37,7 +37,7 @@ def test_sends_a_message stub(IO).select(nil, [socket], nil, 1) { ["not an error"] } any_instance_of(Fluent::Plugin::OutSyslogRFC5424) do |fluent_plugin| - mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :verify_peer=>true, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :version=>"TLSv1_2"}).returns(socket) + mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>nil, :cert_path=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :enable_system_cert_store=>true, :fqdn=>nil, :version=>"TLSv1_2"}).returns(socket) end output_driver.run do @@ -64,8 +64,8 @@ def test_reconnects mock(IO).select(nil, [good_socket], nil, 1) { ["not an error"] } any_instance_of(Fluent::Plugin::OutSyslogRFC5424) do |fluent_plugin| - mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :verify_peer=>true, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :version=>"TLSv1_2"}).returns(bad_socket) - mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :verify_peer=>true, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :version=>"TLSv1_2"}).returns(good_socket) + mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>nil, :cert_path=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :enable_system_cert_store=>true, :fqdn=>nil, :version=>"TLSv1_2"}).returns(bad_socket) + mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>nil, :cert_path=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :enable_system_cert_store=>true, :fqdn=>nil, :version=>"TLSv1_2"}).returns(good_socket) end output_driver.run(shutdown: false, force_flush_retry: true) do @@ -112,7 +112,7 @@ def test_insecure_tls stub(IO).select(nil, [socket], nil, 1) { ["not an error"] } any_instance_of(Fluent::Plugin::OutSyslogRFC5424) do |fluent_plugin| - mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>true, :verify_fqdn=>false, :verify_peer=>true, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :version=>"TLSv1_2"}).returns(socket) + mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>true, :verify_fqdn=>false, :cert_paths=>nil, :cert_path=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :enable_system_cert_store=>true, :fqdn=>nil, :version=>"TLSv1_2"}).returns(socket) end output_driver.run do @@ -136,7 +136,7 @@ def test_secure_tls stub(IO).select(nil, [socket], nil, 1) { ["not an error"] } any_instance_of(Fluent::Plugin::OutSyslogRFC5424) do |fluent_plugin| - mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :verify_peer=>true, :cert_paths=>"supertrustworthy", :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :version=>"TLSv1_2"}).returns(socket) + mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>"supertrustworthy", :cert_path=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :enable_system_cert_store=>true, :fqdn=>nil, :version=>"TLSv1_2"}).returns(socket) end output_driver.run do @@ -151,11 +151,12 @@ def test_secure_mutual_tls port 123 transport tls verify_fqdn true - verify_peer true trusted_ca_path supertrustworthy - private_key_path supertrustworthykey - private_key_passphrase supertrustworthypassphrase + client_cert_path clientsupertrustworthykey + private_key_path clientsupertrustworthykey + private_key_passphrase clientsupertrustworthypassphrase allow_self_signed_cert false + enable_system_cert_store true fqdn supertrustworthyfqdn version "TLSv1_2" ) @@ -167,7 +168,7 @@ def test_secure_mutual_tls stub(IO).select(nil, [socket], nil, 1) { ["not an error"] } any_instance_of(Fluent::Plugin::OutSyslogRFC5424) do |fluent_plugin| - mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :verify_peer=>true, :cert_paths=>"supertrustworthy", :private_key_path=>"supertrustworthykey", :private_key_passphrase=>"supertrustworthypassphrase", :allow_self_signed_cert=>false, :fqdn=>"supertrustworthyfqdn", :version=>"TLSv1_2"}).returns(socket) + mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>"supertrustworthy", :cert_path=>"supertrustworthy", :private_key_path=>"clientsupertrustworthykey", :private_key_passphrase=>"clientsupertrustworthykey", :allow_self_signed_cert=>false, :enable_system_cert_store=>true, :fqdn=>"supertrustworthyfqdn", :version=>"TLSv1_2"}).returns(socket) end output_driver.run do @@ -189,7 +190,7 @@ def test_close_is_called_on_sockets stub(IO).select(nil, [socket], nil, 1) { ["not an error"] } any_instance_of(Fluent::Plugin::OutSyslogRFC5424) do |fluent_plugin| - mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :verify_peer=>true, :cert_paths=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :fqdn=>nil, :version=>"TLSv1_2"}).returns(socket) + mock(fluent_plugin).socket_create(:tls, "example.com", 123, {:insecure=>false, :verify_fqdn=>true, :cert_paths=>nil, :cert_path=>nil, :private_key_path=>nil, :private_key_passphrase=>nil, :allow_self_signed_cert=>false, :enable_system_cert_store=>true, :fqdn=>nil, :version=>"TLSv1_2"}).returns(socket) end output_driver.run do