rails_kms_credentials 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []