Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Load certificates from windows certstore #2601

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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