Skip to content

Commit

Permalink
Standardised SSL settings (#42)
Browse files Browse the repository at this point in the history
This commit adds standardized SSL settings and deprecates their non-standard counterparts. Deprecated settings will continue to work, and will provide pipeline maintainers with guidance toward using their standardized counterparts:

- Adds new `ssl_truststore_path`, `ssl_truststore_password`, and `ssl_truststore_type` settings for configuring SSL-trust using a PKCS-12 or JKS trust store, deprecating their `truststore`, `truststore_password`, and `truststore_type` counterparts.
- Adds new `ssl_certificate_authorities` setting for configuring SSL-trust using a PEM-formated list certificate authorities, deprecating its `cacert` counterpart.
- Adds new `ssl_keystore_path`, `ssl_keystore_password`, and `ssl_keystore_type` settings for configuring SSL-identity using a PKCS-12 or JKS key store, deprecating their `keystore`, `keystore_password`, and `keystore_type` counterparts.
- Adds new `ssl_certificate` and `ssl_key` settings for configuring SSL-identity using a PEM-formatted certificate/key pair, deprecating their `client_cert` and `client_key` counterparts. 

Other changes:
- Added a way for plugin maintainers to include this mixin _without_ supporting the now-deprecated SSL options.
- Added the `ssl_cipher_suites` option

---------
Co-authored-by: Ry Biesemeyer <[email protected]>
  • Loading branch information
edmocosta authored Aug 30, 2023
1 parent 7de5618 commit 0e65a76
Show file tree
Hide file tree
Showing 8 changed files with 716 additions and 350 deletions.
20 changes: 2 additions & 18 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,3 @@
---
sudo: false
language: ruby
cache: bundler

script: bundle exec rspec spec
jdk: openjdk8
matrix:
include:
- rvm: jruby-9.2.20.1
env: LOGSTASH_BRANCH=8.0
- rvm: jruby-9.2.20.1
env: LOGSTASH_BRANCH=7.16
- rvm: jruby-9.1.13.0
env: LOGSTASH_BRANCH=6.7
- rvm: jruby-9.2.7.0
env: LOGSTASH_BRANCH=6.8
fast_finish: true
before_install: gem install bundler -v '< 2'
import:
- logstash-plugins/.ci:travis/[email protected]
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
## 7.3.0
- Adds standardized SSL settings and deprecates their non-standard counterparts. Deprecated settings will continue to work, and will provide pipeline maintainers with guidance toward using their standardized counterparts [#42](https://github.com/logstash-plugins/logstash-mixin-http_client/pull/42)
- Adds new `ssl_truststore_path`, `ssl_truststore_password`, and `ssl_truststore_type` settings for configuring SSL-trust using a PKCS-12 or JKS trust store, deprecating their `truststore`, `truststore_password`, and `truststore_type` counterparts.
- Adds new `ssl_certificate_authorities` setting for configuring SSL-trust using a PEM-formated list certificate authorities, deprecating its `cacert` counterpart.
- Adds new `ssl_keystore_path`, `ssl_keystore_password`, and `ssl_keystore_type` settings for configuring SSL-identity using a PKCS-12 or JKS key store, deprecating their `keystore`, `keystore_password`, and `keystore_type` counterparts.
- Adds new `ssl_certificate` and `ssl_key` settings for configuring SSL-identity using a PEM-formatted certificate/key pair, deprecating their `client_cert` and `client_key` counterparts.
- Added a way for plugin maintainers to include this mixin _without_ supporting the now-deprecated SSL options.
- Added the `ssl_cipher_suites` option

## 7.2.0
- Feat: add `ssl_supported_protocols` option [#40](https://github.com/logstash-plugins/logstash-mixin-http_client/pull/40)

Expand Down
8 changes: 8 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,11 @@ source 'https://rubygems.org'

# Specify your gem's dependencies in logstash-mass_effect.gemspec
gemspec

logstash_path = ENV["LOGSTASH_PATH"] || "../../logstash"
use_logstash_source = ENV["LOGSTASH_SOURCE"] && ENV["LOGSTASH_SOURCE"].to_s == "1"

if Dir.exist?(logstash_path) && use_logstash_source
gem 'logstash-core', :path => "#{logstash_path}/logstash-core"
gem 'logstash-core-plugin-api', :path => "#{logstash_path}/logstash-core-plugin-api"
end
337 changes: 182 additions & 155 deletions lib/logstash/plugin_mixins/http_client.rb

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
module LogStash::PluginMixins::HttpClient
module DeprecatedSslConfigSupport
def self.included(base)
fail ArgumentError unless base <= LogStash::PluginMixins::HttpClient::Implementation

require 'logstash/plugin_mixins/normalize_config_support'
base.include(LogStash::PluginMixins::NormalizeConfigSupport)

# If you need to use a custom X.509 CA (.pem certs) specify the path to that here
base.config :cacert, :validate => :path, :deprecated => 'Use `ssl_certificate_authorities` instead'
# If you'd like to use a client certificate (note, most people don't want this) set the path to the x509 cert here
base.config :client_cert, :validate => :path, :deprecated => 'Use `ssl_certificate` instead'
# If you're using a client certificate specify the path to the encryption key here
base.config :client_key, :validate => :path, :deprecated => 'Use `ssl_key` instead'
# If you need to use a custom keystore (`.jks`) specify that here. This does not work with .pem keys!
base.config :keystore, :validate => :path, :deprecated => 'Use `ssl_keystore_path` instead'
# Specify the keystore password here.
# Note, most .jks files created with keytool require a password!
base.config :keystore_password, :validate => :password, :deprecated => 'Use `ssl_keystore_password` instead'
# Specify the keystore type here. One of `JKS` or `PKCS12`. Default is `JKS`
base.config :keystore_type, :validate => :string, :default => 'JKS', :deprecated => 'Use `ssl_keystore_type` instead'
# If you need to use a custom truststore (`.jks`) specify that here. This does not work with .pem certs!
base.config :truststore, :validate => :path, :deprecated => 'Use `ssl_truststore_path` instead'
# Specify the truststore password here.
# Note, most .jks files created with keytool require a password!
base.config :truststore_password, :validate => :password, :deprecated => 'Use `ssl_truststore_password` instead'
# Specify the truststore type here. One of `JKS` or `PKCS12`. Default is `JKS`
base.config :truststore_type, :validate => :string, :default => 'JKS', :deprecated => 'Use `ssl_truststore_type` instead'
# NOTE: the default setting [] uses Java SSL engine defaults.
end

def initialize(*a)
super

@ssl_certificate_authorities = normalize_config(:ssl_certificate_authorities) do |normalize|
normalize.with_deprecated_mapping(:cacert) do |cacert|
[cacert]
end
end

@ssl_certificate = normalize_config(:ssl_certificate) do |normalize|
normalize.with_deprecated_alias(:client_cert)
end

@ssl_key = normalize_config(:ssl_key) do |normalize|
normalize.with_deprecated_alias(:client_key)
end

%w[keystore truststore].each do |store|
%w[path type password].each do |variable|
config_name = "ssl_#{store}_#{variable}"
normalized_value = normalize_config(config_name) do |normalize|
deprecated_config_alias = variable == 'path' ? store : "#{store}_#{variable}"
normalize.with_deprecated_alias(deprecated_config_alias.to_sym)
end
instance_variable_set("@#{config_name}", normalized_value)
end
end
end

def ssl_options
fail(InvalidHTTPConfigError, "When `client_cert` is provided, `client_key` must also be provided") if @client_cert && !@client_key
fail(InvalidHTTPConfigError, "A `client_key` is not allowed unless a `client_cert` is provided") if @client_key && !@client_cert

fail(LogStash::ConfigurationError, "When `keystore` is provided, `keystore_password` must also be provided") if @keystore && !@keystore_password
fail(LogStash::ConfigurationError, "A `keystore_password` is not allowed unless a `keystore` is provided") if @keystore_password && !@keystore

fail(LogStash::ConfigurationError, "When `truststore` is provided, `truststore_password` must also be provided") if @truststore && !@truststore_password
fail(LogStash::ConfigurationError, "A `truststore_password` is not allowed unless a `truststore` is provided") if @truststore_password && !@truststore

super
end
end
end
3 changes: 2 additions & 1 deletion logstash-mixin-http_client.gemspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Gem::Specification.new do |s|
s.name = 'logstash-mixin-http_client'
s.version = '7.2.0'
s.version = '7.3.0'
s.licenses = ['Apache License (2.0)']
s.summary = "AWS mixins to provide a unified interface for Amazon Webservice"
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 @@ -19,6 +19,7 @@ Gem::Specification.new do |s|
s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
s.add_runtime_dependency 'logstash-codec-plain'
s.add_runtime_dependency 'manticore', '>= 0.8.0', '< 1.0.0'
s.add_runtime_dependency 'logstash-mixin-normalize_config_support', '~>1.0'

s.add_development_dependency 'logstash-devutils'
s.add_development_dependency 'stud'
Expand Down
177 changes: 1 addition & 176 deletions spec/plugin_mixin/http_client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

class Dummy < LogStash::Inputs::Base
include LogStash::PluginMixins::HttpClient
config_name 'dummy'
end

describe LogStash::PluginMixins::HttpClient do
Expand All @@ -29,51 +30,6 @@ class Dummy < LogStash::Inputs::Base
expect(impl.send(:client)).to eql(impl.client)
end

shared_examples "setting ca bundles" do |key, type|
subject { Dummy.new(conf).send(:client_config) }

it "should correctly set the path" do
expect(subject[:ssl][key]).to eql(path), "Expected to find path for #{key}"
end

if type == :jks
let(:store_password) { conf["#{key}_password"] }
let(:store_type) { conf["#{key}_type"]}

it "should set the bundle password" do
expect(subject[:ssl]["#{key}_password".to_sym]).to eql(store_password)
end

it "should set the bundle type" do
expect(subject[:ssl]["#{key}_type".to_sym]).to eql(store_type)
end
end
end

describe "with a custom ssl bundle" do
let(:file) { Stud::Temporary.file }
let(:path) { file.path }
after { File.unlink(path)}

context "with x509" do
let(:conf) { basic_config.merge("cacert" => path) }

include_examples("setting ca bundles", :ca_file)
end

context "with JKS" do
let(:conf) {
basic_config.merge(
"truststore" => path,
"truststore_password" => "foobar",
"truststore_type" => "jks"
)
}

include_examples("setting ca bundles", :truststore, :jks)
end
end

describe "with a custom validate_after_activity" do
subject { Dummy.new(client_config).send(:client_config) }

Expand Down Expand Up @@ -120,135 +76,4 @@ class Dummy < LogStash::Inputs::Base
end
end
end

["keystore", "truststore"].each do |store|
describe "with a custom #{store}" do
let(:file) { Stud::Temporary.file }
let(:path) { file.path }
let(:password) { "foo" }
after { File.unlink(path)}

let(:conf) {
basic_config.merge(
store => path,
"#{store}_password" => password,
"#{store}_type" => "jks"
)
}

include_examples("setting ca bundles", store.to_sym, :jks)

context "with no password set" do
let(:password) { nil }

it "should raise an error" do
expect do
Dummy.new(conf).client_config
end.to raise_error(LogStash::ConfigurationError)
end
end
end
end

describe "with a client cert" do
let(:file) { Stud::Temporary.file }
let(:path) { file.path }
after { File.unlink(path)}

context "with correct client certs" do
let(:conf) { basic_config.merge("client_cert" => path, "client_key" => path) }

it "should create without error" do
expect {
Dummy.new(conf).client_config
}.not_to raise_error
end
end

shared_examples("raising a configuration error") do
it "should raise an error error" do
expect {
Dummy.new(conf).client_config
}.to raise_error(LogStash::PluginMixins::HttpClient::InvalidHTTPConfigError)
end
end

context "without a key" do
let(:conf) { basic_config.merge("client_cert" => path) }

include_examples("raising a configuration error")
end

context "without a cert" do
let(:conf) { basic_config.merge("client_key" => path) }

include_examples("raising a configuration error")
end
end

describe "with verify mode" do
let(:file) { Stud::Temporary.file }
let(:path) { file.path }
after { File.unlink(path)}

context "default" do
let(:conf) { basic_config }

it "sets manticore verify to :strict" do
expect( Dummy.new(conf).client_config[:ssl] ).to include :verify => :strict
end
end

context "'full'" do
let(:conf) { basic_config.merge("ssl_verification_mode" => 'full') }

it "sets manticore verify to :strict" do
expect( Dummy.new(conf).client_config[:ssl] ).to include :verify => :strict
end
end

context "'none'" do
let(:conf) { basic_config.merge("ssl_verification_mode" => 'none') }

it "sets manticore verify to :disable" do
expect( Dummy.new(conf).client_config[:ssl] ).to include :verify => :disable
end
end

end

describe "with supported protocols" do
context "default" do
let(:conf) { basic_config }

it "does not set manticore protocols option" do
expect( Dummy.new(conf).client_config[:ssl] ).to_not include :protocols
end
end

context "empty" do
let(:conf) { basic_config.merge("ssl_supported_protocols" => []) }

it "does not set manticore protocols option" do
expect( Dummy.new(conf).client_config[:ssl] ).to_not include :protocols
end
end

context "'TLSv1.3'" do
let(:conf) { basic_config.merge("ssl_supported_protocols" => ['TLSv1.3']) }

it "sets manticore protocols option" do
expect( Dummy.new(conf).client_config[:ssl] ).to include :protocols => ['TLSv1.3']
end
end

context "'TLSv1.2' and 'TLSv1.3'" do
let(:conf) { basic_config.merge("ssl_supported_protocols" => ['TLSv1.3', 'TLSv1.2']) }

it "sets manticore protocols option" do
expect( Dummy.new(conf).client_config[:ssl] ).to include :protocols => ['TLSv1.3', 'TLSv1.2']
end
end

end
end
Loading

0 comments on commit 0e65a76

Please sign in to comment.