settings_reader-vault_resolver 0.2.4 → 0.3.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: ce73ad9e3b10d933922778fa85c1f2fecc4f33dd0041a83c4b6b034229c7574f
4
- data.tar.gz: eef4339b9136147de04ba2e85648fbf2328c3771fed427e600edf544683c1c98
3
+ metadata.gz: c1a6da72b08435eb9eae6bff284c09d0ab717de2e73e3bfea7e4bdc255b1bf2b
4
+ data.tar.gz: 2003918d4ad830d9dc4ab0127ec0e970eb2994e66e42ce8fb3f3936e1bb2e476
5
5
  SHA512:
6
- metadata.gz: ddab1303046474d0da7916d9e64803d9c599f1ee80e2d50e2c96e4cc73ff17f5d4e0b45dd0db37447d3553596135883ca088868800c588f9ceffb7113457bfe4
7
- data.tar.gz: 6f31f31fccc0281890df52503a9b8c353229fe7cc6f4233eb251e69ed245ea63acdc8bd4cd9e9e5cd1e0f6ef00c448ba30e0afb732105d2322a0ae338180438d
6
+ metadata.gz: 4d4618260512414b329893c4651f1594398f34a5d54d94b0afe0989aa57f54208d85c16dae2f43fd0df3a0842f40c05e87202477a0c04dba9c6c0341f401f108
7
+ data.tar.gz: 6880bd9a5166bd7a01c2444fb4ce520a724c6df1ea6b4ec3ab1e844d4216602cd80b3d04b7d3b40dccbc3d9d3c7e808b54a818e2dadf78f9c9c400df4ea379dd
data/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.3.0]
4
+ ### Breaking changes
5
+ - Require configuration before use
6
+
7
+ ### New features
8
+ - Gem configurations
9
+ - Require configuration before use
10
+ - Report renew errors via configuration listeners
11
+
12
+ ### Fixes
13
+ - Cleanup logging
14
+
15
+ ## [0.2.4]
16
+ ### Fixes
17
+ - Fix refresher task logging
18
+
19
+ ## [0.2.3]
20
+ ### Fixes
21
+ - Fix logging setup when gem loaded before rails
22
+
23
+ ## [0.2.2]
24
+ ### New features
25
+ - Add logging to gem
26
+
3
27
  ## [0.2.1]
4
28
  ### Fixes
5
29
  - Use default k8s auth route without namespace
@@ -21,7 +45,11 @@
21
45
  - Secrets caching
22
46
  - Automatic secrets lease renewal
23
47
 
24
- [Unreleased]: https://github.com/matic-insurance/settings_reader-vault_resolver/compare/0.2.1...HEAD
48
+ [Unreleased]: https://github.com/matic-insurance/settings_reader-vault_resolver/compare/0.3.0...HEAD
49
+ [0.2.4]: https://github.com/matic-insurance/settings_reader-vault_resolver/commits/0.3.0
50
+ [0.2.4]: https://github.com/matic-insurance/settings_reader-vault_resolver/commits/0.2.4
51
+ [0.2.3]: https://github.com/matic-insurance/settings_reader-vault_resolver/commits/0.2.3
52
+ [0.2.2]: https://github.com/matic-insurance/settings_reader-vault_resolver/commits/0.2.2
25
53
  [0.2.1]: https://github.com/matic-insurance/settings_reader-vault_resolver/commits/0.2.1
26
54
  [0.2.0]: https://github.com/matic-insurance/settings_reader-vault_resolver/commits/0.2.0
27
55
  [0.1.1]: https://github.com/matic-insurance/settings_reader-vault_resolver/commits/0.1.1
data/README.md CHANGED
@@ -28,7 +28,13 @@ Vault.token = 'MY_SUPER_SECRET_TOKEN'
28
28
 
29
29
  #Load Settings Reader and configure resolver
30
30
  AppSettings = SettingsReader.load do |config|
31
- # ... Other configurations
31
+ # ... SettingReader configurations
32
+
33
+ # Configure vault resolver
34
+ SettingsReader::VaultResolver.configure do |vault_resolver_config|
35
+ vault_resolver_config.logger = Rails.logger
36
+ # ... VaultResolver configurations
37
+ end
32
38
 
33
39
  # Add vault resolver as one of resolvers
34
40
  config.resolvers << SettingsReader::VaultResolver.resolver
data/codecov.yml ADDED
@@ -0,0 +1,12 @@
1
+ codecov:
2
+ require_ci_to_pass: yes
3
+
4
+ coverage:
5
+ precision: 2
6
+ round: up
7
+ range: "90...100"
8
+
9
+ ignore:
10
+ - "spec"
11
+ - "bin"
12
+ - "local"
@@ -0,0 +1,45 @@
1
+ module SettingsReader
2
+ module VaultResolver
3
+ # Configurations for vault resolver
4
+ class Configuration
5
+ # Logger for gem
6
+ # Default: Logger.new(STDOUT, level: Logger::ERROR)
7
+ attr_accessor :logger
8
+
9
+ # How often do we check if secret lease is about to expire
10
+ # Default: 60seconds
11
+ attr_accessor :lease_refresh_interval
12
+
13
+ # Time before expiration when we try to renew the lease
14
+ # Default: 300seconds
15
+ attr_accessor :lease_renew_delay
16
+
17
+ # Block to be executed when lease is refreshed
18
+ # Default: empty proc
19
+ attr_accessor :lease_renew_success_listener
20
+
21
+ # Block to be executed when lease is not refreshed
22
+ # Default: empty proc
23
+ attr_accessor :lease_renew_error_listener
24
+
25
+ def initialize
26
+ @logger = Logger.new($stdout, level: Logger::ERROR)
27
+ @lease_refresh_interval = 60
28
+ @lease_renew_delay = 300
29
+ @lease_renew_error_listener = proc {}
30
+ @lease_renew_success_listener = proc {}
31
+ end
32
+
33
+ def setup_lease_refresher(cache, previous_task = nil)
34
+ previous_task&.shutdown
35
+
36
+ timer_task = Concurrent::TimerTask.new(execution_interval: lease_refresh_interval) do
37
+ SettingsReader::VaultResolver::Refresher.new(cache, self).refresh
38
+ end
39
+ timer_task.add_observer(SettingsReader::VaultResolver::RefresherObserver.new(self))
40
+ timer_task.execute
41
+ timer_task
42
+ end
43
+ end
44
+ end
45
+ end
@@ -9,6 +9,12 @@ module SettingsReader
9
9
  IDENTIFIER = 'vault://'.freeze
10
10
  DATABASE_MOUNT = 'database'.freeze
11
11
 
12
+ attr_reader :config
13
+
14
+ def initialize(config)
15
+ @config = config
16
+ end
17
+
12
18
  def resolvable?(value, _path)
13
19
  return unless value.respond_to?(:start_with?)
14
20
 
@@ -28,7 +34,6 @@ module SettingsReader
28
34
  debug { "Fetching new kv secret at: #{address}" }
29
35
  Vault.kv(address.mount).read(address.path)
30
36
  rescue Vault::HTTPClientError => e
31
- error { "Error retrieving secret at: #{address}: #{e.message}" }
32
37
  raise SettingsReader::VaultResolver::Error, e.message
33
38
  end
34
39
 
@@ -36,7 +41,6 @@ module SettingsReader
36
41
  debug { "Fetching new database secret at: #{address}" }
37
42
  Vault.logical.read(address.full_path)
38
43
  rescue Vault::HTTPClientError => e
39
- error { "Error retrieving database secret: #{address}: #{e.message}" }
40
44
  return nil if e.message.include?('* unknown role')
41
45
 
42
46
  raise SettingsReader::VaultResolver::Error, e.message
@@ -50,10 +54,11 @@ module SettingsReader
50
54
  if (secret = address.mount == DATABASE_MOUNT ? database_secret(address) : kv_secret(address))
51
55
  debug { "Retrieved secret at: #{address}" }
52
56
  SettingsReader::VaultResolver::Entry.new(address, secret)
53
- else
54
- debug { "Secret not retrieved: #{address}" }
55
57
  end
56
58
  end
59
+ rescue StandardError => e
60
+ error { "Error retrieving secret: #{address}: #{e.message}" }
61
+ raise e
57
62
  end
58
63
 
59
64
  def cache
@@ -3,37 +3,34 @@ module SettingsReader
3
3
  # Methods for centralized logging
4
4
  module Logging
5
5
  def debug(&block)
6
- logger.debug do
7
- "[VaultResolver] #{block.call}"
8
- end
9
- nil
6
+ log_message(Logger::DEBUG, &block)
10
7
  end
11
8
 
12
9
  def info(&block)
13
- logger.info do
14
- "[VaultResolver] #{block.call}"
15
- end
16
- nil
10
+ log_message(Logger::INFO, &block)
17
11
  end
18
12
 
19
13
  def warn(&block)
20
- logger.warn do
21
- "[VaultResolver] #{block.call}"
22
- end
23
- nil
14
+ log_message(Logger::WARN, &block)
24
15
  end
25
16
 
26
17
  def error(&block)
27
- logger.error do
18
+ log_message(Logger::ERROR, &block)
19
+ end
20
+
21
+ private
22
+
23
+ def log_message(severity, &block)
24
+ logger&.log(severity) do
28
25
  "[VaultResolver] #{block.call}"
26
+ rescue StandardError => _e
27
+ # Ignoring errors in log message
29
28
  end
30
29
  nil
31
30
  end
32
31
 
33
- private
34
-
35
32
  def logger
36
- SettingsReader::VaultResolver.logger
33
+ config.logger
37
34
  end
38
35
  end
39
36
  end
@@ -1,3 +1,5 @@
1
+ require 'concurrent/promise'
2
+
1
3
  module SettingsReader
2
4
  module VaultResolver
3
5
  # Vault Lease refresher task
@@ -7,35 +9,34 @@ module SettingsReader
7
9
  DEFAULT_RENEW_DELAY = 200
8
10
  REFRESH_INTERVAL = 60
9
11
 
10
- def initialize(cache)
12
+ attr_reader :cache, :config
13
+
14
+ def initialize(cache, config)
11
15
  @cache = cache
16
+ @config = config
12
17
  end
13
18
 
14
19
  def refresh
15
- info { 'Starting Vault lease refreshing' }
16
- @cache.entries.each do |entry|
20
+ info { 'Performing Vault leases refresh' }
21
+ promises = cache.entries.map do |entry|
22
+ debug { "Checking lease for #{entry}. Leased?: #{entry.leased?}. Expires in: #{entry.expires_in}s" }
17
23
  refresh_entry(entry)
18
- end
19
- info { 'Finished Vault lease refreshing' }
24
+ end.compact
25
+ promises.each(&:wait)
26
+ promises
20
27
  end
21
28
 
22
29
  def refresh_entry(entry)
23
- debug { "Checking lease for #{entry}. Leased?: #{entry.leased?}. Expires in: #{entry.expires_in}s" }
24
- return unless entry.leased?
25
- return unless entry.expires_in < DEFAULT_RENEW_DELAY
26
-
27
- info { "Refreshing lease for #{entry}. Expires in: #{entry.expires_in}" }
28
- entry.renew
29
- info { "Lease renewed for #{entry}. Expires in: #{entry.expires_in}" }
30
- rescue SettingsReader::VaultResolver::Error => e
31
- error { "Error refreshing lease for #{entry}: #{e.message}" }
32
- # Continue renewal.
33
- end
30
+ return unless entry.leased? && entry.expires_in < config.lease_renew_delay
34
31
 
35
- def self.refresh_task(cache)
36
- refresher = self
37
- Concurrent::TimerTask.new(execution_interval: refresher::REFRESH_INTERVAL) do
38
- refresher.new(cache).refresh
32
+ Concurrent::Promise.execute do
33
+ debug { "Refreshing lease for #{entry}. Expires in: #{entry.expires_in}" }
34
+ entry.renew
35
+ info { "Lease renewed for #{entry}. Expires in: #{entry.expires_in}" }
36
+ entry
37
+ rescue StandardError => e
38
+ error { "Error refreshing lease for #{entry}: #{e.message}" }
39
+ raise SettingsReader::VaultResolver::Error, e.message
39
40
  end
40
41
  end
41
42
  end
@@ -0,0 +1,30 @@
1
+ module SettingsReader
2
+ module VaultResolver
3
+ # Check lease refresh result and report problems if needed
4
+ class RefresherObserver
5
+ attr_reader :config
6
+
7
+ def initialize(config)
8
+ @config = config
9
+ end
10
+
11
+ def update(_time, result, error)
12
+ if result
13
+ result.map do |promise|
14
+ promise.on_success(&method(:notify_success)).on_error(&method(:notify_error))
15
+ end.each(&:wait)
16
+ else
17
+ notify_error(error)
18
+ end
19
+ end
20
+
21
+ def notify_success(result)
22
+ config.lease_renew_success_listener.call(result)
23
+ end
24
+
25
+ def notify_error(result)
26
+ config.lease_renew_error_listener.call(result)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,5 +1,5 @@
1
1
  module SettingsReader
2
2
  module VaultResolver
3
- VERSION = '0.2.4'.freeze
3
+ VERSION = '0.3.0'.freeze
4
4
  end
5
5
  end
@@ -4,10 +4,12 @@ require 'concurrent/timer_task'
4
4
  require 'settings_reader'
5
5
  require 'settings_reader/vault_resolver/version'
6
6
  require 'settings_reader/vault_resolver/logging'
7
+ require 'settings_reader/vault_resolver/configuration'
7
8
  require 'settings_reader/vault_resolver/address'
8
9
  require 'settings_reader/vault_resolver/entry'
9
10
  require 'settings_reader/vault_resolver/cache'
10
11
  require 'settings_reader/vault_resolver/refresher'
12
+ require 'settings_reader/vault_resolver/refresher_observer'
11
13
  require 'settings_reader/vault_resolver/instance'
12
14
 
13
15
  module SettingsReader
@@ -16,36 +18,23 @@ module SettingsReader
16
18
  class Error < StandardError; end
17
19
 
18
20
  class << self
19
- attr_accessor :cache, :refresher_timer_task
21
+ attr_reader :configuration, :refresher_timer_task
20
22
  end
21
23
 
22
- def self.logger
23
- return @logger if @logger
24
- return @logger = Rails.logger if (defined? Rails) && Rails.logger
25
-
26
- @logger = Logger.new($stdout, level: Logger::INFO)
27
- end
28
-
29
- def self.logger=(logger)
30
- @logger = logger
24
+ def self.configure(&block)
25
+ @configuration = SettingsReader::VaultResolver::Configuration.new
26
+ block&.call(@configuration)
27
+ @refresher_timer_task = @configuration.setup_lease_refresher(cache, refresher_timer_task)
31
28
  end
32
29
 
33
- def self.setup_cache
34
- logger.debug { '[VaultResolver] Setting up secrets cache' }
35
- self.cache ||= SettingsReader::VaultResolver::Cache.new
36
- end
37
-
38
- def self.setup_lease_refresher
39
- logger.debug { '[VaultResolver] Setting up lease resolver task' }
40
- self.refresher_timer_task ||= SettingsReader::VaultResolver::Refresher.refresh_task(self.cache)
41
- self.refresher_timer_task.execute
30
+ def self.cache
31
+ @cache ||= SettingsReader::VaultResolver::Cache.new
42
32
  end
43
33
 
44
34
  def self.resolver
45
- SettingsReader::VaultResolver::Instance.new
46
- end
35
+ raise Error, 'Gem not configured. Call configure before getting resolver' unless configuration
47
36
 
48
- setup_cache
49
- setup_lease_refresher
37
+ SettingsReader::VaultResolver::Instance.new(configuration)
38
+ end
50
39
  end
51
40
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: settings_reader-vault_resolver
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Volodymyr Mykhailyk
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-03-28 00:00:00.000000000 Z
11
+ date: 2022-03-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -77,16 +77,19 @@ files:
77
77
  - Rakefile
78
78
  - bin/console
79
79
  - bin/setup
80
+ - codecov.yml
80
81
  - docker-compose.yml
81
82
  - lib/settings_reader/vault_resolver.rb
82
83
  - lib/settings_reader/vault_resolver/address.rb
83
84
  - lib/settings_reader/vault_resolver/cache.rb
85
+ - lib/settings_reader/vault_resolver/configuration.rb
84
86
  - lib/settings_reader/vault_resolver/entry.rb
85
87
  - lib/settings_reader/vault_resolver/helpers/k8s_auth.rb
86
88
  - lib/settings_reader/vault_resolver/instance.rb
87
89
  - lib/settings_reader/vault_resolver/logging.rb
88
90
  - lib/settings_reader/vault_resolver/patches/authenticate.rb
89
91
  - lib/settings_reader/vault_resolver/refresher.rb
92
+ - lib/settings_reader/vault_resolver/refresher_observer.rb
90
93
  - lib/settings_reader/vault_resolver/version.rb
91
94
  - settings_reader-vault_resolver.gemspec
92
95
  homepage: https://github.com/matic-insurance/settings_reader-vault_resolver