Skip to content

Commit

Permalink
Merge pull request #2601 from cosmo0920/load-windows-certstore-with-c…
Browse files Browse the repository at this point in the history
…ertstore_c

Load certificates from windows certstore
  • Loading branch information
repeatedly authored Sep 4, 2019
2 parents 4a4b1cc + dd273aa commit 6aec3f6
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 1 deletion.
1 change: 1 addition & 0 deletions fluentd.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Gem::Specification.new do |gem|
gem.add_runtime_dependency("win32-ipc", ["~> 0.6.1"])
gem.add_runtime_dependency("win32-event", ["~> 0.6.1"])
gem.add_runtime_dependency("windows-pr", ["~> 1.2.5"])
gem.add_runtime_dependency("certstore_c", ["~> 0.1.2"])
end

gem.add_development_dependency("rake", ["~> 11.0"])
Expand Down
18 changes: 18 additions & 0 deletions lib/fluent/plugin/out_forward.rb
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@ class ForwardOutput < Output
config_param :tls_client_private_key_path, :string, default: nil
desc 'The client private key passphrase for TLS.'
config_param :tls_client_private_key_passphrase, :string, default: nil, secret: true
desc 'The certificate thumbprint for searching from Windows system certstore.'
config_param :tls_cert_thumbprint, :string, default: nil, secret: true
desc 'The certificate logical store name on Windows system certstore.'
config_param :tls_cert_logical_store_name, :string, default: nil
desc 'Enable to use certificate enterprise store on Windows system certstore.'
config_param :tls_cert_use_enterprise_store, :bool, default: true
desc "Enable keepalive connection."
config_param :keepalive, :bool, default: false
desc "Expired time of keepalive. Default value is nil, which means to keep connection as long as possible"
Expand Down Expand Up @@ -198,6 +204,15 @@ def configure(conf)
@tls_verify_hostname = false
@tls_allow_self_signed_cert = true
end

if Fluent.windows?
if (@tls_cert_path || @tls_ca_cert_path) && @tls_cert_logical_store_name
raise Fluent::ConfigError, "specified both cert path and tls_cert_logical_store_name is not permitted"
end
else
raise Fluent::ConfigError, "This parameter is for only Windows" if @tls_cert_logical_store_name
raise Fluent::ConfigError, "This parameter is for only Windows" if @tls_cert_thumbprint
end
end

@ack_handler = @require_ack_response ? AckHandler.new(timeout: @ack_response_timeout, log: @log, read_length: @read_length) : nil
Expand Down Expand Up @@ -346,6 +361,9 @@ def create_transfer_socket(host, port, hostname, &block)
cert_path: @tls_client_cert_path,
private_key_path: @tls_client_private_key_path,
private_key_passphrase: @tls_client_private_key_passphrase,
cert_thumbprint: @tls_cert_thumbprint,
cert_logical_store_name: @tls_cert_logical_store_name,
cert_use_enterprise_store: @tls_cert_use_enterprise_store,

# Enabling SO_LINGER causes data loss on Windows
# https://github.com/fluent/fluentd/issues/1968
Expand Down
15 changes: 14 additions & 1 deletion lib/fluent/plugin_helper/socket.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
require 'socket'
require 'ipaddr'
require 'openssl'
if Fluent.windows?
require 'certstore'
end

require_relative 'socket_option'

Expand Down Expand Up @@ -96,7 +99,9 @@ def socket_create_tls(
host, port,
version: TLS_DEFAULT_VERSION, ciphers: CIPHERS_DEFAULT, insecure: false, verify_fqdn: 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, **kwargs, &block)
cert_path: nil, private_key_path: nil, private_key_passphrase: nil,
cert_thumbprint: nil, cert_logical_store_name: nil, cert_use_enterprise_store: true,
**kwargs, &block)

host_is_ipaddress = IPAddr.new(host) rescue false
fqdn ||= host unless host_is_ipaddress
Expand All @@ -113,6 +118,14 @@ def socket_create_tls(
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
Expand Down
75 changes: 75 additions & 0 deletions test/plugin/test_out_forward.rb
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,81 @@ def try_write(chunk)
assert_equal([dummy_cert_path], d.instance.tls_ca_cert_path)
end

sub_test_case "certstore loading parameters for Windows" do
test 'certstore related config parameters' do
omit "certstore related values raise error on not Windows" if Fluent.windows?
conf = %[
send_timeout 5
transport tls
tls_cert_logical_store_name Root
tls_cert_thumbprint a909502dd82ae41433e6f83886b00d4277a32a7b
<server>
host #{TARGET_HOST}
port #{TARGET_PORT}
</server>
]

assert_raise(Fluent::ConfigError) do
create_driver(conf)
end
end

test 'cert_logical_store_name and tls_cert_thumbprint default values' do
conf = %[
send_timeout 5
transport tls
<server>
host #{TARGET_HOST}
port #{TARGET_PORT}
</server>
]

@d = d = create_driver(conf)
assert_nil d.instance.tls_cert_logical_store_name
assert_nil d.instance.tls_cert_thumbprint
end

data('CA cert' => 'tls_ca_cert_path',
'non CA cert' => 'tls_cert_path')
test 'specify tls_cert_logical_store_name and tls_cert_path should raise error' do |param|
omit "Loading CertStore feature works only Windows" unless Fluent.windows?
dummy_cert_path = File.join(TMP_DIR, "dummy_cert.pem")
FileUtils.touch(dummy_cert_path)
conf = %[
send_timeout 5
transport tls
#{param} #{dummy_cert_path}
tls_cert_logical_store_name Root
<server>
host #{TARGET_HOST}
port #{TARGET_PORT}
</server>
]

assert_raise(Fluent::ConfigError) do
create_driver(conf)
end
end

test 'configure cert_logical_store_name and tls_cert_thumbprint' do
omit "Loading CertStore feature works only Windows" unless Fluent.windows?
conf = %[
send_timeout 5
transport tls
tls_cert_logical_store_name Root
tls_cert_thumbprint a909502dd82ae41433e6f83886b00d4277a32a7b
<server>
host #{TARGET_HOST}
port #{TARGET_PORT}
</server>
]

@d = d = create_driver(conf)
assert_equal "Root", d.instance.tls_cert_logical_store_name
assert_equal "a909502dd82ae41433e6f83886b00d4277a32a7b", d.instance.tls_cert_thumbprint
end
end

test 'compress_default_value' do
@d = d = create_driver
assert_equal :text, d.instance.compress
Expand Down

0 comments on commit 6aec3f6

Please sign in to comment.