settings_reader-vault_resolver 0.2.2 → 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: 16ca7880831b27b05c24651940a1dab796b792f7d98229f2f01e229ffcee5662
4
- data.tar.gz: ff8e434b0512ce66772e8f99b16761ea51597614b195abb91889a5543ba88267
3
+ metadata.gz: c1a6da72b08435eb9eae6bff284c09d0ab717de2e73e3bfea7e4bdc255b1bf2b
4
+ data.tar.gz: 2003918d4ad830d9dc4ab0127ec0e970eb2994e66e42ce8fb3f3936e1bb2e476
5
5
  SHA512:
6
- metadata.gz: e1476c785e7369a2a2f3d4ee47a149cfd3c1fc2ebf333a94a1ec158c564584995ced9392fa08e1be9ec16ba166c0f20899414e02622473a4d0058ef5d70abce2
7
- data.tar.gz: 8c1a40bd635b8e9de7193114618a0669e3c9d3ffabae250ff5efc416a31636c199584bb7e474373ead29bde9e85e281adbba0e7ba123358e1729d0e599bf17bf
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
- @logger ||= 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,30 +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
- @cache.entries.each do |entry|
20
+ info { 'Performing Vault leases refresh' }
21
+ promises = cache.entries.map do |entry|
16
22
  debug { "Checking lease for #{entry}. Leased?: #{entry.leased?}. Expires in: #{entry.expires_in}s" }
17
- next unless entry.leased?
18
- next unless entry.expires_in < DEFAULT_RENEW_DELAY
23
+ refresh_entry(entry)
24
+ end.compact
25
+ promises.each(&:wait)
26
+ promises
27
+ end
28
+
29
+ def refresh_entry(entry)
30
+ return unless entry.leased? && entry.expires_in < config.lease_renew_delay
19
31
 
20
- info { "Refreshing lease for #{entry}. Expires in: #{entry.expires_in}" }
32
+ Concurrent::Promise.execute do
33
+ debug { "Refreshing lease for #{entry}. Expires in: #{entry.expires_in}" }
21
34
  entry.renew
22
35
  info { "Lease renewed for #{entry}. Expires in: #{entry.expires_in}" }
23
- rescue SettingsReader::VaultResolver::Error => e
36
+ entry
37
+ rescue StandardError => e
24
38
  error { "Error refreshing lease for #{entry}: #{e.message}" }
25
- # Continue renewal.
26
- end
27
- end
28
-
29
- def self.refresh_task(cache)
30
- refresher = self
31
- Concurrent::TimerTask.new(execution_interval: refresher::REFRESH_INTERVAL) do
32
- info { 'Refreshing Vault leases' }
33
- refresher.new(cache).refresh
39
+ raise SettingsReader::VaultResolver::Error, e.message
34
40
  end
35
41
  end
36
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.2'.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,30 +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
25
-
26
- @logger = Logger.new($stdout, level: Logger::INFO)
27
- end
28
-
29
- def self.setup_cache
30
- self.cache ||= SettingsReader::VaultResolver::Cache.new
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_lease_refresher
34
- self.refresher_timer_task ||= SettingsReader::VaultResolver::Refresher.refresh_task(self.cache)
35
- self.refresher_timer_task.execute
30
+ def self.cache
31
+ @cache ||= SettingsReader::VaultResolver::Cache.new
36
32
  end
37
33
 
38
34
  def self.resolver
39
- SettingsReader::VaultResolver::Instance.new
40
- end
35
+ raise Error, 'Gem not configured. Call configure before getting resolver' unless configuration
41
36
 
42
- setup_cache
43
- setup_lease_refresher
37
+ SettingsReader::VaultResolver::Instance.new(configuration)
38
+ end
44
39
  end
45
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.2
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