Skip to content

Commit ba418f1

Browse files
UXabreArend Lapere
authored andcommitted
Support TLS certificate & key pair
1 parent aeb60e2 commit ba418f1

File tree

4 files changed

+122
-2
lines changed

4 files changed

+122
-2
lines changed

docs/index.asciidoc

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,9 @@ This plugin supports the following configuration options plus the
287287
| <<plugins-{type}s-{plugin}-ilm_policy>> |<<string,string>>|No
288288
| <<plugins-{type}s-{plugin}-ilm_rollover_alias>> |<<string,string>>|No
289289
| <<plugins-{type}s-{plugin}-index>> |<<string,string>>|No
290+
| <<plugins-{type}s-{plugin}-tls_certificate>> |a valid filesystem path|No
290291
| <<plugins-{type}s-{plugin}-keystore>> |a valid filesystem path|No
292+
| <<plugins-{type}s-{plugin}-tls_private_key>> |a valid filesystem path|No
291293
| <<plugins-{type}s-{plugin}-keystore_password>> |<<password,password>>|No
292294
| <<plugins-{type}s-{plugin}-manage_template>> |<<boolean,boolean>>|No
293295
| <<plugins-{type}s-{plugin}-parameters>> |<<hash,hash>>|No
@@ -628,6 +630,24 @@ Logstash uses
628630
http://www.joda.org/joda-time/apidocs/org/joda/time/format/DateTimeFormat.html[Joda
629631
formats] for the index pattern from event timestamp.
630632

633+
[id="plugins-{type}s-{plugin}-tls_certificate"]
634+
===== `tls_certificate`
635+
636+
* Value type is <<path,path>>
637+
* There is no default value for this setting.
638+
639+
The tls_certificate used to present a client certificate to the server.
640+
It accepts .pem formatted files
641+
642+
[id="plugins-{type}s-{plugin}-tls_private_key"]
643+
===== `tls_private_key`
644+
645+
* Value type is <<path,path>>
646+
* There is no default value for this setting.
647+
648+
The tls_private_key used to present a client private key to the server, to be used in conjunction with tls_certificate.
649+
It accepts .pkcs8 formatted files
650+
631651

632652
[id="plugins-{type}s-{plugin}-keystore"]
633653
===== `keystore`

lib/logstash/outputs/elasticsearch/http_client_builder.rb

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,21 @@ def self.setup_ssl(logger, params)
112112

113113
return {:ssl => {:enabled => false}} if params["ssl"] == false
114114

115-
cacert, truststore, truststore_password, keystore, keystore_password =
116-
params.values_at('cacert', 'truststore', 'truststore_password', 'keystore', 'keystore_password')
115+
cacert, truststore, truststore_password, keystore, keystore_password, tls_certificate, tls_private_key =
116+
params.values_at('cacert', 'truststore', 'truststore_password', 'keystore', 'keystore_password', 'tls_certificate', 'tls_private_key')
117117

118118
if cacert && truststore
119119
raise(LogStash::ConfigurationError, "Use either \"cacert\" or \"truststore\" when configuring the CA certificate") if truststore
120120
end
121121

122+
if tls_certificate && keystore
123+
raise(LogStash::ConfigurationError, "Use either \"tls_certificate\" or \"keystore\" when configuring the client certificate")
124+
end
125+
126+
if (tls_private_key && !tls_certificate) || (tls_certificate && !tls_private_key)
127+
raise(LogStash::ConfigurationError, "Both a \"tls_private_key\" and a \"tls_certificate\" need to be present")
128+
end
129+
122130
ssl_options = {:enabled => true}
123131

124132
if cacert
@@ -131,7 +139,11 @@ def self.setup_ssl(logger, params)
131139
if keystore
132140
ssl_options[:keystore] = keystore
133141
ssl_options[:keystore_password] = keystore_password.value if keystore_password
142+
elsif tls_certificate && tls_private_key
143+
ssl_options[:client_cert] = tls_certificate
144+
ssl_options[:client_key] = tls_private_key
134145
end
146+
135147
if !params["ssl_certificate_verification"]
136148
logger.warn [
137149
"** WARNING ** Detected UNSAFE options in elasticsearch output configuration!",

lib/logstash/plugin_mixins/elasticsearch/api_configs.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ def self.included(mod)
6666
# Set the keystore password
6767
mod.config :keystore_password, :validate => :password
6868

69+
# The certificate to present to the server. (only pem format supported)
70+
mod.config :tls_certificate, :validate => :path
71+
# The private key to present to the server. (only pkcs8 format supported)
72+
mod.config :tls_private_key, :validate => :path
73+
6974
# This setting asks Elasticsearch for the list of all cluster nodes and adds them to the hosts list.
7075
# Note: This will return ALL nodes with HTTP enabled (including master nodes!). If you use
7176
# this with master nodes, you probably want to disable HTTP on them by setting

spec/unit/outputs/elasticsearch_ssl_spec.rb

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,89 @@
7777
end.and_call_original
7878
subject.register
7979
end
80+
end
81+
82+
context "when using both pem-encoded and jks-encoded client certificates" do
83+
let(:tls_certificate) { Stud::Temporary.file.path }
84+
let(:tls_private_key) { Stud::Temporary.file.path }
85+
before do
86+
`openssl req -x509 -batch -nodes -newkey rsa:2048 -keyout #{tls_private_key} -out #{tls_certificate}`
87+
end
88+
89+
after :each do
90+
File.delete(tls_private_key)
91+
File.delete(tls_certificate)
92+
subject.close
93+
end
8094

95+
subject do
96+
settings = {
97+
"hosts" => "node01",
98+
"ssl" => true,
99+
"tls_certificate" => tls_certificate,
100+
"tls_private_key" => tls_private_key,
101+
# just any file will do for this test
102+
"keystore" => tls_certificate
103+
}
104+
next LogStash::Outputs::ElasticSearch.new(settings)
105+
end
106+
107+
it "should fail to load the plugin" do
108+
expect { subject.register }.to raise_error(LogStash::ConfigurationError)
109+
end
110+
end
111+
112+
context "when configuring only tls_certificate but ommitting the private_key" do
113+
let(:tls_certificate) { Stud::Temporary.file.path }
114+
let(:tls_private_key) { Stud::Temporary.file.path }
115+
before do
116+
`openssl req -x509 -batch -nodes -newkey rsa:2048 -keyout #{tls_private_key} -out #{tls_certificate}`
117+
end
118+
119+
after :each do
120+
File.delete(tls_private_key)
121+
File.delete(tls_certificate)
122+
subject.close
123+
end
124+
125+
subject do
126+
settings = {
127+
"hosts" => "node01",
128+
"ssl" => true,
129+
"tls_certificate" => tls_certificate,
130+
}
131+
next LogStash::Outputs::ElasticSearch.new(settings)
132+
end
133+
134+
it "should fail to load the plugin" do
135+
expect { subject.register }.to raise_error(LogStash::ConfigurationError)
136+
end
137+
end
138+
139+
context "when configuring only private_key but ommitting the tls_certificate" do
140+
let(:tls_certificate) { Stud::Temporary.file.path }
141+
let(:tls_private_key) { Stud::Temporary.file.path }
142+
before do
143+
`openssl req -x509 -batch -nodes -newkey rsa:2048 -keyout #{tls_private_key} -out #{tls_certificate}`
144+
end
145+
146+
after :each do
147+
File.delete(tls_private_key)
148+
File.delete(tls_certificate)
149+
subject.close
150+
end
151+
152+
subject do
153+
settings = {
154+
"hosts" => "node01",
155+
"ssl" => true,
156+
"tls_private_key" => tls_private_key,
157+
}
158+
next LogStash::Outputs::ElasticSearch.new(settings)
159+
end
160+
161+
it "should fail to load the plugin" do
162+
expect { subject.register }.to raise_error(LogStash::ConfigurationError)
163+
end
81164
end
82165
end

0 commit comments

Comments
 (0)