rails_kms_credentials 0.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d9002ffd4c1c4c037cfefa42fa524a68c695d6fdfa7010a966e5d6a0ed1c0130
4
+ data.tar.gz: cd9410a02314fcc000d5e5e44f1947aa8aa0e5a50a8e434fc29775073ced335c
5
+ SHA512:
6
+ metadata.gz: 14fc42d0dc79b8da2b0458a8109bf7aa224230e9cb76975fbed7412c32d795c7cfea449a9d75ee62406c9bbbf7995a2776f6bf1281ae3192cee43184b50671ad
7
+ data.tar.gz: 4bd8c88b3788508b5ba3e1b3223aceebb862a6595ec76b96b00e70370bb8d2f0e9b43c77b0cd9c2463c4270da17cca0b2bab65e125115c035dc14fd4ff0a4c1c
data/README.md ADDED
@@ -0,0 +1 @@
1
+ # rails-kms-credentials
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsKmsCredentials
4
+ module Application
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ def credentials
9
+ kms_credentials.store.credentials
10
+ end
11
+
12
+ def kms_credentials
13
+ @kms_credentials ||= Credentials.new(config.kms_credentials)
14
+ end
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsKmsCredentials
4
+ class CredentialsConfig < ActiveSupport::OrderedOptions
5
+ end
6
+
7
+ module Configuration
8
+ extend ActiveSupport::Concern
9
+
10
+ def kms_credentials
11
+ @kms_credentials ||= Rails.application.config_for(:kms_credentials).with_indifferent_access
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsKmsCredentials
4
+ class Credentials
5
+ attr_reader :config, :store
6
+
7
+ def initialize(config)
8
+ @config = config
9
+ @_store_klass = Store.get config['store']
10
+ @store = @_store_klass.new self
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,12 @@
1
+ require 'rails'
2
+
3
+ module RailsKmsCredentials
4
+ class Railtie < Rails::Railtie
5
+ railtie_name :rails_kms_credentials
6
+
7
+ rake_tasks do
8
+ load 'tasks/credentials.rake'
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsKmsCredentials
4
+ module Store
5
+ module AzureKeyVault
6
+ module Client
7
+ class Base
8
+ attr_reader :store
9
+
10
+ delegate :config, to: :store
11
+
12
+ def initialize(store)
13
+ @store = store
14
+ end
15
+
16
+ def get_secrets_list(url)
17
+ raise NotImplementedError
18
+ end
19
+
20
+ def get_secret(url)
21
+ raise NotImplementedError
22
+ end
23
+
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsKmsCredentials
4
+ module Store
5
+ module AzureKeyVault
6
+ module Client
7
+ class ClientCredentials < Base
8
+ attr_reader :tenant_id, :client_id, :client_secret
9
+
10
+ def initialize(*)
11
+ super
12
+ @tenant_id = client_config['tenant_id']
13
+ raise 'Missing KmsCredentials AzureKeyVault ClientCredentials tenant_id' if tenant_id.blank?
14
+ @client_id = client_config['client_id']
15
+ raise 'Missing KmsCredentials AzureKeyVault ClientCredentials client_id' if client_id.blank?
16
+ @client_secret = client_config['client_secret']
17
+ raise 'Missing KmsCredentials AzureKeyVault ClientCredentials client_secret' if client_secret.blank?
18
+ end
19
+
20
+ def get_secrets_list(url)
21
+ HTTParty.get(
22
+ url,
23
+ headers: {
24
+ Authorization: "Bearer #{access_token}",
25
+ },
26
+ )
27
+ end
28
+
29
+ def get_secret(url)
30
+ HTTParty.get(
31
+ url,
32
+ headers: {
33
+ Authorization: "Bearer #{access_token}",
34
+ },
35
+ )
36
+ end
37
+
38
+ private
39
+
40
+ def client_config
41
+ config['client']
42
+ end
43
+
44
+ def access_token
45
+ return @access_token if instance_variable_defined?(:@access_token)
46
+ @_access_token_response = HTTParty.post(
47
+ "https://login.microsoftonline.com/#{client_config['tenant_id']}/oauth2/v2.0/token",
48
+ {
49
+ body: {
50
+ client_id: client_config['client_id'],
51
+ client_secret: client_config['client_secret'],
52
+ scope: 'https://vault.azure.net/.default',
53
+ grant_type: 'client_credentials',
54
+ }
55
+ }
56
+ )
57
+ raise 'KmsCredentials AzureKeyVault ClientCredentials unable to get access token' unless @_access_token_response.ok?
58
+ @access_token = @_access_token_response['access_token']
59
+ end
60
+
61
+ end
62
+
63
+ add(:client_credentials, ClientCredentials)
64
+
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsKmsCredentials
4
+ module Store
5
+ module AzureKeyVault
6
+ module Client
7
+ class ManagedIdentity < Base
8
+ def get_secrets_list(url)
9
+ HTTParty.get url
10
+ end
11
+
12
+ def get_secret(url)
13
+ HTTParty.get url
14
+ end
15
+
16
+ end
17
+
18
+ add(:managed_identity, ManagedIdentity)
19
+
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsKmsCredentials
4
+ module Store
5
+ module AzureKeyVault
6
+ module Client
7
+ @map = {}.with_indifferent_access
8
+
9
+ class << self
10
+ attr_reader :map
11
+
12
+ def get(client)
13
+ map[client] || raise("KmsCredentials AzureKeyVault unknown client: `#{client}`")
14
+ end
15
+
16
+ def add(name, klass)
17
+ map[name] = klass
18
+ end
19
+
20
+ end
21
+
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ require 'rails_kms_credentials/store/azure_key_vault/client/base'
28
+ require 'rails_kms_credentials/store/azure_key_vault/client/client_credentials'
29
+ require 'rails_kms_credentials/store/azure_key_vault/client/managed_identity'
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsKmsCredentials
4
+ module Store
5
+ module AzureKeyVault
6
+
7
+ class Store < Base::Store
8
+ attr_reader :vault, :vault_url, :client
9
+
10
+ SECRETS_API_VERSION = '7.3'
11
+
12
+ EMPTY_VALUE = '--EMPTY--'
13
+
14
+ def initialize(*) # rubocop:disable Metrics/AbcSize
15
+ super
16
+ @vault = config['vault']
17
+ raise 'Missing KmsCredentials AzureKeyVault vault' if vault.blank?
18
+ raise "Invalid KmsCredentials AzureKeyVault vault `#{vault}`" if vault =~ /[^0-9a-zA-Z\-]/
19
+ @vault_url = "https://#{vault}.vault.azure.net"
20
+ raise 'Missing KmsCredentials AzureKeyVault client' unless config['client'].is_a? Hash
21
+ raise 'Missing KmsCredentials AzureKeyVault client.type' if config['client']['type'].blank?
22
+ @_client_klass = Client.get config['client']['type']
23
+ @client = @_client_klass.new self
24
+ @loaded = false
25
+ end
26
+
27
+ def credentials # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
28
+ return @credentials if instance_variable_defined?(:@credentials)
29
+ load_secrets
30
+ @credentials = @_secrets.values.each_with_object(ActiveSupport::OrderedOptions.new) do |secret, memo|
31
+ name = secret['name'].split('--')
32
+ name.each { |x| x.gsub!('-', '_') }
33
+ parent = name[0..-2].inject(memo) do |h, key|
34
+ if h.key?(key) && !h[key].is_a?(ActiveSupport::OrderedOptions)
35
+ raise "KmsCredentials AzureKeyVault credentials format issue: #{secret['name']}"
36
+ end
37
+ h[key] ||= ActiveSupport::OrderedOptions.new
38
+ end
39
+ parent[name.last] = secret['value'] == EMPTY_VALUE ? '' : secret['value']
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def load_secrets
46
+ return if @loaded
47
+ load_secrets_list
48
+ end
49
+
50
+ def load_secrets_list(url = nil) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
51
+ @_get_secrets_list_responses ||= []
52
+ @_secrets ||= {}
53
+ url ||= "#{vault_url}/secrets?api-version=#{SECRETS_API_VERSION}"
54
+ response = client.get_secrets_list url
55
+ @_get_secrets_list_responses << response
56
+ raise "KmsCredentials AzureKeyVault unable to get list of secrets: #{url}" unless response.ok?
57
+ response['value'].each do |secret|
58
+ secret_name = secret['id'].split('/').last
59
+ secret['name'] = secret_name
60
+ @_secrets[secret_name] = secret
61
+ load_secret secret_name
62
+ end
63
+ if response['nextLink']
64
+ load_secrets_list(response['nextLink'])
65
+ else
66
+ @loaded = true
67
+ end
68
+ end
69
+
70
+ def load_secret(secret_name)
71
+ @_get_secret_responses ||= {}
72
+ return unless (secret = @_secrets[secret_name])
73
+ response = client.get_secret "#{secret['id']}?api-version=#{SECRETS_API_VERSION}"
74
+ @_get_secret_responses[secret_name] = response
75
+ raise "KmsCredentials AzureKeyVault unable to get secret: #{secret['id']}" unless response.ok?
76
+ secret['value'] = response['value']
77
+ end
78
+
79
+ end
80
+ end
81
+
82
+ add(:azure_key_vault, AzureKeyVault::Store)
83
+
84
+ end
85
+ end
86
+
87
+ require 'rails_kms_credentials/store/azure_key_vault/client'
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsKmsCredentials
4
+ module Store
5
+ module Base
6
+ class Store
7
+ attr_reader :root
8
+
9
+ delegate :config, to: :root
10
+
11
+ def initialize(root)
12
+ @root = root
13
+ end
14
+
15
+ def credentials
16
+ raise NotImplementedError
17
+ end
18
+
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsKmsCredentials
4
+ module Store
5
+ @map = {}.with_indifferent_access
6
+
7
+ class << self
8
+ attr_reader :map
9
+
10
+ def get(store)
11
+ map[store] || raise("KmsCredentials unknown store: `#{store}`")
12
+ end
13
+
14
+ def add(name, klass)
15
+ map[name] = klass
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+ end
22
+
23
+ require 'rails_kms_credentials/store/base'
24
+ require 'rails_kms_credentials/store/azure_key_vault'
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsKmsCredentials
4
+
5
+ module Version
6
+ MAJOR = 0
7
+ MINOR = 0
8
+ PATCH = 1
9
+
10
+ end
11
+
12
+ VERSION = [
13
+ Version::MAJOR,
14
+ Version::MINOR,
15
+ Version::PATCH,
16
+ ].join('.').freeze
17
+
18
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Container Module
4
+ module RailsKmsCredentials; end
5
+
6
+ require 'active_support/concern'
7
+
8
+ require 'rails_kms_credentials/application'
9
+ require 'rails_kms_credentials/configuration'
10
+ require 'rails_kms_credentials/credentials'
11
+ require 'rails_kms_credentials/store'
12
+ require 'rails_kms_credentials/railtie'
13
+ require 'rails_kms_credentials/version'
14
+
15
+ Rails::Application::Configuration.send(:include, RailsKmsCredentials::Configuration)
16
+ Rails::Application.send(:include, RailsKmsCredentials::Application)
@@ -0,0 +1,8 @@
1
+ namespace :kms_creds do
2
+ task :show, [:environment] do |_, args|
3
+ end
4
+
5
+ task :edit, [:environment] do |_, args|
6
+ ENV['EDITOR'] += ' --wait' if ENV['EDITOR'].present? && (ENV['EDITOR'] == 'code' || ENV['EDITOR'].ends_with?('/code')) # Stupid fix for vscode exiting too quickly
7
+ end
8
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH << File.join(File.dirname(__FILE__), 'lib')
4
+ require 'rails_kms_credentials/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = 'rails_kms_credentials'
8
+ s.version = RailsKmsCredentials::VERSION
9
+ s.authors = ['Taylor Yelverton']
10
+ s.email = 'rubygems@yelvert.io'
11
+ s.homepage = 'https://github.com/ComplyMD/rails_kms_credentials'
12
+ s.summary = 'Add support for different credentials for different kmss to Rails'
13
+ s.license = 'MIT'
14
+ s.description = 'Add support for different credentials for different kmss to Rails'
15
+ s.metadata = {
16
+ 'bug_tracker_uri' => 'https://github.com/ComplyMD/rails_kms_credentials/issues',
17
+ 'changelog_uri' => 'https://github.com/ComplyMD/rails_kms_credentials/commits/master',
18
+ 'documentation_uri' => 'https://github.com/ComplyMD/rails_kms_credentials/wiki',
19
+ 'homepage_uri' => 'https://github.com/ComplyMD/rails_kms_credentials',
20
+ 'source_code_uri' => 'https://github.com/ComplyMD/rails_kms_credentials',
21
+ 'rubygems_mfa_required' => 'true',
22
+ }
23
+
24
+ s.files = Dir['lib/**/*','README.md','MIT-LICENSE','rails_kms_credentials.gemspec']
25
+
26
+ s.require_paths = %w[ lib ]
27
+
28
+ s.required_ruby_version = '>= 2.7.0'
29
+
30
+ s.add_dependency('activesupport', '>= 5.0.0')
31
+ s.add_dependency('railties', '>= 5.0.0')
32
+
33
+ s.add_dependency('httparty', '~> 0.17.0')
34
+ end
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails_kms_credentials
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Taylor Yelverton
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-11-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 5.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 5.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: railties
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 5.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 5.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: httparty
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.17.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.17.0
55
+ description: Add support for different credentials for different kmss to Rails
56
+ email: rubygems@yelvert.io
57
+ executables: []
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - README.md
62
+ - lib/rails_kms_credentials.rb
63
+ - lib/rails_kms_credentials/application.rb
64
+ - lib/rails_kms_credentials/configuration.rb
65
+ - lib/rails_kms_credentials/credentials.rb
66
+ - lib/rails_kms_credentials/railtie.rb
67
+ - lib/rails_kms_credentials/store.rb
68
+ - lib/rails_kms_credentials/store/azure_key_vault.rb
69
+ - lib/rails_kms_credentials/store/azure_key_vault/client.rb
70
+ - lib/rails_kms_credentials/store/azure_key_vault/client/base.rb
71
+ - lib/rails_kms_credentials/store/azure_key_vault/client/client_credentials.rb
72
+ - lib/rails_kms_credentials/store/azure_key_vault/client/managed_identity.rb
73
+ - lib/rails_kms_credentials/store/base.rb
74
+ - lib/rails_kms_credentials/version.rb
75
+ - lib/tasks/credentials.rake
76
+ - rails_kms_credentials.gemspec
77
+ homepage: https://github.com/ComplyMD/rails_kms_credentials
78
+ licenses:
79
+ - MIT
80
+ metadata:
81
+ bug_tracker_uri: https://github.com/ComplyMD/rails_kms_credentials/issues
82
+ changelog_uri: https://github.com/ComplyMD/rails_kms_credentials/commits/master
83
+ documentation_uri: https://github.com/ComplyMD/rails_kms_credentials/wiki
84
+ homepage_uri: https://github.com/ComplyMD/rails_kms_credentials
85
+ source_code_uri: https://github.com/ComplyMD/rails_kms_credentials
86
+ rubygems_mfa_required: 'true'
87
+ post_install_message:
88
+ rdoc_options: []
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: 2.7.0
96
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ requirements: []
102
+ rubygems_version: 3.1.4
103
+ signing_key:
104
+ specification_version: 4
105
+ summary: Add support for different credentials for different kmss to Rails
106
+ test_files: []