Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Standardize SSL settings #6

Merged
merged 2 commits into from
Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.1.3
- Deprecates the `ssl` option in favor of `ssl_enabled` [#6](https://github.com/logstash-plugins/logstash-input-elastic_serverless_forwarder/pull/6)
- Bumps `logstash-input-http` gem version to `>= 3.7.2` (SSL-normalized)

## 0.1.2
- [DOC] Adds "Technical Preview" call-out to documentation [#4](https://github.com/logstash-plugins/logstash-input-elastic_serverless_forwarder/pull/4)

Expand Down
17 changes: 15 additions & 2 deletions docs/index.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ input {
input {
elastic_serverless_forwarder {
port => 8080
ssl => false
ssl_enabled => false
}
}
----
Expand Down Expand Up @@ -144,11 +144,12 @@ This plugin supports the following configuration options plus the <<plugins-{typ
| <<plugins-{type}s-{plugin}-auth_basic_password>> |<<password,password>>|No
| <<plugins-{type}s-{plugin}-host>> |<<string,string>>|No
| <<plugins-{type}s-{plugin}-port>> |<<number,number>>|No
| <<plugins-{type}s-{plugin}-ssl>> |<<boolean,boolean>>|No
| <<plugins-{type}s-{plugin}-ssl>> |<<boolean,boolean>>|__Deprecated__
| <<plugins-{type}s-{plugin}-ssl_certificate>> |a valid filesystem path|No
| <<plugins-{type}s-{plugin}-ssl_certificate_authorities>> |<<array,array>>|No
| <<plugins-{type}s-{plugin}-ssl_client_authentication>> |<<string,string>>, one of `["none", "optional", "required"]`|No
| <<plugins-{type}s-{plugin}-ssl_cipher_suites>> |<<array,array>>|No
| <<plugins-{type}s-{plugin}-ssl_enabled>> |<<boolean,boolean>>|No
| <<plugins-{type}s-{plugin}-ssl_handshake_timeout>> |<<number,number>>|No
| <<plugins-{type}s-{plugin}-ssl_key>> |a valid filesystem path|No
| <<plugins-{type}s-{plugin}-ssl_key_passphrase>> |<<password,password>>|No
Expand Down Expand Up @@ -197,6 +198,7 @@ The TCP port to bind to

[id="plugins-{type}s-{plugin}-ssl"]
===== `ssl`
deprecated[0.1.3, Replaced by <<plugins-{type}s-{plugin}-ssl_enabled>>]

* Value type is <<boolean,boolean>>
* Default value is `true`
Expand Down Expand Up @@ -255,6 +257,17 @@ By default the server doesn't do any client authentication.
This means that connections from clients are _private_ when SSL is enabled, but that this input will allow SSL connections from _any_ client.
If you wish to configure this plugin to reject connections from untrusted hosts, you will need to configure this plugin to authenticate clients, and may also need to configure it with a list of `ssl_certificate_authorities`.


[id="plugins-{type}s-{plugin}-ssl_enabled"]
===== `ssl_enabled`

* Value type is <<boolean,boolean>>
* Default value is `true`

Events are by default sent over SSL, which requires configuring this plugin to present an identity certificate using <<plugins-{type}s-{plugin}-ssl_certificate>> and key using <<plugins-{type}s-{plugin}-ssl_key>>.
edmocosta marked this conversation as resolved.
Show resolved Hide resolved

You can disable SSL with `+ssl_enabled => false+`.

[id="plugins-{type}s-{plugin}-ssl_handshake_timeout"]
===== `ssl_handshake_timeout`

Expand Down
39 changes: 20 additions & 19 deletions lib/logstash/inputs/elastic_serverless_forwarder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
require "logstash/namespace"

require "logstash/plugin_mixins/plugin_factory_support"
require "logstash/plugin_mixins/normalize_config_support"

require 'logstash/inputs/http'
require 'logstash/codecs/json_lines'

class LogStash::Inputs::ElasticServerlessForwarder < LogStash::Inputs::Base
include LogStash::PluginMixins::PluginFactorySupport
include LogStash::PluginMixins::NormalizeConfigSupport

config_name "elastic_serverless_forwarder"

Expand All @@ -21,7 +23,8 @@ class LogStash::Inputs::ElasticServerlessForwarder < LogStash::Inputs::Base
config :auth_basic_password, :validate => :password

# ssl-config
config :ssl, :validate => :boolean, :default => true
config :ssl, :validate => :boolean, :default => true, :deprecated => "Use 'ssl_enabled' instead."
config :ssl_enabled, :validate => :boolean, :default => true

# ssl-identity
config :ssl_certificate, :validate => :path
Expand All @@ -38,20 +41,11 @@ class LogStash::Inputs::ElasticServerlessForwarder < LogStash::Inputs::Base
config :ssl_supported_protocols, :validate => :string, :list => true
config :ssl_handshake_timeout, :validate => :number, :default => 10_000

# we present the ES-like ssl_certificate_authorities, but our
# internal http input plugin uses ssl_verify_mode to describe
# the same behaviour.
SSL_CLIENT_AUTHENTICATION_TO_VERIFY_MODE_MAP = {
'none' => 'none',
'optional' => 'peer',
'required' => 'force_peer',
}.each_value(&:freeze).freeze # deep freeze
private_constant :SSL_CLIENT_AUTHENTICATION_TO_VERIFY_MODE_MAP


def initialize(*a)
super

normalize_ssl_configs!

if original_params.include?('codec')
fail LogStash::ConfigurationError, 'The `elastic_serverless_forwarder` input does not have an externally-configurable `codec`'
end
Expand Down Expand Up @@ -109,14 +103,14 @@ def inner_http_input_options
if @auth_basic_username
http_options['user'] = @auth_basic_username
http_options['password'] = @auth_basic_password || fail(LogStash::ConfigurationError, '`auth_basic_password` is REQUIRED when `auth_basic_username` is provided')
logger.warn("HTTP Basic Auth over non-secured connection") if @ssl == false
logger.warn("HTTP Basic Auth over non-secured connection") if @ssl_enabled == false
end

if @ssl == false
if @ssl_enabled == false
ignored_ssl_settings = @original_params.keys.grep('ssl_')
logger.warn("Explicit SSL-related settings are ignored because `ssl => false`: #{ignored_ssl_settings.keys}") if ignored_ssl_settings.any?
logger.warn("Explicit SSL-related settings are ignored because `ssl_enabled => false`: #{ignored_ssl_settings.keys}") if ignored_ssl_settings.any?
else
http_options['ssl'] = true
http_options['ssl_enabled'] = true

http_options['ssl_cipher_suites'] = @ssl_cipher_suites if @original_params.include?('ssl_cipher_suites')
http_options['ssl_supported_protocols'] = @ssl_supported_protocols if @original_params.include?('ssl_supported_protocols')
Expand All @@ -131,9 +125,10 @@ def inner_http_input_options
end

def ssl_identity_options
ssl_enabled_config = @original_params.include?('ssl') ? 'ssl' : 'ssl_enabled'
identity_options = {
'ssl_certificate' => @ssl_certificate || fail(LogStash::ConfigurationError, '`ssl_certificate` is REQUIRED when `ssl => true`'),
'ssl_key' => @ssl_key || fail(LogStash::ConfigurationError, '`ssl_key` is REQUIRED when `ssl => true`')
'ssl_certificate' => @ssl_certificate || fail(LogStash::ConfigurationError, "`ssl_certificate` is REQUIRED when `#{ssl_enabled_config} => true`"),
'ssl_key' => @ssl_key || fail(LogStash::ConfigurationError, "`ssl_key` is REQUIRED when `#{ssl_enabled_config} => true`")
}
identity_options['ssl_key_passphrase'] = @ssl_key_passphrase if @original_params.include?('ssl_key_passphrase')

Expand All @@ -142,7 +137,7 @@ def ssl_identity_options

def ssl_trust_options
trust_options = {
'ssl_verify_mode' => SSL_CLIENT_AUTHENTICATION_TO_VERIFY_MODE_MAP.fetch(@ssl_client_authentication)
'ssl_client_authentication' => @ssl_client_authentication
}
if @ssl_client_authentication == 'none'
logger.warn("Explicit `ssl_certificate_authorities` is ignored because `ssl_client_authentication => #{@ssl_client_authentication}`")
Expand All @@ -160,6 +155,12 @@ def inner_json_lines_codec_options
}
end

def normalize_ssl_configs!
@ssl_enabled = normalize_config(:ssl_enabled) do |normalizer|
normalizer.with_deprecated_alias(:ssl)
end
end

class QueueWrapper
def initialize(wrapped_queue)
@wrapped_queue = wrapped_queue
Expand Down
5 changes: 3 additions & 2 deletions logstash-input-elastic_serverless_forwarder.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Gem::Specification.new do |s|
s.name = 'logstash-input-elastic_serverless_forwarder'
s.version = '0.1.2'
s.version = '0.1.3'
s.licenses = ['Apache License (2.0)']
s.summary = "Receives events from Elastic Serverless Forwarder over HTTP or HTTPS"
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"
Expand All @@ -23,8 +23,9 @@ Gem::Specification.new do |s|
s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
s.add_runtime_dependency 'logstash-mixin-ecs_compatibility_support', '~>1.2'
s.add_runtime_dependency 'logstash-mixin-plugin_factory_support'
s.add_runtime_dependency 'logstash-input-http'
s.add_runtime_dependency 'logstash-input-http', '>= 3.7.2'
s.add_runtime_dependency 'logstash-codec-json_lines'
s.add_runtime_dependency 'logstash-mixin-normalize_config_support', '~>1.0'

s.add_development_dependency 'logstash-devutils'

Expand Down
25 changes: 22 additions & 3 deletions spec/inputs/elastic_serverless_forwarder_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
let!(:queue) { Queue.new }

context 'baseline' do
let(:config) { super().merge('ssl' => false) }
let(:config) { super().merge('ssl_enabled' => false) }
let(:scheme) { 'http' }

it_behaves_like "an interruptible input plugin" do
Expand All @@ -45,7 +45,7 @@
end

context 'no user-defined codec' do
let(:config) { super().merge('ssl' => false) } # minimal config
let(:config) { super().merge('ssl_enabled' => false) } # minimal config

##
# @codec ivar is required PENDING https://github.com/elastic/logstash/issues/14828
Expand Down Expand Up @@ -185,7 +185,7 @@ def pop_with_timeout(queue, timeout)
end

describe 'unsecured HTTP' do
let(:config) { super().merge('ssl' => false) }
let(:config) { super().merge('ssl_enabled' => false) }
let(:scheme) { 'http' }

include_examples 'successful request handling'
Expand Down Expand Up @@ -321,4 +321,23 @@ def pop_with_timeout(queue, timeout)
end
end
end

describe 'deprecated SSL options' do
let(:config) do
super().merge({
'ssl_certificate' => generated_certs_directory.join('server_from_root.crt').to_path,
'ssl_key' => generated_certs_directory.join('server_from_root.key.pkcs8').to_path,
})
end

[true, false].each do |enabled|
context "when `ssl => #{enabled}`" do
let(:config) { super().merge('ssl' => enabled) }

it "sets @ssl_enabled to `#{enabled}`" do
expect(esf_input.instance_variable_get(:@ssl_enabled)).to be enabled
end
end
end
end
end