logstash-filter-elasticsearch 3.19.0 → 3.19.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 28c0544d8e61fe99078cabecc2ce4cf898aefc35775e80a71a5bb34221d534d5
4
- data.tar.gz: 6f42fd12be09e9aa4b619c95ffff8cc9dba427f5f71f915d2e7c30a583f83fec
3
+ metadata.gz: 9a0e21ee3a328a2c9f6ad6a7cba6035f09fdc3a760787441efc9746b0db53a00
4
+ data.tar.gz: 66facd522d9a822e62529bd6fc99207db46070232f13558fef87565002c24a9c
5
5
  SHA512:
6
- metadata.gz: 3aaa9a9b8b31e1782e927fe4bccb26fd28063206dfeaf00c574657e0d91e3c7c7544565c657a65d37a5e164c0e2477b8fdab3f4dfb2c7feb79971962e94cbb87
7
- data.tar.gz: 339a881e589fe44d5657e4a4417f9e72f38921a08ff99b2cbc1534785fcddb00ae484960311a70d653f3ca058f38ceed0a290d789bb0d728d7db1ff8de8a6d46
6
+ metadata.gz: baebe8460aaaa98b3c84da38a52e344a840beed5cfe6ae7359a07b4a86e2403d01ed693755b5e7750c6f8c56586be0ad51aac306e7f5a112c03398ffe4138015
7
+ data.tar.gz: 97afa7a8436f4a27472c60670230ed6746f84c12e7daeff3ff08723cddcf57402e1918ef4dca1d8fe0b51aa9fb2318d0f529f89fd148b29bf4d9aec146502ec6
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ ## 3.19.1
2
+ - Support base64-encoded and Elastic Cloud (`essu_`-prefixed) API keys in the `api_key` option; reject unrecognized formats at startup. [#229](https://github.com/logstash-plugins/logstash-filter-elasticsearch/pull/229)
3
+
1
4
  ## 3.19.0
2
5
  - ES|QL support [#199](https://github.com/logstash-plugins/logstash-filter-elasticsearch/pull/199)
3
6
 
data/docs/index.asciidoc CHANGED
@@ -305,8 +305,12 @@ Example:
305
305
  Authenticate using Elasticsearch API key. Note that this option also requires
306
306
  enabling the <<plugins-{type}s-{plugin}-ssl_enabled>> option.
307
307
 
308
- Format is `id:api_key` where `id` and `api_key` are as returned by the
309
- Elasticsearch {ref}/security-api-create-api-key.html[Create API key API].
308
+ The format is `id:api_key`, where `id` and `api_key` are as returned by the
309
+ Elasticsearch
310
+ {ref}/security-api-create-api-key.html[Create
311
+ API key API]. The base64-encoded form of that pair is also accepted, as is an
312
+ https://www.elastic.co/docs/deploy-manage/api-keys/elastic-cloud-api-keys[Elastic Cloud API key]
313
+ (prefixed with `essu_`), which is used as-is.
310
314
 
311
315
  [id="plugins-{type}s-{plugin}-ca_trusted_fingerprint"]
312
316
  ===== `ca_trusted_fingerprint`
@@ -101,12 +101,40 @@ module LogStash
101
101
  end
102
102
 
103
103
  def setup_api_key(api_key)
104
- return {} unless (api_key && api_key.value)
104
+ return {} unless (api_key&.value)
105
105
 
106
- token = ::Base64.strict_encode64(api_key.value)
106
+ token = resolve_api_key(api_key.value)
107
107
  { 'Authorization' => "ApiKey #{token}" }
108
108
  end
109
109
 
110
+ # Resolves the `api_key` value into the credential used in the
111
+ # `Authorization: ApiKey` header. An already base64-encoded key and an Elastic
112
+ # Cloud API key are used as-is; a raw `id:api_key` pair is base64-encoded. An
113
+ # unrecognized value is rejected so a malformed key surfaces at startup rather
114
+ # than as a later authentication failure.
115
+ def resolve_api_key(key_value)
116
+ if base64?(key_value) || cloud_api_key?(key_value)
117
+ key_value
118
+ elsif key_value.match?(/\A[^:]+:[^:]+\z/)
119
+ Base64.strict_encode64(key_value)
120
+ else
121
+ raise LogStash::ConfigurationError, "Invalid api_key format. Expected a base64-encoded key, an 'id:api_key' pair, or a Cloud API key (essu_ prefix)."
122
+ end
123
+ end
124
+
125
+ # Elastic Cloud API keys (such as the unified Serverless keys) are opaque
126
+ # tokens prefixed with `essu_` that Elasticsearch accepts verbatim in the
127
+ # `Authorization: ApiKey` header, with no base64 encoding.
128
+ def cloud_api_key?(string)
129
+ string.match?(/\Aessu_.+/)
130
+ end
131
+
132
+ def base64?(string)
133
+ string == Base64.strict_encode64(Base64.strict_decode64(string))
134
+ rescue ArgumentError
135
+ false
136
+ end
137
+
110
138
  def get_transport_client_class
111
139
  # LS-core includes `elasticsearch` gem. The gem is composed of two separate gems: `elasticsearch-api` and `elasticsearch-transport`
112
140
  # And now `elasticsearch-transport` is old, instead we have `elastic-transport`.
@@ -73,7 +73,8 @@ class LogStash::Filters::Elasticsearch < LogStash::Filters::Base
73
73
  config :cloud_auth, :validate => :password
74
74
 
75
75
  # Authenticate using Elasticsearch API key.
76
- # format is id:api_key (as returned by https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html[Create API key])
76
+ # Format is either the `id:api_key` pair (as returned by https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html[Create API key]),
77
+ # its base64-encoded form, or an https://www.elastic.co/docs/deploy-manage/api-keys/elastic-cloud-api-keys[Elastic Cloud API key] (prefixed with `essu_`) can be used.
77
78
  config :api_key, :validate => :password
78
79
 
79
80
  # Set the address of a forward HTTP proxy.
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
 
3
3
  s.name = 'logstash-filter-elasticsearch'
4
- s.version = '3.19.0'
4
+ s.version = ::File.read('version').split("\n").first
5
5
  s.licenses = ['Apache License (2.0)']
6
6
  s.summary = "Copies fields from previous log events in Elasticsearch to current events "
7
7
  s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"
@@ -11,7 +11,7 @@ Gem::Specification.new do |s|
11
11
  s.require_paths = ["lib"]
12
12
 
13
13
  # Files
14
- s.files = Dir["lib/**/*","spec/**/*","*.gemspec","*.md","CONTRIBUTORS","Gemfile","LICENSE","NOTICE.TXT", "vendor/jar-dependencies/**/*.jar", "vendor/jar-dependencies/**/*.rb", "VERSION", "docs/**/*"]
14
+ s.files = Dir["lib/**/*","spec/**/*","*.gemspec","*.md","CONTRIBUTORS","Gemfile","LICENSE","NOTICE.TXT", "vendor/jar-dependencies/**/*.jar", "vendor/jar-dependencies/**/*.rb", "VERSION", "version", "docs/**/*"]
15
15
 
16
16
  # Tests
17
17
  s.test_files = s.files.grep(%r{^(test|spec|features)/})
@@ -4,6 +4,7 @@ require "logstash/plugin"
4
4
  require "logstash/filters/elasticsearch"
5
5
  require "logstash/json"
6
6
  require "cabin"
7
+ require "manticore"
7
8
  require "webrick"
8
9
  require "uri"
9
10
 
@@ -324,14 +325,50 @@ describe LogStash::Filters::Elasticsearch do
324
325
  end
325
326
 
326
327
  context "with ssl" do
327
- let(:config) { super().merge({ 'api_key' => LogStash::Util::Password.new('foo:bar'), "ssl_enabled" => true }) }
328
+ let(:api_key_value) { nil }
329
+ let(:config) { super().merge("ssl_enabled" => true, 'api_key' => LogStash::Util::Password.new(api_key_value)) }
330
+ let(:encoded_api_key) { Base64.strict_encode64('foo:bar') }
328
331
 
329
- it "should set authorization" do
330
- plugin.register
331
- client = plugin.send(:get_client).client
332
- auth_header = extract_transport(client).options[:transport_options][:headers]['Authorization']
332
+ shared_examples "a plugin that sets the ApiKey authorization header" do
333
+ it "correctly sets the Authorization header" do
334
+ plugin.register
335
+ client = plugin.send(:get_client).client
336
+ auth_header = extract_transport(client).options[:transport_options][:headers]['Authorization']
337
+
338
+ expect(auth_header).to eql("ApiKey #{encoded_api_key}")
339
+ end
340
+ end
341
+
342
+ context "with a non-encoded API key" do
343
+ let(:api_key_value) { "foo:bar" }
344
+ it_behaves_like "a plugin that sets the ApiKey authorization header"
345
+ end
346
+
347
+ context "with an encoded API key" do
348
+ let(:api_key_value) { encoded_api_key }
349
+ it_behaves_like "a plugin that sets the ApiKey authorization header"
350
+ end
351
+
352
+ context "with an Elastic Cloud API key (essu_ prefix)" do
353
+ # The suffix is intentionally not canonical base64: a Cloud key is opaque
354
+ # and must be forwarded verbatim regardless of its payload encoding.
355
+ let(:api_key_value) { "essu_VFZGblZreFhTekJ4ZDB4M2NHUnZRMEU2YzNWd1pYSnpaV055WlhRPQ==AAAAAAAA" }
356
+
357
+ it "sets the Authorization header verbatim without re-encoding" do
358
+ plugin.register
359
+ client = plugin.send(:get_client).client
360
+ auth_header = extract_transport(client).options[:transport_options][:headers]['Authorization']
361
+
362
+ expect(auth_header).to eql("ApiKey #{api_key_value}")
363
+ end
364
+ end
333
365
 
334
- expect( auth_header ).to eql "ApiKey #{Base64.strict_encode64('foo:bar')}"
366
+ context "with an unrecognized api_key format" do
367
+ let(:api_key_value) { "not-a-valid-key" }
368
+
369
+ it "fails registration with a configuration error" do
370
+ expect { plugin.register }.to raise_error(LogStash::ConfigurationError, /Invalid api_key format/)
371
+ end
335
372
  end
336
373
 
337
374
  context 'user also set' do
data/version ADDED
@@ -0,0 +1 @@
1
+ 3.19.1
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-filter-elasticsearch
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.19.0
4
+ version: 3.19.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elastic
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2025-07-21 00:00:00.000000000 Z
10
+ date: 2026-07-17 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
13
+ name: logstash-core-plugin-api
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
16
  - - ">="
@@ -19,7 +19,6 @@ dependencies:
19
19
  - - "<="
20
20
  - !ruby/object:Gem::Version
21
21
  version: '2.99'
22
- name: logstash-core-plugin-api
23
22
  type: :runtime
24
23
  prerelease: false
25
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -31,6 +30,7 @@ dependencies:
31
30
  - !ruby/object:Gem::Version
32
31
  version: '2.99'
33
32
  - !ruby/object:Gem::Dependency
33
+ name: elasticsearch
34
34
  requirement: !ruby/object:Gem::Requirement
35
35
  requirements:
36
36
  - - ">="
@@ -39,7 +39,6 @@ dependencies:
39
39
  - - "<"
40
40
  - !ruby/object:Gem::Version
41
41
  version: '9'
42
- name: elasticsearch
43
42
  type: :runtime
44
43
  prerelease: false
45
44
  version_requirements: !ruby/object:Gem::Requirement
@@ -51,12 +50,12 @@ dependencies:
51
50
  - !ruby/object:Gem::Version
52
51
  version: '9'
53
52
  - !ruby/object:Gem::Dependency
53
+ name: manticore
54
54
  requirement: !ruby/object:Gem::Requirement
55
55
  requirements:
56
56
  - - ">="
57
57
  - !ruby/object:Gem::Version
58
58
  version: 0.7.1
59
- name: manticore
60
59
  type: :runtime
61
60
  prerelease: false
62
61
  version_requirements: !ruby/object:Gem::Requirement
@@ -65,12 +64,12 @@ dependencies:
65
64
  - !ruby/object:Gem::Version
66
65
  version: 0.7.1
67
66
  - !ruby/object:Gem::Dependency
67
+ name: logstash-mixin-ecs_compatibility_support
68
68
  requirement: !ruby/object:Gem::Requirement
69
69
  requirements:
70
70
  - - "~>"
71
71
  - !ruby/object:Gem::Version
72
72
  version: '1.3'
73
- name: logstash-mixin-ecs_compatibility_support
74
73
  type: :runtime
75
74
  prerelease: false
76
75
  version_requirements: !ruby/object:Gem::Requirement
@@ -79,12 +78,12 @@ dependencies:
79
78
  - !ruby/object:Gem::Version
80
79
  version: '1.3'
81
80
  - !ruby/object:Gem::Dependency
81
+ name: logstash-mixin-ca_trusted_fingerprint_support
82
82
  requirement: !ruby/object:Gem::Requirement
83
83
  requirements:
84
84
  - - "~>"
85
85
  - !ruby/object:Gem::Version
86
86
  version: '1.0'
87
- name: logstash-mixin-ca_trusted_fingerprint_support
88
87
  type: :runtime
89
88
  prerelease: false
90
89
  version_requirements: !ruby/object:Gem::Requirement
@@ -93,12 +92,12 @@ dependencies:
93
92
  - !ruby/object:Gem::Version
94
93
  version: '1.0'
95
94
  - !ruby/object:Gem::Dependency
95
+ name: logstash-mixin-normalize_config_support
96
96
  requirement: !ruby/object:Gem::Requirement
97
97
  requirements:
98
98
  - - "~>"
99
99
  - !ruby/object:Gem::Version
100
100
  version: '1.0'
101
- name: logstash-mixin-normalize_config_support
102
101
  type: :runtime
103
102
  prerelease: false
104
103
  version_requirements: !ruby/object:Gem::Requirement
@@ -107,12 +106,12 @@ dependencies:
107
106
  - !ruby/object:Gem::Version
108
107
  version: '1.0'
109
108
  - !ruby/object:Gem::Dependency
109
+ name: logstash-mixin-validator_support
110
110
  requirement: !ruby/object:Gem::Requirement
111
111
  requirements:
112
112
  - - "~>"
113
113
  - !ruby/object:Gem::Version
114
114
  version: '1.0'
115
- name: logstash-mixin-validator_support
116
115
  type: :runtime
117
116
  prerelease: false
118
117
  version_requirements: !ruby/object:Gem::Requirement
@@ -121,12 +120,12 @@ dependencies:
121
120
  - !ruby/object:Gem::Version
122
121
  version: '1.0'
123
122
  - !ruby/object:Gem::Dependency
123
+ name: cabin
124
124
  requirement: !ruby/object:Gem::Requirement
125
125
  requirements:
126
126
  - - "~>"
127
127
  - !ruby/object:Gem::Version
128
128
  version: '0.6'
129
- name: cabin
130
129
  type: :development
131
130
  prerelease: false
132
131
  version_requirements: !ruby/object:Gem::Requirement
@@ -135,12 +134,12 @@ dependencies:
135
134
  - !ruby/object:Gem::Version
136
135
  version: '0.6'
137
136
  - !ruby/object:Gem::Dependency
137
+ name: webrick
138
138
  requirement: !ruby/object:Gem::Requirement
139
139
  requirements:
140
140
  - - ">="
141
141
  - !ruby/object:Gem::Version
142
142
  version: '0'
143
- name: webrick
144
143
  type: :development
145
144
  prerelease: false
146
145
  version_requirements: !ruby/object:Gem::Requirement
@@ -149,12 +148,12 @@ dependencies:
149
148
  - !ruby/object:Gem::Version
150
149
  version: '0'
151
150
  - !ruby/object:Gem::Dependency
151
+ name: logstash-devutils
152
152
  requirement: !ruby/object:Gem::Requirement
153
153
  requirements:
154
154
  - - ">="
155
155
  - !ruby/object:Gem::Version
156
156
  version: '0'
157
- name: logstash-devutils
158
157
  type: :development
159
158
  prerelease: false
160
159
  version_requirements: !ruby/object:Gem::Requirement
@@ -213,13 +212,13 @@ files:
213
212
  - spec/filters/fixtures/test_certs/ls.key
214
213
  - spec/filters/integration/elasticsearch_esql_spec.rb
215
214
  - spec/filters/integration/elasticsearch_spec.rb
215
+ - version
216
216
  homepage: https://elastic.co/logstash
217
217
  licenses:
218
218
  - Apache License (2.0)
219
219
  metadata:
220
220
  logstash_plugin: 'true'
221
221
  logstash_group: filter
222
- post_install_message:
223
222
  rdoc_options: []
224
223
  require_paths:
225
224
  - lib
@@ -234,8 +233,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
234
233
  - !ruby/object:Gem::Version
235
234
  version: '0'
236
235
  requirements: []
237
- rubygems_version: 3.3.26
238
- signing_key:
236
+ rubygems_version: 3.6.3
239
237
  specification_version: 4
240
238
  summary: Copies fields from previous log events in Elasticsearch to current events
241
239
  test_files: