logstash-integration-rabbitmq 7.0.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +9 -0
- data/CONTRIBUTORS +27 -0
- data/Gemfile +11 -0
- data/LICENSE +13 -0
- data/NOTICE.TXT +5 -0
- data/README.md +98 -0
- data/docs/index.asciidoc +29 -0
- data/docs/input-rabbitmq.asciidoc +398 -0
- data/docs/output-rabbitmq.asciidoc +272 -0
- data/lib/logstash/inputs/rabbitmq.rb +317 -0
- data/lib/logstash/outputs/rabbitmq.rb +131 -0
- data/lib/logstash/plugin_mixins/rabbitmq_connection.rb +234 -0
- data/lib/logstash_registry.rb +7 -0
- data/logstash-integration-rabbitmq.gemspec +53 -0
- data/spec/fixtures/README.md +150 -0
- data/spec/fixtures/client/cert.pem +69 -0
- data/spec/fixtures/client/key.pem +27 -0
- data/spec/fixtures/client/keycert.p12 +0 -0
- data/spec/fixtures/client/req.pem +15 -0
- data/spec/fixtures/client_untrusted/cert.pem +19 -0
- data/spec/fixtures/client_untrusted/key.pem +28 -0
- data/spec/fixtures/client_untrusted/keycert.p12 +0 -0
- data/spec/fixtures/server/cert.pem +69 -0
- data/spec/fixtures/server/key.pem +27 -0
- data/spec/fixtures/server/key_password +1 -0
- data/spec/fixtures/server/keycert.p12 +0 -0
- data/spec/fixtures/server/rabbitmq.config +10 -0
- data/spec/fixtures/server/req.pem +15 -0
- data/spec/fixtures/testca/cacert.cer +0 -0
- data/spec/fixtures/testca/cacert.pem +17 -0
- data/spec/fixtures/testca/certs/01.pem +18 -0
- data/spec/fixtures/testca/certs/02.pem +18 -0
- data/spec/fixtures/testca/certs/05.pem +69 -0
- data/spec/fixtures/testca/certs/06.pem +69 -0
- data/spec/fixtures/testca/index.txt +4 -0
- data/spec/fixtures/testca/index.txt.attr +1 -0
- data/spec/fixtures/testca/index.txt.attr.old +1 -0
- data/spec/fixtures/testca/index.txt.old +3 -0
- data/spec/fixtures/testca/openssl.cnf +53 -0
- data/spec/fixtures/testca/private/cakey.pem +27 -0
- data/spec/fixtures/testca/serial +1 -0
- data/spec/fixtures/testca/serial.old +1 -0
- data/spec/inputs/rabbitmq_spec.rb +279 -0
- data/spec/outputs/rabbitmq_spec.rb +232 -0
- data/spec/plugin_mixins/rabbitmq_connection_spec.rb +175 -0
- metadata +256 -0
@@ -0,0 +1,131 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require "logstash/pipeline"
|
3
|
+
require_relative '../plugin_mixins/rabbitmq_connection'
|
4
|
+
java_import java.util.concurrent.TimeoutException
|
5
|
+
java_import com.rabbitmq.client.AlreadyClosedException
|
6
|
+
|
7
|
+
require 'back_pressure'
|
8
|
+
|
9
|
+
# Push events to a RabbitMQ exchange. Requires RabbitMQ 2.x
|
10
|
+
# or later version (3.x is recommended).
|
11
|
+
#
|
12
|
+
# Relevant links:
|
13
|
+
#
|
14
|
+
# * http://www.rabbitmq.com/[RabbitMQ]
|
15
|
+
# * http://rubymarchhare.info[March Hare]
|
16
|
+
module LogStash
|
17
|
+
module Outputs
|
18
|
+
class RabbitMQ < LogStash::Outputs::Base
|
19
|
+
include LogStash::PluginMixins::RabbitMQConnection
|
20
|
+
|
21
|
+
config_name "rabbitmq"
|
22
|
+
|
23
|
+
concurrency :shared
|
24
|
+
|
25
|
+
# The default codec for this plugin is JSON. You can override this to suit your particular needs however.
|
26
|
+
default :codec, "json"
|
27
|
+
|
28
|
+
# Key to route to by default. Defaults to 'logstash'
|
29
|
+
#
|
30
|
+
# * Routing keys are ignored on fanout exchanges.
|
31
|
+
config :key, :validate => :string, :default => "logstash"
|
32
|
+
|
33
|
+
# The name of the exchange
|
34
|
+
config :exchange, :validate => :string, :required => true
|
35
|
+
|
36
|
+
# The exchange type (fanout, topic, direct)
|
37
|
+
config :exchange_type, :validate => EXCHANGE_TYPES, :required => true
|
38
|
+
|
39
|
+
# Is this exchange durable? (aka; Should it survive a broker restart?)
|
40
|
+
config :durable, :validate => :boolean, :default => true
|
41
|
+
|
42
|
+
# Should RabbitMQ persist messages to disk?
|
43
|
+
config :persistent, :validate => :boolean, :default => true
|
44
|
+
|
45
|
+
# Properties to be passed along with the message
|
46
|
+
config :message_properties, :validate => :hash, :default => {}
|
47
|
+
|
48
|
+
def register
|
49
|
+
connect!
|
50
|
+
@hare_info.exchange = declare_exchange!(@hare_info.channel, @exchange, @exchange_type, @durable)
|
51
|
+
# The connection close should close all channels, so it is safe to store thread locals here without closing them
|
52
|
+
@thread_local_channel = java.lang.ThreadLocal.new
|
53
|
+
@thread_local_exchange = java.lang.ThreadLocal.new
|
54
|
+
|
55
|
+
@gated_executor = back_pressure_provider_for_connection(@hare_info.connection)
|
56
|
+
end
|
57
|
+
|
58
|
+
def symbolize(myhash)
|
59
|
+
Hash[myhash.map{|(k,v)| [k.to_sym,v]}]
|
60
|
+
end
|
61
|
+
|
62
|
+
def multi_receive_encoded(events_and_data)
|
63
|
+
events_and_data.each do |event, data|
|
64
|
+
publish(event, data)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def publish(event, message)
|
69
|
+
raise ArgumentError, "No exchange set in HareInfo!!!" unless @hare_info.exchange
|
70
|
+
@gated_executor.execute do
|
71
|
+
local_exchange.publish(message, :routing_key => event.sprintf(@key), :properties => symbolize(@message_properties.merge(:persistent => @persistent)))
|
72
|
+
end
|
73
|
+
rescue MarchHare::Exception, IOError, AlreadyClosedException, TimeoutException => e
|
74
|
+
@logger.error("Error while publishing. Will retry.",
|
75
|
+
:message => e.message,
|
76
|
+
:exception => e.class,
|
77
|
+
:backtrace => e.backtrace)
|
78
|
+
|
79
|
+
sleep_for_retry
|
80
|
+
retry
|
81
|
+
end
|
82
|
+
|
83
|
+
def local_exchange
|
84
|
+
exchange = @thread_local_exchange.get
|
85
|
+
if !exchange
|
86
|
+
exchange = declare_exchange!(local_channel, @exchange, @exchange_type, @durable)
|
87
|
+
@thread_local_exchange.set(exchange)
|
88
|
+
end
|
89
|
+
exchange
|
90
|
+
end
|
91
|
+
|
92
|
+
def local_channel
|
93
|
+
channel = @thread_local_channel.get
|
94
|
+
if !channel
|
95
|
+
channel = @hare_info.connection.create_channel
|
96
|
+
@thread_local_channel.set(channel)
|
97
|
+
end
|
98
|
+
channel
|
99
|
+
end
|
100
|
+
|
101
|
+
def close
|
102
|
+
close_connection
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
# When the other end of a RabbitMQ connection is either unwilling or unable to continue reading bytes from
|
108
|
+
# its underlying TCP stream, the connection is flagged as "blocked", but attempts to publish onto exchanges
|
109
|
+
# using the connection will not block in the client.
|
110
|
+
#
|
111
|
+
# Here we hook into notifications of connection-blocked state to set up a `BackPressure::GatedExecutor`,
|
112
|
+
# which is used elsewhere to prevent runaway writes when publishing to an exchange on a blocked connection.
|
113
|
+
def back_pressure_provider_for_connection(march_hare_connection)
|
114
|
+
BackPressure::GatedExecutor.new(description: "RabbitMQ[#{self.id}]", logger: logger).tap do |executor|
|
115
|
+
march_hare_connection.on_blocked do |reason|
|
116
|
+
executor.engage_back_pressure("connection flagged as blocked: `#{reason}`")
|
117
|
+
end
|
118
|
+
march_hare_connection.on_unblocked do
|
119
|
+
executor.remove_back_pressure('connection flagged as unblocked')
|
120
|
+
end
|
121
|
+
march_hare_connection.on_recovery_started do
|
122
|
+
executor.engage_back_pressure("connection is being recovered")
|
123
|
+
end
|
124
|
+
march_hare_connection.on_recovery do
|
125
|
+
executor.remove_back_pressure('connection recovered')
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,234 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "logstash/namespace"
|
3
|
+
require "march_hare"
|
4
|
+
require "java"
|
5
|
+
|
6
|
+
# Common functionality for the rabbitmq input/output
|
7
|
+
module LogStash
|
8
|
+
module PluginMixins
|
9
|
+
module RabbitMQConnection
|
10
|
+
EXCHANGE_TYPES = ["fanout", "direct", "topic", "x-consistent-hash", "x-modulus-hash"]
|
11
|
+
|
12
|
+
HareInfo = Struct.new(:connection, :channel, :exchange, :queue)
|
13
|
+
|
14
|
+
def self.included(base)
|
15
|
+
base.extend(self)
|
16
|
+
base.setup_rabbitmq_connection_config
|
17
|
+
end
|
18
|
+
|
19
|
+
def setup_rabbitmq_connection_config
|
20
|
+
# RabbitMQ server address(es)
|
21
|
+
# host can either be a single host, or a list of hosts
|
22
|
+
# i.e.
|
23
|
+
# host => "localhost"
|
24
|
+
# or
|
25
|
+
# host => ["host01", "host02]
|
26
|
+
#
|
27
|
+
# if multiple hosts are provided on the initial connection and any subsequent
|
28
|
+
# recovery attempts of the hosts is chosen at random and connected to.
|
29
|
+
# Note that only one host connection is active at a time.
|
30
|
+
config :host, :validate => :string, :required => true , :list => true
|
31
|
+
|
32
|
+
# RabbitMQ port to connect on
|
33
|
+
config :port, :validate => :number, :default => 5672
|
34
|
+
|
35
|
+
# RabbitMQ username
|
36
|
+
config :user, :validate => :string, :default => "guest"
|
37
|
+
|
38
|
+
# RabbitMQ password
|
39
|
+
config :password, :validate => :password, :default => "guest"
|
40
|
+
|
41
|
+
# The vhost (virtual host) to use. If you don't know what this
|
42
|
+
# is, leave the default. With the exception of the default
|
43
|
+
# vhost ("/"), names of vhosts should not begin with a forward
|
44
|
+
# slash.
|
45
|
+
config :vhost, :validate => :string, :default => "/"
|
46
|
+
|
47
|
+
# Enable or disable SSL.
|
48
|
+
# Note that by default remote certificate verification is off.
|
49
|
+
# Specify ssl_certificate_path and ssl_certificate_password if you need
|
50
|
+
# certificate verification
|
51
|
+
config :ssl, :validate => :boolean
|
52
|
+
|
53
|
+
# Version of the SSL protocol to use.
|
54
|
+
config :ssl_version, :validate => :string, :default => "TLSv1.2"
|
55
|
+
|
56
|
+
config :verify_ssl, :validate => :boolean, :default => false,
|
57
|
+
:obsolete => "This function did not actually function correctly and was removed." +
|
58
|
+
"If you wish to validate SSL certs use the ssl_certificate_path and ssl_certificate_password options."
|
59
|
+
|
60
|
+
# Path to an SSL certificate in PKCS12 (.p12) format used for verifying the remote host
|
61
|
+
config :ssl_certificate_path, :validate => :path
|
62
|
+
|
63
|
+
# Password for the encrypted PKCS12 (.p12) certificate file specified in ssl_certificate_path
|
64
|
+
config :ssl_certificate_password, :validate => :password
|
65
|
+
|
66
|
+
config :debug, :validate => :boolean, :obsolete => "Use the logstash --debug flag for this instead."
|
67
|
+
|
68
|
+
# Set this to automatically recover from a broken connection. You almost certainly don't want to override this!!!
|
69
|
+
config :automatic_recovery, :validate => :boolean, :default => true
|
70
|
+
|
71
|
+
# Time in seconds to wait before retrying a connection
|
72
|
+
config :connect_retry_interval, :validate => :number, :default => 1
|
73
|
+
|
74
|
+
# The default connection timeout in milliseconds. If not specified the timeout is infinite.
|
75
|
+
config :connection_timeout, :validate => :number
|
76
|
+
|
77
|
+
# Heartbeat delay in seconds. If unspecified no heartbeats will be sent
|
78
|
+
config :heartbeat, :validate => :number
|
79
|
+
|
80
|
+
# Passive queue creation? Useful for checking queue existance without modifying server state
|
81
|
+
config :passive, :validate => :boolean, :default => false
|
82
|
+
|
83
|
+
# TLS certifcate path
|
84
|
+
config :tls_certificate_path, :validate => :path, :obsolete => "This setting is obsolete. Use ssl_certificate_path instead"
|
85
|
+
|
86
|
+
# TLS certificate password
|
87
|
+
config :tls_certificate_password, :validate => :string, :obsolete => "This setting is obsolete. Use ssl_certificate_password instead"
|
88
|
+
|
89
|
+
# Extra queue arguments as an array.
|
90
|
+
# To make a RabbitMQ queue mirrored, use: `{"x-ha-policy" => "all"}`
|
91
|
+
config :arguments, :validate => :array, :default => {}
|
92
|
+
end
|
93
|
+
|
94
|
+
def conn_str
|
95
|
+
"amqp://#{@user}@#{@host}:#{@port}#{@vhost}"
|
96
|
+
end
|
97
|
+
|
98
|
+
def close_connection
|
99
|
+
@rabbitmq_connection_stopping = true
|
100
|
+
@hare_info.channel.close if channel_open?
|
101
|
+
@hare_info.connection.close if connection_open?
|
102
|
+
end
|
103
|
+
|
104
|
+
def rabbitmq_settings
|
105
|
+
return @rabbitmq_settings if @rabbitmq_settings
|
106
|
+
|
107
|
+
s = {
|
108
|
+
:vhost => @vhost,
|
109
|
+
:hosts => @host,
|
110
|
+
:port => @port,
|
111
|
+
:user => @user,
|
112
|
+
:automatic_recovery => @automatic_recovery,
|
113
|
+
:pass => @password ? @password.value : "guest",
|
114
|
+
}
|
115
|
+
|
116
|
+
s[:timeout] = @connection_timeout || 0
|
117
|
+
s[:heartbeat] = @heartbeat || 0
|
118
|
+
|
119
|
+
if @ssl
|
120
|
+
s[:tls] = @ssl_version
|
121
|
+
|
122
|
+
cert_path = @ssl_certificate_path
|
123
|
+
cert_pass = @ssl_certificate_password.value if @ssl_certificate_password
|
124
|
+
|
125
|
+
if !!cert_path ^ !!cert_pass
|
126
|
+
raise LogStash::ConfigurationError, "RabbitMQ requires both ssl_certificate_path AND ssl_certificate_password to be set!"
|
127
|
+
end
|
128
|
+
|
129
|
+
s[:tls_certificate_path] = cert_path
|
130
|
+
s[:tls_certificate_password] = cert_pass
|
131
|
+
end
|
132
|
+
|
133
|
+
@rabbitmq_settings = s
|
134
|
+
end
|
135
|
+
|
136
|
+
def connect!
|
137
|
+
@hare_info = connect() unless @hare_info # Don't duplicate the conn!
|
138
|
+
rescue MarchHare::Exception, java.io.IOException => e
|
139
|
+
error_message = if e.message.empty? && e.is_a?(java.io.IOException)
|
140
|
+
# IOException with an empty message is probably an instance of
|
141
|
+
# these problems:
|
142
|
+
# https://github.com/logstash-plugins/logstash-output-rabbitmq/issues/52
|
143
|
+
# https://github.com/rabbitmq/rabbitmq-java-client/issues/100
|
144
|
+
#
|
145
|
+
# Best guess is to help the user understand that there is probably
|
146
|
+
# some kind of configuration problem causing the error, but we
|
147
|
+
# can't really offer any more detailed hints :\
|
148
|
+
"An unknown error occurred. RabbitMQ gave no hints as to the cause. Maybe this is a configuration error (invalid vhost, for example). I recommend checking the RabbitMQ server logs for clues about this failure."
|
149
|
+
else
|
150
|
+
e.message
|
151
|
+
end
|
152
|
+
|
153
|
+
if @logger.debug?
|
154
|
+
@logger.error("RabbitMQ connection error, will retry.",
|
155
|
+
:error_message => error_message,
|
156
|
+
:exception => e.class.name,
|
157
|
+
:backtrace => e.backtrace)
|
158
|
+
else
|
159
|
+
@logger.error("RabbitMQ connection error, will retry.",
|
160
|
+
:error_message => error_message,
|
161
|
+
:exception => e.class.name)
|
162
|
+
end
|
163
|
+
|
164
|
+
sleep_for_retry
|
165
|
+
retry
|
166
|
+
end
|
167
|
+
|
168
|
+
def channel_open?
|
169
|
+
@hare_info && @hare_info.channel && @hare_info.channel.open?
|
170
|
+
end
|
171
|
+
|
172
|
+
def connection_open?
|
173
|
+
@hare_info && @hare_info.connection && @hare_info.connection.open?
|
174
|
+
end
|
175
|
+
|
176
|
+
def connected?
|
177
|
+
return nil unless @hare_info && @hare_info.connection
|
178
|
+
@hare_info.connection.connected?
|
179
|
+
end
|
180
|
+
|
181
|
+
private
|
182
|
+
|
183
|
+
def declare_exchange!(channel, exchange, exchange_type, durable)
|
184
|
+
@logger.debug? && @logger.debug("Declaring an exchange", :name => exchange,
|
185
|
+
:type => exchange_type, :durable => durable)
|
186
|
+
exchange = channel.exchange(exchange, :type => exchange_type.to_sym, :durable => durable)
|
187
|
+
@logger.debug? && @logger.debug("Exchange declared")
|
188
|
+
exchange
|
189
|
+
rescue StandardError => e
|
190
|
+
@logger.error("Could not declare exchange!",
|
191
|
+
:exchange => exchange, :type => exchange_type,
|
192
|
+
:durable => durable, :error_class => e.class.name,
|
193
|
+
:error_message => e.message, :backtrace => e.backtrace)
|
194
|
+
raise e
|
195
|
+
end
|
196
|
+
|
197
|
+
def connect
|
198
|
+
@logger.debug? && @logger.debug("Connecting to RabbitMQ. Settings: #{rabbitmq_settings.inspect}")
|
199
|
+
|
200
|
+
connection = MarchHare.connect(rabbitmq_settings)
|
201
|
+
|
202
|
+
connection.on_shutdown do |conn, cause|
|
203
|
+
@logger.warn("RabbitMQ connection was closed!",
|
204
|
+
:url => connection_url(conn),
|
205
|
+
:automatic_recovery => @automatic_recovery,
|
206
|
+
:cause => cause)
|
207
|
+
end
|
208
|
+
connection.on_blocked do
|
209
|
+
@logger.warn("RabbitMQ connection blocked! Check your RabbitMQ instance!",
|
210
|
+
:url => connection_url(connection))
|
211
|
+
end
|
212
|
+
connection.on_unblocked do
|
213
|
+
@logger.warn("RabbitMQ connection unblocked!", :url => connection_url(connection))
|
214
|
+
end
|
215
|
+
|
216
|
+
channel = connection.create_channel
|
217
|
+
@logger.info("Connected to RabbitMQ at #{rabbitmq_settings[:host]}")
|
218
|
+
|
219
|
+
HareInfo.new(connection, channel)
|
220
|
+
end
|
221
|
+
|
222
|
+
# Mostly used for printing debug logs
|
223
|
+
def connection_url(connection)
|
224
|
+
user_pass = connection.user ? "#{connection.user}:XXXXXX@" : ""
|
225
|
+
protocol = params["ssl"] ? "amqps" : "amqp"
|
226
|
+
"#{protocol}://#{user_pass}#{connection.host}:#{connection.port}#{connection.vhost}"
|
227
|
+
end
|
228
|
+
|
229
|
+
def sleep_for_retry
|
230
|
+
Stud.stoppable_sleep(@connect_retry_interval) { @rabbitmq_connection_stopping }
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "logstash/plugins/registry"
|
3
|
+
require "logstash/inputs/rabbitmq"
|
4
|
+
require "logstash/outputs/rabbitmq"
|
5
|
+
|
6
|
+
LogStash::PLUGIN_REGISTRY.add(:input, "rabbitmq", LogStash::Inputs::RabbitMQ)
|
7
|
+
LogStash::PLUGIN_REGISTRY.add(:output, "rabbitmq", LogStash::Outputs::RabbitMQ)
|
@@ -0,0 +1,53 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'logstash-integration-rabbitmq'
|
3
|
+
s.version = '7.0.0'
|
4
|
+
s.licenses = ['Apache License (2.0)']
|
5
|
+
s.summary = "Integration with RabbitMQ - input and output plugins"
|
6
|
+
s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline "+
|
7
|
+
"using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program."
|
8
|
+
s.authors = ["Elastic"]
|
9
|
+
s.email = 'info@elastic.co'
|
10
|
+
s.homepage = "http://www.elastic.co/guide/en/logstash/current/index.html"
|
11
|
+
s.require_paths = ["lib"]
|
12
|
+
|
13
|
+
# Files
|
14
|
+
s.files = Dir.glob(%w(
|
15
|
+
lib/**/*
|
16
|
+
spec/**/*
|
17
|
+
*.gemspec
|
18
|
+
*.md
|
19
|
+
CONTRIBUTORS
|
20
|
+
Gemfile
|
21
|
+
LICENSE
|
22
|
+
NOTICE.TXT
|
23
|
+
vendor/jar-dependencies/**/*.jar
|
24
|
+
vendor/jar-dependencies/**/*.rb
|
25
|
+
VERSION docs/**/*
|
26
|
+
))
|
27
|
+
|
28
|
+
# Tests
|
29
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
30
|
+
|
31
|
+
# Special flag to let us know this is actually a logstash plugin
|
32
|
+
s.metadata = {
|
33
|
+
"logstash_plugin" => "true",
|
34
|
+
"logstash_group" => "integration",
|
35
|
+
"integration_plugins" => "logstash-input-rabbitmq,logstash-output-rabbitmq"
|
36
|
+
}
|
37
|
+
|
38
|
+
s.platform = RUBY_PLATFORM
|
39
|
+
|
40
|
+
# Gem dependencies
|
41
|
+
s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
|
42
|
+
s.add_runtime_dependency "logstash-core", ">= 6.5.0"
|
43
|
+
|
44
|
+
s.add_runtime_dependency 'logstash-codec-json'
|
45
|
+
|
46
|
+
s.add_runtime_dependency 'march_hare', ['~> 4.0'] #(MIT license)
|
47
|
+
s.add_runtime_dependency 'stud', '~> 0.0.22'
|
48
|
+
s.add_runtime_dependency 'back_pressure', '~> 1.0'
|
49
|
+
|
50
|
+
s.add_development_dependency 'logstash-devutils'
|
51
|
+
s.add_development_dependency 'logstash-input-generator'
|
52
|
+
s.add_development_dependency 'logstash-codec-plain'
|
53
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
# TLS Testing notes
|
2
|
+
|
3
|
+
Currently all TLS integration style testing is manual. This fixture may be used to help test.
|
4
|
+
|
5
|
+
* client - has the key store with client public/private key and the server public key
|
6
|
+
* server - has the key store with server public/private key and the client public key
|
7
|
+
* client_untrusted - has a keystore with public/private key that is self signed
|
8
|
+
|
9
|
+
logstash config
|
10
|
+
---------
|
11
|
+
```
|
12
|
+
input {
|
13
|
+
rabbitmq {
|
14
|
+
host => "localhost"
|
15
|
+
port => 5671
|
16
|
+
queue => "hello"
|
17
|
+
codec => plain
|
18
|
+
ssl => true
|
19
|
+
ssl_certificate_path => "/Users/jake/workspace/plugins/logstash-mixin-rabbitmq_connection/spec/fixtures/client/keycert.p12"
|
20
|
+
ssl_certificate_password => "MySecretPassword"
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
output{ stdout { codec => rubydebug } }
|
25
|
+
```
|
26
|
+
|
27
|
+
rabbit mq install
|
28
|
+
--------
|
29
|
+
(mac)
|
30
|
+
|
31
|
+
```
|
32
|
+
brew install rabbitmq
|
33
|
+
export PATH=$PATH:/usr/local/sbin
|
34
|
+
vim /usr/local/etc/rabbitmq/rabbitmq.config
|
35
|
+
|
36
|
+
```
|
37
|
+
```
|
38
|
+
[
|
39
|
+
{rabbit, [
|
40
|
+
{ssl_listeners, [5671]},
|
41
|
+
{ssl_options, [{cacertfile,"/Users/jake/workspace/plugins/logstash-mixin-rabbitmq_connection/spec/fixtures/testca/cacert.pem"},
|
42
|
+
{certfile,"/Users/jake/workspace/plugins/logstash-mixin-rabbitmq_connection/spec/fixtures/server/cert.pem"},
|
43
|
+
{keyfile,"/Users/jake/workspace/plugins/logstash-mixin-rabbitmq_connection/spec/fixtures/server/key.pem"},
|
44
|
+
{verify,verify_peer},
|
45
|
+
{fail_if_no_peer_cert,false}]}
|
46
|
+
]}
|
47
|
+
].
|
48
|
+
```
|
49
|
+
```
|
50
|
+
export PATH=$PATH:/usr/local/sbin
|
51
|
+
rabbitmq-server
|
52
|
+
tail -f /usr/local/var/log/rabbitmq/rabbit@localhost.log
|
53
|
+
```
|
54
|
+
|
55
|
+
sending a test message with ruby
|
56
|
+
----------
|
57
|
+
https://www.rabbitmq.com/tutorials/tutorial-one-ruby.html
|
58
|
+
|
59
|
+
```
|
60
|
+
gem install bunny --version ">= 2.6.4"
|
61
|
+
```
|
62
|
+
Create a file called send.rb
|
63
|
+
```
|
64
|
+
#!/usr/bin/env ruby
|
65
|
+
# encoding: utf-8
|
66
|
+
|
67
|
+
require "bunny"
|
68
|
+
|
69
|
+
conn = Bunny.new(:automatically_recover => false)
|
70
|
+
conn.start
|
71
|
+
|
72
|
+
ch = conn.create_channel
|
73
|
+
q = ch.queue("hello")
|
74
|
+
|
75
|
+
ch.default_exchange.publish("Test message", :routing_key => q.name)
|
76
|
+
puts "Message sent'"
|
77
|
+
|
78
|
+
conn.close
|
79
|
+
```
|
80
|
+
Send the message with Logstash running as the consumer
|
81
|
+
```
|
82
|
+
ruby send.rb
|
83
|
+
```
|
84
|
+
|
85
|
+
password for all files
|
86
|
+
--------
|
87
|
+
MySecretPassword
|
88
|
+
|
89
|
+
start from testca dir
|
90
|
+
---------
|
91
|
+
```
|
92
|
+
cd testca
|
93
|
+
```
|
94
|
+
|
95
|
+
client
|
96
|
+
-------
|
97
|
+
```
|
98
|
+
openssl genrsa -out ../client/key.pem 2048
|
99
|
+
openssl req -config openssl.cnf -key ../client/key.pem -new -sha256 -out ../client/req.pem
|
100
|
+
# for hostname use localhost, O=client
|
101
|
+
openssl ca -config openssl.cnf -in ../client/req.pem -out ../client/cert.pem
|
102
|
+
openssl x509 -in ../client/cert.pem -text -noout
|
103
|
+
openssl pkcs12 -export -out ../client/keycert.p12 -inkey ../client/key.pem -in ../client/cert.pem
|
104
|
+
```
|
105
|
+
|
106
|
+
server
|
107
|
+
-------
|
108
|
+
```
|
109
|
+
openssl genrsa -out ../server/key.pem 2048
|
110
|
+
openssl req -config openssl.cnf -key ../server/key.pem -new -sha256 -out ../server/req.pem
|
111
|
+
# for hostname use localhost, O=server
|
112
|
+
openssl ca -config openssl.cnf -in ../server/req.pem -out ../server/cert.pem
|
113
|
+
openssl x509 -in ../server/cert.pem -text -noout
|
114
|
+
openssl pkcs12 -export -out ../server/keycert.p12 -inkey ../server/key.pem -in ../server/cert.pem
|
115
|
+
```
|
116
|
+
|
117
|
+
establish trust
|
118
|
+
----------
|
119
|
+
```
|
120
|
+
cd server
|
121
|
+
keytool -import -file ../client/cert.pem -alias client_cert -keystore keycert.p12
|
122
|
+
cd client
|
123
|
+
keytool -import -file ../server/cert.pem -alias server_cert -keystore keycert.p12
|
124
|
+
```
|
125
|
+
|
126
|
+
reading
|
127
|
+
-----------
|
128
|
+
```
|
129
|
+
openssl x509 -in cert.pem -text -noout
|
130
|
+
keytool -list -v -keystore keycert.p12
|
131
|
+
```
|
132
|
+
|
133
|
+
self signed cert (untrusted)
|
134
|
+
-------
|
135
|
+
```
|
136
|
+
openssl req -x509 -batch -nodes -newkey rsa:2048 -keyout key.pem -out cert.pem -subj "/CN=localhost, O=client" -days 10000
|
137
|
+
openssl pkcs12 -export -out keycert.p12 -inkey key.pem -in cert.pem
|
138
|
+
|
139
|
+
```
|
140
|
+
|
141
|
+
Issue [44](https://github.com/logstash-plugins/logstash-mixin-rabbitmq_connection/issues/44) validation
|
142
|
+
---------
|
143
|
+
configure Logstash to the untrusted cert :`ssl_certificate_path => "/Users/jake/workspace/plugins/logstash-mixin-rabbitmq_connection/spec/fixtures/client_untrusted/keycert.p12"`
|
144
|
+
|
145
|
+
This _SHOULD_ fail an error like the following:
|
146
|
+
```
|
147
|
+
Using TLS/SSL version TLSv1.2
|
148
|
+
[2017-12-19T12:47:12,891][ERROR][logstash.inputs.rabbitmq ] RabbitMQ connection error, will retry. {:error_message=>"sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target", :exception=>"Java::JavaxNetSsl::SSLHandshakeException"}
|
149
|
+
```
|
150
|
+
There should _NOT_ be any warnings about a NullTrustManager or disabling verification, and you should _NOT_ be able to send messages.
|