logstash-integration-elastic_enterprise_search 2.2.1 → 3.0.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2f0c1374a08bc723fd7452e115e7372c8e0bb416c6e7e2e6d10769b15b571b7c
4
- data.tar.gz: 53debfd033dae11b5d5c80809c51c8a6db5997c80f5eeb3901414932c0d48e17
3
+ metadata.gz: b06802185d7a0e45e13ac9a3f5a952901e7fdd186d78c50dd5f38c7db18f2c41
4
+ data.tar.gz: 263045ba6b2947b74a418b663de0dcdf63f67475bb99ac4f1252f5bfd6cec4b1
5
5
  SHA512:
6
- metadata.gz: dcb96b16bafc1b85a0e4e375925b8d6ad5e6f3366044e1ea13b4318ab0c5b75b84d342fe76077ddcc30f4b0423f0e47028b474d2012e34570357a07ad9ff94e8
7
- data.tar.gz: fab4c000386cca49902de6f11aa392d95032b4fd7897826fc7515dac40012315c2356d1c624485b4689faf229b7455176845ac40cdf3c298e596ad517a545a93
6
+ metadata.gz: d294f1592ce25cb470ddd7746e095974b005722a022c6eb8faad76f30ac8d895c02b9afa1be2d9715e5d25fd4c1eb8a206e22b15d1ed84f9f27fb0e21d4806bc
7
+ data.tar.gz: 99fe5e6638912b63c977cca07f85456e00a627dee50475d5e5fa628a49fe062c0f77b7c1994c208391d1675240df755e1f3de4d6e32e9160ea48408b0a318572
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## 3.0.0
2
+ - Bumped Enterprise Search clients to version `>= 7.16`, `< 9` [#18](https://github.com/logstash-plugins/logstash-integration-elastic_enterprise_search/pull/18)
3
+ - Added support to SSL configurations (`ssl_certificate_authorities`, `ssl_truststore_path`, `ssl_truststore_password`, `ssl_truststore_type`, `ssl_verification_mode`, `ssl_supported_protocols` and `ssl_cipher_suites`)
4
+ - [BREAKING] Swiftype endpoints are no longer supported for both plugins App Search and Workplace Search
5
+ - The App Search deprecated options `host` and `path` were removed
6
+ - Fixed the sprintf format support for the Workplace Search `source` configuration
7
+
1
8
  ## 2.2.1
2
9
  - Fix, change implementation of connectivity check method to be compatible with version `v8.0+` of Workplace Search [#16](https://github.com/logstash-plugins/logstash-integration-elastic_enterprise_search/pull/16)
3
10
 
data/README.md CHANGED
@@ -88,6 +88,16 @@ bin/plugin install --no-verify
88
88
  ```
89
89
  - Start Logstash and proceed to test the plugin
90
90
 
91
+ ### Thoubleshooting integration test failures
92
+ Integration tests uses some certificates fixtures. These security artifacts has 1 year expiration, so time to time
93
+ they would trigger errors due to bad certificate.
94
+ To regenerate use:
95
+ ```sh
96
+ > cd spec/fixture/certificates
97
+ > ./generate.sh
98
+ ```
99
+ Re-run locally the integration tests (with Docker scripts) and if it's green again create a PR to update.
100
+
91
101
  ## Contributing
92
102
 
93
103
  All contributions are welcome: ideas, patches, documentation, bug reports, complaints, and even something you drew up on a napkin.
@@ -1,13 +1,13 @@
1
1
  # encoding: utf-8
2
- require "logstash/outputs/base"
3
- require "elastic-app-search"
4
- require "elastic-enterprise-search"
5
- require 'logstash/plugin_mixins/deprecation_logger_support'
2
+ require 'logstash/outputs/base'
3
+ require 'logstash/plugin_mixins/enterprise_search/ssl_configs'
4
+ require 'logstash/plugin_mixins/enterprise_search/client'
6
5
 
7
6
  class LogStash::Outputs::ElasticAppSearch < LogStash::Outputs::Base
8
- include LogStash::PluginMixins::DeprecationLoggerSupport
9
7
 
10
- config_name "elastic_app_search"
8
+ include LogStash::PluginMixins::EnterpriseSearch::SSLConfigs
9
+
10
+ config_name 'elastic_app_search'
11
11
 
12
12
  # The name of the search engine you created in App Search, an information
13
13
  # repository that includes the indexed document records.
@@ -21,16 +21,11 @@ class LogStash::Outputs::ElasticAppSearch < LogStash::Outputs::Base
21
21
  # or, if the field is missing from the event and cannot be resolved at all.
22
22
  config :engine, :validate => :string, :required => true
23
23
 
24
- # The hostname of the App Search API that is associated with your App Search account.
25
- # Set this when using the https://www.elastic.co/cloud/app-search-service
26
- config :host, :validate => :string
27
-
28
- # The value of the API endpoint in the form of a URL. Note: The value of the of the `path` setting will be will be appended to this URL.
29
- # Set this when using the https://www.elastic.co/downloads/app-search
30
- config :url, :validate => :string
24
+ # The value of the API endpoint in the form of a URL.
25
+ config :url, :validate => :string, :required => true, :default => Elastic::EnterpriseSearch::Utils::DEFAULT_HOST
31
26
 
32
- # The private API Key with write permissions. Visit the https://app.swiftype.com/as/credentials
33
- # in the App Search dashboard to find the key associated with your account.
27
+ # The private API Key with write permissions.
28
+ # https://www.elastic.co/guide/en/app-search/current/authentication.html#authentication-api-keys
34
29
  config :api_key, :validate => :password, :required => true
35
30
 
36
31
  # Where to move the value from the `@timestamp` field.
@@ -46,57 +41,42 @@ class LogStash::Outputs::ElasticAppSearch < LogStash::Outputs::Base
46
41
  # like `myapp-%{sequence_id}`. Reusing ids will cause documents to be rewritten.
47
42
  config :document_id, :validate => :string
48
43
 
49
- # The path that is appended to the `url` parameter when connecting to a https://www.elastic.co/downloads/app-search
50
- config :path, :validate => :string, :default => "/api/as/v1/"
51
-
52
- ENGINE_WITH_SPRINTF_REGEX = /^.*%\{.+\}.*$/
44
+ ENGINE_WITH_SPRINTF_REGEX = /^.*%\{.+\}.*$/.freeze
53
45
 
54
- public
55
46
  def register
56
- @use_old_client = false
57
- if @host.nil? && @url.nil?
58
- raise ::LogStash::ConfigurationError.new("Please specify either \"url\" (for self-managed) or \"host\" (for SaaS).")
59
- elsif @host && @url
60
- raise ::LogStash::ConfigurationError.new("Both \"url\" or \"host\" can't be set simultaneously. Please specify either \"url\" (for self-managed ot Elastic Enterprise Search) or \"host\" (for SaaS).")
61
- elsif @host && path_is_set? # because path has a default value we need extra work to if the user set it
62
- raise ::LogStash::ConfigurationError.new("The setting \"path\" is not compatible with \"host\". Use \"path\" only with \"url\".")
63
- elsif @host
64
- @deprecation_logger.deprecated("Deprecated service usage, the `host` setting will be removed when Swiftype AppSearch service is shutdown")
65
- @use_old_client = true
66
- @client = Elastic::AppSearch::Client.new(:host_identifier => @host, :api_key => @api_key.value)
67
- elsif @url
68
- if path_is_set?
69
- @deprecation_logger.deprecated("Deprecated service usage, the `path` setting will be removed when Swiftype AppSearch service is shutdown")
70
- @use_old_client = true
71
- @client = Elastic::AppSearch::Client.new(:api_endpoint => @url + @path, :api_key => @api_key.value)
72
- else
73
- @client = Elastic::EnterpriseSearch::AppSearch::Client.new(:host => @url, :http_auth => @api_key.value, :external_url => @url)
74
- end
75
- end
76
- check_connection! unless @engine =~ ENGINE_WITH_SPRINTF_REGEX
47
+ @retry_disabled = false
48
+ @client = LogStash::PluginMixins::EnterpriseSearch::AppSearch::Client.new(client_options, params: params)
49
+ check_connection!
77
50
  rescue => e
78
51
  if e.message =~ /401/
79
- raise ::LogStash::ConfigurationError.new("Failed to connect to App Search. Error: 401. Please check your credentials")
52
+ raise ::LogStash::ConfigurationError, "Failed to connect to App Search. Please check your credentials. Error: #{e.message}"
80
53
  elsif e.message =~ /404/
81
- raise ::LogStash::ConfigurationError.new("Failed to connect to App Search. Error: 404. Please check if host '#{@host}' is correct and you've created an engine with name '#{@engine}'")
54
+ raise ::LogStash::ConfigurationError, "Failed to connect to App Search. Please check if url '#{@url}' is correct and you've created an engine with name '#{@engine}'. Error: #{e.message}"
82
55
  else
83
- raise ::LogStash::ConfigurationError.new("Failed to connect to App Search. #{e.message}")
56
+ raise ::LogStash::ConfigurationError, "Failed to connect to App Search. Error: #{e.message}"
84
57
  end
85
58
  end
86
59
 
87
- public
88
60
  def multi_receive(events)
89
61
  # because App Search has a limit of 100 documents per bulk
90
62
  events.each_slice(100) do |events|
91
63
  batch = format_batch(events)
92
64
  if @logger.trace?
93
- @logger.trace("Sending bulk to App Search", :size => batch.size, :data => batch.inspect)
65
+ @logger.trace('Sending bulk to App Search', :size => batch.size, :data => batch.inspect)
94
66
  end
95
67
  index(batch)
96
68
  end
97
69
  end
98
70
 
99
71
  private
72
+
73
+ def client_options
74
+ options = { :host => @url, :http_auth => @api_key.value }
75
+ options[:logger] = @logger if @logger.debug?
76
+ options[:tracer] = @logger if @logger.trace?
77
+ options
78
+ end
79
+
100
80
  def format_batch(events)
101
81
  docs_for_engine = {}
102
82
  events.each do |event|
@@ -104,18 +84,18 @@ class LogStash::Outputs::ElasticAppSearch < LogStash::Outputs::Base
104
84
  # we need to remove default fields that start with "@"
105
85
  # since Elastic App Search doesn't accept them
106
86
  if @timestamp_destination
107
- doc[@timestamp_destination] = doc.delete("@timestamp")
87
+ doc[@timestamp_destination] = doc.delete('@timestamp')
108
88
  else # delete it
109
- doc.delete("@timestamp")
89
+ doc.delete('@timestamp')
110
90
  end
111
91
  if @document_id
112
- doc["id"] = event.sprintf(@document_id)
92
+ doc['id'] = event.sprintf(@document_id)
113
93
  end
114
- doc.delete("@version")
94
+ doc.delete('@version')
115
95
  resolved_engine = event.sprintf(@engine)
116
96
  unless docs_for_engine[resolved_engine]
117
97
  if @logger.debug?
118
- @logger.debug("Creating new engine segment in batch to send", :resolved_engine => resolved_engine)
98
+ @logger.debug('Creating new engine segment in batch to send', :resolved_engine => resolved_engine)
119
99
  end
120
100
  docs_for_engine[resolved_engine] = []
121
101
  end
@@ -124,21 +104,21 @@ class LogStash::Outputs::ElasticAppSearch < LogStash::Outputs::Base
124
104
  docs_for_engine
125
105
  end
126
106
 
127
- def index(batch)
128
- batch.each do |resolved_engine, documents|
107
+ def index(docs_partitioned_by_engine)
108
+ docs_partitioned_by_engine.each do |resolved_engine, documents|
129
109
  begin
130
110
  if resolved_engine =~ ENGINE_WITH_SPRINTF_REGEX || resolved_engine =~ /^\s*$/
131
111
  raise "Cannot resolve engine field name #{@engine} from event"
132
112
  end
133
- if connected_to_swiftype?
134
- response = @client.index_documents(resolved_engine, documents)
135
- else
136
- response = @client.index_documents(resolved_engine, {:documents => documents})
137
- end
113
+
114
+ response = @client.index_documents(resolved_engine, { :documents => documents })
138
115
  report(documents, response)
139
116
  rescue => e
140
- @logger.error("Failed to execute index operation. Retrying..", :exception => e.class, :reason => e.message,
141
- :resolved_engine => resolved_engine, :backtrace => e.backtrace)
117
+ @logger.error('Failed to execute index operation.', :exception => e.class, :reason => e.message,
118
+ :resolved_engine => resolved_engine, :backtrace => e.backtrace, :retry => !@retry_disabled)
119
+
120
+ raise e if @retry_disabled
121
+
142
122
  sleep(1)
143
123
  retry
144
124
  end
@@ -147,33 +127,17 @@ class LogStash::Outputs::ElasticAppSearch < LogStash::Outputs::Base
147
127
 
148
128
  def report(documents, response)
149
129
  documents.each_with_index do |document, i|
150
- if connected_to_swiftype?
151
- errors = response[i]["errors"]
152
- else
153
- errors = response.body[i]["errors"]
154
- end
130
+ errors = response.body[i]['errors']
155
131
  if errors.empty?
156
- @logger.trace? && @logger.trace("Document was indexed with no errors", :document => document)
132
+ @logger.trace? && @logger.trace('Document was indexed with no errors', :document => document)
157
133
  else
158
- @logger.warn("Document failed to index. Dropping..", :document => document, :errors => errors.to_a)
134
+ @logger.warn('Document failed to index. Dropping..', :document => document, :errors => errors.to_a)
159
135
  end
160
136
  end
161
137
  end
162
138
 
163
139
  def check_connection!
164
- if connected_to_swiftype?
165
- @client.get_engine(@engine)
166
- else
167
- res = @client.list_engines({:page_size => 1})
168
- raise "Received HTTP error code #{res.status}" unless res.status == 200
169
- end
170
- end
171
-
172
- def path_is_set?
173
- original_params.key?("path")
174
- end
175
-
176
- def connected_to_swiftype?
177
- @use_old_client
140
+ res = @client.list_engines({ 'page[size]': 1 })
141
+ raise "Received HTTP error code #{res.status}" unless res.status == 200
178
142
  end
179
143
  end
@@ -1,12 +1,16 @@
1
1
  # encoding: utf-8
2
- require "logstash/outputs/base"
3
- require "elastic-workplace-search"
2
+ require 'logstash/outputs/base'
3
+ require 'logstash/plugin_mixins/enterprise_search/client'
4
+ require 'logstash/plugin_mixins/enterprise_search/ssl_configs'
4
5
 
5
6
  class LogStash::Outputs::ElasticWorkplaceSearch < LogStash::Outputs::Base
6
- config_name "elastic_workplace_search"
7
+
8
+ include LogStash::PluginMixins::EnterpriseSearch::SSLConfigs
9
+
10
+ config_name 'elastic_workplace_search'
7
11
 
8
12
  # The value of the API endpoint in the form of a URL.
9
- config :url, :validate => :string, :required => true
13
+ config :url, :validate => :string, :required => true, :default => Elastic::EnterpriseSearch::Utils::DEFAULT_HOST
10
14
 
11
15
  # The ID of the source you created in Workplace Search.
12
16
  # The `source` field supports
@@ -36,72 +40,98 @@ class LogStash::Outputs::ElasticWorkplaceSearch < LogStash::Outputs::Base
36
40
  # like `myapp-%{sequence_id}`. Reusing ids will cause documents to be rewritten.
37
41
  config :document_id, :validate => :string
38
42
 
39
- public
43
+ SOURCE_WITH_SPRINTF_REGEX = /^.*%\{.+\}.*$/.freeze
44
+
40
45
  def register
41
- Elastic::WorkplaceSearch.endpoint = "#{@url.chomp('/')}/api/ws/v1/"
42
- @client = Elastic::WorkplaceSearch::Client.new(:access_token => @access_token.value)
43
- check_connection!
44
- rescue Elastic::WorkplaceSearch::InvalidCredentials
45
- raise ::LogStash::ConfigurationError.new("Failed to connect to Workplace Search. Error: 401. Please check your credentials")
46
- rescue Elastic::WorkplaceSearch::NonExistentRecord
47
- raise ::LogStash::ConfigurationError.new("Failed to connect to Workplace Search. Error: 404. Please check if url '#{@url}' is correct and you've created a source with ID '#{@source}'")
48
- rescue => e
49
- raise ::LogStash::ConfigurationError.new("Failed to connect to Workplace Search. #{e.message}")
46
+ @retry_disabled = false
47
+ @client = LogStash::PluginMixins::EnterpriseSearch::WorkplaceSearch::Client.new(client_options, params: params)
48
+ begin
49
+ check_connection!
50
+ rescue => e
51
+ raise ::LogStash::ConfigurationError, "Failed to connect to Workplace Search. Error: #{e.message}"
52
+ end
50
53
  end
51
54
 
52
- public
53
55
  def multi_receive(events)
54
56
  # because Workplace Search has a limit of 100 documents per bulk
55
57
  events.each_slice(100) do |events|
56
58
  batch = format_batch(events)
57
- if @logger.trace?
58
- @logger.trace("Sending bulk to Workplace Search", :size => batch.size, :data => batch.inspect)
59
- end
59
+ @logger.trace('Sending bulk to Workplace Search', :size => batch.size, :data => batch.inspect) if @logger.trace?
60
60
  index(batch)
61
61
  end
62
62
  end
63
63
 
64
64
  private
65
+
66
+ def client_options
67
+ options = { :host => @url, :http_auth => @access_token.value }
68
+ options[:logger] = @logger if @logger.debug?
69
+ options[:tracer] = @logger if @logger.trace?
70
+ options
71
+ end
72
+
65
73
  def format_batch(events)
74
+ docs_per_source = {}
66
75
  events.map do |event|
67
76
  doc = event.to_hash
68
77
  # we need to remove default fields that start with "@"
69
78
  # since Elastic Workplace Search doesn't accept them
70
79
  if @timestamp_destination
71
- doc[@timestamp_destination] = doc.delete("@timestamp")
80
+ doc[@timestamp_destination] = doc.delete('@timestamp')
72
81
  else # delete it
73
- doc.delete("@timestamp")
82
+ doc.delete('@timestamp')
83
+ end
84
+
85
+ doc['id'] = event.sprintf(@document_id) if @document_id
86
+ doc.delete('@version')
87
+
88
+ resolved_source = event.sprintf(@source)
89
+ unless docs_per_source[resolved_source]
90
+ @logger.debug('Creating new source segment in batch to send', resolved_source: resolved_source) if @logger.debug?
91
+ docs_per_source[resolved_source] = []
74
92
  end
75
- if @document_id
76
- doc["id"] = event.sprintf(@document_id)
93
+ docs_per_source[resolved_source] << doc
94
+ end
95
+
96
+ docs_per_source
97
+ end
98
+
99
+ def index(docs_partitioned_by_source)
100
+ docs_partitioned_by_source.each do |resolved_source, documents|
101
+ begin
102
+ raise "Cannot resolve source field name #{@source} from event" unless resolved?(resolved_source)
103
+
104
+ response = @client.index_documents(resolved_source, { :documents => documents })
105
+ report(documents, response)
106
+ rescue => e
107
+ @logger.error('Failed to execute index operation.', :exception => e.class, :reason => e.message,
108
+ :resolved_source => resolved_source, :backtrace => e.backtrace, :retry => !@retry_disabled)
109
+
110
+ raise e if @retry_disabled
111
+
112
+ sleep(1)
113
+ retry
77
114
  end
78
- doc.delete("@version")
79
- doc
80
115
  end
81
116
  end
82
117
 
83
- def index(documents)
84
- response = @client.index_documents(@source, documents)
85
- report(documents, response)
86
- rescue => e
87
- @logger.error("Failed to execute index operation. Retrying..", :exception => e.class, :reason => e.message)
88
- sleep(1)
89
- retry
118
+ def resolved?(source)
119
+ !(source =~ SOURCE_WITH_SPRINTF_REGEX) && !(source =~ /^\s*$/)
90
120
  end
91
121
 
92
122
  def report(documents, response)
93
123
  documents.each_with_index do |document, i|
94
- errors = response["results"][i]["errors"]
95
- if errors.empty?
96
- @logger.trace? && @logger.trace("Document was indexed with no errors", :document => document)
124
+ errors = response.body&.dig('results', i, 'errors')
125
+ if errors&.empty?
126
+ @logger.trace? && @logger.trace('Document was indexed with no errors', :document => document)
97
127
  else
98
- @logger.warn("Document failed to index. Dropping..", :document => document, :errors => errors.to_a)
128
+ @logger.warn('Document failed to index. Dropping..', :document => document, :errors => errors.to_a)
99
129
  end
100
130
  end
101
131
  end
102
132
 
103
133
  def check_connection!
104
- # This is the preferred way to check compatibility across different versions of Workplace Search service.
105
- @client.index_documents(@source, {:documents => []})
134
+ res = @client.list_content_sources({ 'page[size]': 1 })
135
+ raise "Received HTTP error code #{res.status}" unless res.status == 200
106
136
  end
107
137
  end
@@ -0,0 +1,35 @@
1
+ require 'elastic-enterprise-search'
2
+ require 'logstash/plugin_mixins/enterprise_search/manticore_transport'
3
+
4
+ module LogStash::PluginMixins::EnterpriseSearch
5
+
6
+ module AppSearch
7
+ # App Search client for Enterprise Search.
8
+ # This client extends Elastic::EnterpriseSearch::AppSearch::Client but overrides #transport to use Manticore.
9
+ class Client < Elastic::EnterpriseSearch::AppSearch::Client
10
+ attr_reader :params
11
+
12
+ include LogStash::PluginMixins::EnterpriseSearch::ManticoreTransport
13
+
14
+ def initialize(options, params: {})
15
+ @params = params
16
+ super options
17
+ end
18
+ end
19
+ end
20
+
21
+ module WorkplaceSearch
22
+ # Workplace Search client for Enterprise Search.
23
+ # This client extends Elastic::EnterpriseSearch::WorkplaceSearch::Client but overrides #transport to use Manticore.
24
+ class Client < Elastic::EnterpriseSearch::WorkplaceSearch::Client
25
+ attr_reader :params
26
+
27
+ include LogStash::PluginMixins::EnterpriseSearch::ManticoreTransport
28
+
29
+ def initialize(options, params: {})
30
+ @params = params
31
+ super options
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,84 @@
1
+ module LogStash::PluginMixins::EnterpriseSearch
2
+ # This module is meant to be included in EnterpriseSearch::Clients subclasses and overrides
3
+ # the default #transport method, changing the HTTP client to Manticore.
4
+ # It also provides common Manticore configurations such as :ssl.
5
+ module ManticoreTransport
6
+ def self.included(base)
7
+ if eps_version_7?
8
+ require 'elasticsearch/transport/transport/http/manticore'
9
+ else
10
+ require 'elastic/transport/transport/http/manticore'
11
+ end
12
+
13
+ raise ArgumentError, "`#{base}` must inherit Elastic::EnterpriseSearch::Client" unless base < Elastic::EnterpriseSearch::Client
14
+ raise ArgumentError, "`#{base}` must respond to :params" unless base.instance_methods.include? :params
15
+ end
16
+
17
+ # overrides Elastic::EnterpriseSearch::Client#transport
18
+ def transport
19
+ @options[:transport] || transport_klass.new(
20
+ host: host,
21
+ log: log,
22
+ logger: logger,
23
+ request_timeout: overall_timeout,
24
+ adapter: @options[:adapter],
25
+ transport_options: {
26
+ request: { open_timeout: open_timeout }
27
+ },
28
+ transport_class: manticore_transport_klass,
29
+ ssl: build_ssl_config,
30
+ enable_meta_header: @options[:enable_meta_header] || true,
31
+ trace: !@options[:tracer].nil?,
32
+ tracer: @options[:tracer]
33
+ )
34
+ end
35
+
36
+ def self.eps_version_7?
37
+ Elastic::EnterpriseSearch::VERSION.start_with?('7')
38
+ end
39
+
40
+ private
41
+
42
+ def manticore_transport_klass
43
+ ManticoreTransport.eps_version_7? ? Elasticsearch::Transport::Transport::HTTP::Manticore : Elastic::Transport::Transport::HTTP::Manticore
44
+ end
45
+
46
+ def transport_klass
47
+ case Elasticsearch::Transport::VERSION
48
+ when /7\.1[123]/
49
+ Elasticsearch::Client
50
+ else
51
+ Elasticsearch::Transport::Client
52
+ end
53
+ end
54
+
55
+ def build_transport_options
56
+ { request: { open_timeout: open_timeout } }
57
+ end
58
+
59
+ def build_ssl_config
60
+ ssl_certificate_authorities, ssl_truststore_path = params.values_at('ssl_certificate_authorities', 'ssl_truststore_path')
61
+ if ssl_certificate_authorities && ssl_truststore_path
62
+ raise ::LogStash::ConfigurationError, 'Use either "ssl_certificate_authorities" or "ssl_truststore_path" when configuring the CA certificate'
63
+ end
64
+
65
+ ssl_options = {}
66
+ if ssl_certificate_authorities&.any?
67
+ raise ::LogStash::ConfigurationError, 'Multiple values on "ssl_certificate_authorities" are not supported by this plugin' if ssl_certificate_authorities.size > 1
68
+
69
+ ssl_options[:ca_file] = ssl_certificate_authorities.first
70
+ end
71
+
72
+ if ssl_truststore_path
73
+ ssl_options[:truststore] = ssl_truststore_path
74
+ ssl_options[:truststore_type] = params['ssl_truststore_type'] if params.include?('ssl_truststore_type')
75
+ ssl_options[:truststore_password] = params['ssl_truststore_password'].value if params.include?('ssl_truststore_password')
76
+ end
77
+
78
+ ssl_options[:verify] = params['ssl_verification_mode'] == 'full' ? :strict : :disable
79
+ ssl_options[:cipher_suites] = params['ssl_cipher_suites'] if params.include?('ssl_cipher_suites')
80
+ ssl_options[:protocols] = params['ssl_supported_protocols'] if params['ssl_supported_protocols']&.any?
81
+ ssl_options
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,32 @@
1
+ module LogStash::PluginMixins::EnterpriseSearch
2
+ # This module defines common SSL options that can be reused by the app and workplace search plugins.
3
+ module SSLConfigs
4
+ def self.included(base)
5
+ # SSL Certificate Authority files in PEM encoded format, must also include any chain certificates as necessary
6
+ base.config :ssl_certificate_authorities, :validate => :path, :list => true
7
+
8
+ # The JKS truststore to validate the server's certificate.
9
+ # Use either `:ssl_truststore_path` or `:ssl_certificate_authorities`
10
+ base.config :ssl_truststore_path, :validate => :path
11
+
12
+ # Set the truststore password
13
+ base.config :ssl_truststore_password, :validate => :password
14
+
15
+ # The format of the truststore file. It must be either jks or pkcs12
16
+ base.config :ssl_truststore_type, :validate => %w[pkcs12 jks]
17
+
18
+ # Options to verify the server's certificate.
19
+ # "full": validates that the provided certificate has an issue date that’s within the not_before and not_after dates;
20
+ # chains to a trusted Certificate Authority (CA); has a hostname or IP address that matches the names within the certificate.
21
+ # "none": performs no certificate validation. Disabling this severely compromises security (https://www.cs.utexas.edu/~shmat/shmat_ccs12.pdf)
22
+ base.config :ssl_verification_mode, :validate => %w[full none], :default => 'full'
23
+
24
+ # Supported protocols with versions.
25
+ base.config :ssl_supported_protocols, :validate => %w[TLSv1.1 TLSv1.2 TLSv1.3], :default => [], :list => true
26
+
27
+ # The list of cipher suites to use, listed by priorities.
28
+ # Supported cipher suites vary depending on which version of Java is used.
29
+ base.config :ssl_cipher_suites, :validate => :string, :list => true
30
+ end
31
+ end
32
+ end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'logstash-integration-elastic_enterprise_search'
3
- s.version = '2.2.1'
3
+ s.version = '3.0.0'
4
4
  s.licenses = ['Apache-2.0']
5
5
  s.summary = "Integration with Elastic Enterprise Search - output plugins"
6
6
  s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline "+
@@ -24,11 +24,10 @@ Gem::Specification.new do |s|
24
24
  }
25
25
 
26
26
  # Gem dependencies
27
+ s.add_runtime_dependency "manticore", '~> 0.8'
27
28
  s.add_runtime_dependency "logstash-core-plugin-api", "~> 2.0"
28
29
  s.add_runtime_dependency "logstash-codec-plain"
29
- s.add_runtime_dependency "elastic-app-search", '~>7.8.0'
30
- s.add_runtime_dependency "elastic-enterprise-search", '~>7.16.0'
31
- s.add_runtime_dependency "elastic-workplace-search", '~>0.4.1'
30
+ s.add_runtime_dependency 'elastic-enterprise-search', '>= 7.16', '< 9'
32
31
  s.add_runtime_dependency "logstash-mixin-deprecation_logger_support", '~>1.0'
33
32
  s.add_development_dependency "logstash-devutils"
34
33
  end
@@ -0,0 +1,10 @@
1
+ # Warning: do not use the certificates produced by this tool in production. This is for testing purposes only
2
+
3
+ openssl genrsa 4096 | openssl pkcs8 -topk8 -nocrypt -out root_ca.key
4
+ openssl req -sha256 -x509 -newkey rsa:4096 -nodes -key root_ca.key -sha256 -days 365 -out root_ca.crt -subj "/C=ES/ST=The Internet/L=The Internet/O=Logstash CA/OU=Logstash/CN=enterprise_search"
5
+ openssl req -sha256 -x509 -newkey rsa:4096 -nodes -key root_ca.key -sha256 -days 365 -out root_untrusted_ca.crt -subj "/C=ES/ST=The Darknet/L=The Darknet/O=Logstash CA/OU=Logstash/CN=127.0.0.1"
6
+ openssl pkcs12 -export -in root_ca.crt -inkey root_ca.key -out root_keystore.p12 -password pass:changeme -name ent-search
7
+ keytool -importkeystore -srckeystore root_keystore.p12 -destkeystore root_keystore.jks -srcstoretype PKCS12 -deststoretype jks -srcstorepass changeme -deststorepass changeme -srcalias ent-search -destalias ent-search -srckeypass changeme -destkeypass changeme
8
+
9
+ rm -rf root_keystore.p12
10
+ rm -rf *.csr
@@ -0,0 +1,34 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ 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
33
+ qk9INcfDhzlxwVIqYAoLXTV/ru3mTZI=
34
+ -----END CERTIFICATE-----