logstash-integration-rabbitmq 7.0.0-java
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|