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.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +9 -0
  3. data/CONTRIBUTORS +27 -0
  4. data/Gemfile +11 -0
  5. data/LICENSE +13 -0
  6. data/NOTICE.TXT +5 -0
  7. data/README.md +98 -0
  8. data/docs/index.asciidoc +29 -0
  9. data/docs/input-rabbitmq.asciidoc +398 -0
  10. data/docs/output-rabbitmq.asciidoc +272 -0
  11. data/lib/logstash/inputs/rabbitmq.rb +317 -0
  12. data/lib/logstash/outputs/rabbitmq.rb +131 -0
  13. data/lib/logstash/plugin_mixins/rabbitmq_connection.rb +234 -0
  14. data/lib/logstash_registry.rb +7 -0
  15. data/logstash-integration-rabbitmq.gemspec +53 -0
  16. data/spec/fixtures/README.md +150 -0
  17. data/spec/fixtures/client/cert.pem +69 -0
  18. data/spec/fixtures/client/key.pem +27 -0
  19. data/spec/fixtures/client/keycert.p12 +0 -0
  20. data/spec/fixtures/client/req.pem +15 -0
  21. data/spec/fixtures/client_untrusted/cert.pem +19 -0
  22. data/spec/fixtures/client_untrusted/key.pem +28 -0
  23. data/spec/fixtures/client_untrusted/keycert.p12 +0 -0
  24. data/spec/fixtures/server/cert.pem +69 -0
  25. data/spec/fixtures/server/key.pem +27 -0
  26. data/spec/fixtures/server/key_password +1 -0
  27. data/spec/fixtures/server/keycert.p12 +0 -0
  28. data/spec/fixtures/server/rabbitmq.config +10 -0
  29. data/spec/fixtures/server/req.pem +15 -0
  30. data/spec/fixtures/testca/cacert.cer +0 -0
  31. data/spec/fixtures/testca/cacert.pem +17 -0
  32. data/spec/fixtures/testca/certs/01.pem +18 -0
  33. data/spec/fixtures/testca/certs/02.pem +18 -0
  34. data/spec/fixtures/testca/certs/05.pem +69 -0
  35. data/spec/fixtures/testca/certs/06.pem +69 -0
  36. data/spec/fixtures/testca/index.txt +4 -0
  37. data/spec/fixtures/testca/index.txt.attr +1 -0
  38. data/spec/fixtures/testca/index.txt.attr.old +1 -0
  39. data/spec/fixtures/testca/index.txt.old +3 -0
  40. data/spec/fixtures/testca/openssl.cnf +53 -0
  41. data/spec/fixtures/testca/private/cakey.pem +27 -0
  42. data/spec/fixtures/testca/serial +1 -0
  43. data/spec/fixtures/testca/serial.old +1 -0
  44. data/spec/inputs/rabbitmq_spec.rb +279 -0
  45. data/spec/outputs/rabbitmq_spec.rb +232 -0
  46. data/spec/plugin_mixins/rabbitmq_connection_spec.rb +175 -0
  47. 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.