logstash-integration-elastic_enterprise_search 2.2.1 → 3.0.1
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 +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +10 -0
- data/lib/logstash/outputs/elastic_app_search.rb +51 -79
- data/lib/logstash/outputs/elastic_workplace_search.rb +75 -37
- data/lib/logstash/plugin_mixins/enterprise_search/client.rb +35 -0
- data/lib/logstash/plugin_mixins/enterprise_search/manticore_transport.rb +84 -0
- data/lib/logstash/plugin_mixins/enterprise_search/ssl_configs.rb +32 -0
- data/logstash-integration-elastic_enterprise_search.gemspec +3 -4
- data/spec/fixtures/certificates/generate.sh +10 -0
- data/spec/fixtures/certificates/root_ca.crt +34 -0
- data/spec/fixtures/certificates/root_ca.key +52 -0
- data/spec/fixtures/certificates/root_keystore.jks +0 -0
- data/spec/fixtures/certificates/root_untrusted_ca.crt +34 -0
- data/spec/fixtures/certificates/root_untrusted_keystore.jks +0 -0
- data/spec/fixtures/certificates/root_untrusted_keystore.p12 +0 -0
- data/spec/integration/outputs/elastic_app_search_spec.rb +133 -105
- data/spec/integration/outputs/elastic_workplace_search_spec.rb +162 -95
- data/spec/unit/outputs/client_spec.rb +26 -0
- data/spec/unit/outputs/elastic_app_search_spec.rb +117 -0
- data/spec/unit/outputs/elastic_workplace_search_spec.rb +117 -0
- data/spec/unit/outputs/manticore_transport_spec.rb +124 -0
- metadata +55 -40
- data/spec/unit/outputs/appsearch_spec.rb +0 -64
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b4473449751c6ce422faa5cdbbcec12e78677a54d40209e397c987d2e2e2d05f
|
4
|
+
data.tar.gz: d1774ea9414e64b243017fa4faac4a53c830b66098208762bb601d9e3a9ac834
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8ed463da5b8975c4765a4688e684e2596a42161128a6bee3f087eff49a6404180051967e6c96f7893581bd7322ff13bdb2d8251f967b8b35496e4b85503e1f83
|
7
|
+
data.tar.gz: e0fcd1f80a3cd350508d9d78922a67e26fc31e01d0433f2fa764033fc2778925b0a8ebebd48e95802718047162630e2d65124395cbd7c7989a7182ce9482e429
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
## 3.0.1
|
2
|
+
- Add deprecation log for App Search and Workplace Search. Both products are removed from Elastic Stack in version 9 [#22](https://github.com/logstash-plugins/logstash-integration-elastic_enterprise_search/pull/22)
|
3
|
+
|
4
|
+
## 3.0.0
|
5
|
+
- Bumped Enterprise Search clients to version `>= 7.16`, `< 9` [#18](https://github.com/logstash-plugins/logstash-integration-elastic_enterprise_search/pull/18)
|
6
|
+
- 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`)
|
7
|
+
- [BREAKING] Swiftype endpoints are no longer supported for both plugins App Search and Workplace Search
|
8
|
+
- The App Search deprecated options `host` and `path` were removed
|
9
|
+
- Fixed the sprintf format support for the Workplace Search `source` configuration
|
10
|
+
|
1
11
|
## 2.2.1
|
2
12
|
- 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
13
|
|
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,15 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
require
|
3
|
-
require "elastic-app-search"
|
4
|
-
require "elastic-enterprise-search"
|
2
|
+
require 'logstash/outputs/base'
|
5
3
|
require 'logstash/plugin_mixins/deprecation_logger_support'
|
4
|
+
require 'logstash/plugin_mixins/enterprise_search/ssl_configs'
|
5
|
+
require 'logstash/plugin_mixins/enterprise_search/client'
|
6
6
|
|
7
7
|
class LogStash::Outputs::ElasticAppSearch < LogStash::Outputs::Base
|
8
|
+
|
9
|
+
include LogStash::PluginMixins::EnterpriseSearch::SSLConfigs
|
8
10
|
include LogStash::PluginMixins::DeprecationLoggerSupport
|
9
11
|
|
10
|
-
config_name
|
12
|
+
config_name 'elastic_app_search'
|
11
13
|
|
12
14
|
# The name of the search engine you created in App Search, an information
|
13
15
|
# repository that includes the indexed document records.
|
@@ -21,16 +23,11 @@ class LogStash::Outputs::ElasticAppSearch < LogStash::Outputs::Base
|
|
21
23
|
# or, if the field is missing from the event and cannot be resolved at all.
|
22
24
|
config :engine, :validate => :string, :required => true
|
23
25
|
|
24
|
-
# The
|
25
|
-
|
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
|
26
|
+
# The value of the API endpoint in the form of a URL.
|
27
|
+
config :url, :validate => :string, :required => true, :default => Elastic::EnterpriseSearch::Utils::DEFAULT_HOST
|
31
28
|
|
32
|
-
# The private API Key with write permissions.
|
33
|
-
#
|
29
|
+
# The private API Key with write permissions.
|
30
|
+
# https://www.elastic.co/guide/en/app-search/current/authentication.html#authentication-api-keys
|
34
31
|
config :api_key, :validate => :password, :required => true
|
35
32
|
|
36
33
|
# Where to move the value from the `@timestamp` field.
|
@@ -46,57 +43,48 @@ class LogStash::Outputs::ElasticAppSearch < LogStash::Outputs::Base
|
|
46
43
|
# like `myapp-%{sequence_id}`. Reusing ids will cause documents to be rewritten.
|
47
44
|
config :document_id, :validate => :string
|
48
45
|
|
49
|
-
|
50
|
-
config :path, :validate => :string, :default => "/api/as/v1/"
|
51
|
-
|
52
|
-
ENGINE_WITH_SPRINTF_REGEX = /^.*%\{.+\}.*$/
|
46
|
+
ENGINE_WITH_SPRINTF_REGEX = /^.*%\{.+\}.*$/.freeze
|
53
47
|
|
54
|
-
public
|
55
48
|
def register
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
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
|
49
|
+
log_message = "The App Search product is deprecated and not supported from version 9 of the Elastic Stack. " +
|
50
|
+
"The Elastic App Search output plugin is deprecated and will only receive security updates and critical bug fixes. " +
|
51
|
+
"Please migrate to the Elastic Connector for continued support. " +
|
52
|
+
"For more details, please visit https://www.elastic.co/guide/en/search-ui/current/tutorials-elasticsearch.html"
|
53
|
+
deprecation_logger.deprecated log_message
|
54
|
+
|
55
|
+
@retry_disabled = false
|
56
|
+
@client = LogStash::PluginMixins::EnterpriseSearch::AppSearch::Client.new(client_options, params: params)
|
57
|
+
check_connection!
|
77
58
|
rescue => e
|
78
59
|
if e.message =~ /401/
|
79
|
-
raise ::LogStash::ConfigurationError
|
60
|
+
raise ::LogStash::ConfigurationError, "Failed to connect to App Search. Please check your credentials. Error: #{e.message}"
|
80
61
|
elsif e.message =~ /404/
|
81
|
-
raise ::LogStash::ConfigurationError
|
62
|
+
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
63
|
else
|
83
|
-
raise ::LogStash::ConfigurationError
|
64
|
+
raise ::LogStash::ConfigurationError, "Failed to connect to App Search. Error: #{e.message}"
|
84
65
|
end
|
85
66
|
end
|
86
67
|
|
87
|
-
public
|
88
68
|
def multi_receive(events)
|
89
69
|
# because App Search has a limit of 100 documents per bulk
|
90
70
|
events.each_slice(100) do |events|
|
91
71
|
batch = format_batch(events)
|
92
72
|
if @logger.trace?
|
93
|
-
@logger.trace(
|
73
|
+
@logger.trace('Sending bulk to App Search', :size => batch.size, :data => batch.inspect)
|
94
74
|
end
|
95
75
|
index(batch)
|
96
76
|
end
|
97
77
|
end
|
98
78
|
|
99
79
|
private
|
80
|
+
|
81
|
+
def client_options
|
82
|
+
options = { :host => @url, :http_auth => @api_key.value }
|
83
|
+
options[:logger] = @logger if @logger.debug?
|
84
|
+
options[:tracer] = @logger if @logger.trace?
|
85
|
+
options
|
86
|
+
end
|
87
|
+
|
100
88
|
def format_batch(events)
|
101
89
|
docs_for_engine = {}
|
102
90
|
events.each do |event|
|
@@ -104,18 +92,18 @@ class LogStash::Outputs::ElasticAppSearch < LogStash::Outputs::Base
|
|
104
92
|
# we need to remove default fields that start with "@"
|
105
93
|
# since Elastic App Search doesn't accept them
|
106
94
|
if @timestamp_destination
|
107
|
-
doc[@timestamp_destination] = doc.delete(
|
95
|
+
doc[@timestamp_destination] = doc.delete('@timestamp')
|
108
96
|
else # delete it
|
109
|
-
doc.delete(
|
97
|
+
doc.delete('@timestamp')
|
110
98
|
end
|
111
99
|
if @document_id
|
112
|
-
doc[
|
100
|
+
doc['id'] = event.sprintf(@document_id)
|
113
101
|
end
|
114
|
-
doc.delete(
|
102
|
+
doc.delete('@version')
|
115
103
|
resolved_engine = event.sprintf(@engine)
|
116
104
|
unless docs_for_engine[resolved_engine]
|
117
105
|
if @logger.debug?
|
118
|
-
@logger.debug(
|
106
|
+
@logger.debug('Creating new engine segment in batch to send', :resolved_engine => resolved_engine)
|
119
107
|
end
|
120
108
|
docs_for_engine[resolved_engine] = []
|
121
109
|
end
|
@@ -124,21 +112,21 @@ class LogStash::Outputs::ElasticAppSearch < LogStash::Outputs::Base
|
|
124
112
|
docs_for_engine
|
125
113
|
end
|
126
114
|
|
127
|
-
def index(
|
128
|
-
|
115
|
+
def index(docs_partitioned_by_engine)
|
116
|
+
docs_partitioned_by_engine.each do |resolved_engine, documents|
|
129
117
|
begin
|
130
118
|
if resolved_engine =~ ENGINE_WITH_SPRINTF_REGEX || resolved_engine =~ /^\s*$/
|
131
119
|
raise "Cannot resolve engine field name #{@engine} from event"
|
132
120
|
end
|
133
|
-
|
134
|
-
|
135
|
-
else
|
136
|
-
response = @client.index_documents(resolved_engine, {:documents => documents})
|
137
|
-
end
|
121
|
+
|
122
|
+
response = @client.index_documents(resolved_engine, { :documents => documents })
|
138
123
|
report(documents, response)
|
139
124
|
rescue => e
|
140
|
-
@logger.error(
|
141
|
-
:resolved_engine => resolved_engine, :backtrace => e.backtrace)
|
125
|
+
@logger.error('Failed to execute index operation.', :exception => e.class, :reason => e.message,
|
126
|
+
:resolved_engine => resolved_engine, :backtrace => e.backtrace, :retry => !@retry_disabled)
|
127
|
+
|
128
|
+
raise e if @retry_disabled
|
129
|
+
|
142
130
|
sleep(1)
|
143
131
|
retry
|
144
132
|
end
|
@@ -147,33 +135,17 @@ class LogStash::Outputs::ElasticAppSearch < LogStash::Outputs::Base
|
|
147
135
|
|
148
136
|
def report(documents, response)
|
149
137
|
documents.each_with_index do |document, i|
|
150
|
-
|
151
|
-
errors = response[i]["errors"]
|
152
|
-
else
|
153
|
-
errors = response.body[i]["errors"]
|
154
|
-
end
|
138
|
+
errors = response.body[i]['errors']
|
155
139
|
if errors.empty?
|
156
|
-
@logger.trace? && @logger.trace(
|
140
|
+
@logger.trace? && @logger.trace('Document was indexed with no errors', :document => document)
|
157
141
|
else
|
158
|
-
@logger.warn(
|
142
|
+
@logger.warn('Document failed to index. Dropping..', :document => document, :errors => errors.to_a)
|
159
143
|
end
|
160
144
|
end
|
161
145
|
end
|
162
146
|
|
163
147
|
def check_connection!
|
164
|
-
|
165
|
-
|
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
|
148
|
+
res = @client.list_engines({ 'page[size]': 1 })
|
149
|
+
raise "Received HTTP error code #{res.status}" unless res.status == 200
|
178
150
|
end
|
179
151
|
end
|
@@ -1,12 +1,18 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
require
|
3
|
-
require
|
2
|
+
require 'logstash/outputs/base'
|
3
|
+
require 'logstash/plugin_mixins/deprecation_logger_support'
|
4
|
+
require 'logstash/plugin_mixins/enterprise_search/client'
|
5
|
+
require 'logstash/plugin_mixins/enterprise_search/ssl_configs'
|
4
6
|
|
5
7
|
class LogStash::Outputs::ElasticWorkplaceSearch < LogStash::Outputs::Base
|
6
|
-
|
8
|
+
|
9
|
+
include LogStash::PluginMixins::EnterpriseSearch::SSLConfigs
|
10
|
+
include LogStash::PluginMixins::DeprecationLoggerSupport
|
11
|
+
|
12
|
+
config_name 'elastic_workplace_search'
|
7
13
|
|
8
14
|
# The value of the API endpoint in the form of a URL.
|
9
|
-
config :url, :validate => :string, :required => true
|
15
|
+
config :url, :validate => :string, :required => true, :default => Elastic::EnterpriseSearch::Utils::DEFAULT_HOST
|
10
16
|
|
11
17
|
# The ID of the source you created in Workplace Search.
|
12
18
|
# The `source` field supports
|
@@ -36,72 +42,104 @@ class LogStash::Outputs::ElasticWorkplaceSearch < LogStash::Outputs::Base
|
|
36
42
|
# like `myapp-%{sequence_id}`. Reusing ids will cause documents to be rewritten.
|
37
43
|
config :document_id, :validate => :string
|
38
44
|
|
39
|
-
|
45
|
+
SOURCE_WITH_SPRINTF_REGEX = /^.*%\{.+\}.*$/.freeze
|
46
|
+
|
40
47
|
def register
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
48
|
+
log_message = "The Workplace Search product is deprecated and not supported from version 9 of the Elastic Stack. " +
|
49
|
+
"The Elastic Workplace Search output plugin is deprecated and will only receive security updates and critical bug fixes. " +
|
50
|
+
"Please migrate to the Elastic Connector for continued support. " +
|
51
|
+
"For more details, please visit https://www.elastic.co/guide/en/search-ui/current/tutorials-elasticsearch.html"
|
52
|
+
deprecation_logger.deprecated log_message
|
53
|
+
|
54
|
+
@retry_disabled = false
|
55
|
+
@client = LogStash::PluginMixins::EnterpriseSearch::WorkplaceSearch::Client.new(client_options, params: params)
|
56
|
+
begin
|
57
|
+
check_connection!
|
58
|
+
rescue => e
|
59
|
+
raise ::LogStash::ConfigurationError, "Failed to connect to Workplace Search. Error: #{e.message}"
|
60
|
+
end
|
50
61
|
end
|
51
62
|
|
52
|
-
public
|
53
63
|
def multi_receive(events)
|
54
64
|
# because Workplace Search has a limit of 100 documents per bulk
|
55
65
|
events.each_slice(100) do |events|
|
56
66
|
batch = format_batch(events)
|
57
|
-
if @logger.trace?
|
58
|
-
@logger.trace("Sending bulk to Workplace Search", :size => batch.size, :data => batch.inspect)
|
59
|
-
end
|
67
|
+
@logger.trace('Sending bulk to Workplace Search', :size => batch.size, :data => batch.inspect) if @logger.trace?
|
60
68
|
index(batch)
|
61
69
|
end
|
62
70
|
end
|
63
71
|
|
64
72
|
private
|
73
|
+
|
74
|
+
def client_options
|
75
|
+
options = { :host => @url, :http_auth => @access_token.value }
|
76
|
+
options[:logger] = @logger if @logger.debug?
|
77
|
+
options[:tracer] = @logger if @logger.trace?
|
78
|
+
options
|
79
|
+
end
|
80
|
+
|
65
81
|
def format_batch(events)
|
82
|
+
docs_per_source = {}
|
66
83
|
events.map do |event|
|
67
84
|
doc = event.to_hash
|
68
85
|
# we need to remove default fields that start with "@"
|
69
86
|
# since Elastic Workplace Search doesn't accept them
|
70
87
|
if @timestamp_destination
|
71
|
-
doc[@timestamp_destination] = doc.delete(
|
88
|
+
doc[@timestamp_destination] = doc.delete('@timestamp')
|
72
89
|
else # delete it
|
73
|
-
doc.delete(
|
90
|
+
doc.delete('@timestamp')
|
74
91
|
end
|
75
|
-
|
76
|
-
|
92
|
+
|
93
|
+
doc['id'] = event.sprintf(@document_id) if @document_id
|
94
|
+
doc.delete('@version')
|
95
|
+
|
96
|
+
resolved_source = event.sprintf(@source)
|
97
|
+
unless docs_per_source[resolved_source]
|
98
|
+
@logger.debug('Creating new source segment in batch to send', resolved_source: resolved_source) if @logger.debug?
|
99
|
+
docs_per_source[resolved_source] = []
|
100
|
+
end
|
101
|
+
docs_per_source[resolved_source] << doc
|
102
|
+
end
|
103
|
+
|
104
|
+
docs_per_source
|
105
|
+
end
|
106
|
+
|
107
|
+
def index(docs_partitioned_by_source)
|
108
|
+
docs_partitioned_by_source.each do |resolved_source, documents|
|
109
|
+
begin
|
110
|
+
raise "Cannot resolve source field name #{@source} from event" unless resolved?(resolved_source)
|
111
|
+
|
112
|
+
response = @client.index_documents(resolved_source, { :documents => documents })
|
113
|
+
report(documents, response)
|
114
|
+
rescue => e
|
115
|
+
@logger.error('Failed to execute index operation.', :exception => e.class, :reason => e.message,
|
116
|
+
:resolved_source => resolved_source, :backtrace => e.backtrace, :retry => !@retry_disabled)
|
117
|
+
|
118
|
+
raise e if @retry_disabled
|
119
|
+
|
120
|
+
sleep(1)
|
121
|
+
retry
|
77
122
|
end
|
78
|
-
doc.delete("@version")
|
79
|
-
doc
|
80
123
|
end
|
81
124
|
end
|
82
125
|
|
83
|
-
def
|
84
|
-
|
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
|
126
|
+
def resolved?(source)
|
127
|
+
!(source =~ SOURCE_WITH_SPRINTF_REGEX) && !(source =~ /^\s*$/)
|
90
128
|
end
|
91
129
|
|
92
130
|
def report(documents, response)
|
93
131
|
documents.each_with_index do |document, i|
|
94
|
-
errors = response
|
95
|
-
if errors
|
96
|
-
@logger.trace? && @logger.trace(
|
132
|
+
errors = response.body&.dig('results', i, 'errors')
|
133
|
+
if errors&.empty?
|
134
|
+
@logger.trace? && @logger.trace('Document was indexed with no errors', :document => document)
|
97
135
|
else
|
98
|
-
@logger.warn(
|
136
|
+
@logger.warn('Document failed to index. Dropping..', :document => document, :errors => errors.to_a)
|
99
137
|
end
|
100
138
|
end
|
101
139
|
end
|
102
140
|
|
103
141
|
def check_connection!
|
104
|
-
|
105
|
-
|
142
|
+
res = @client.list_content_sources({ 'page[size]': 1 })
|
143
|
+
raise "Received HTTP error code #{res.status}" unless res.status == 200
|
106
144
|
end
|
107
145
|
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 = '
|
3
|
+
s.version = '3.0.1'
|
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
|
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-----
|