vault_api 1.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cad0684533828eb9a886d3fd4f87d2c0e6767167
4
+ data.tar.gz: 59365c804b209091283966c83e9ceb4949435a6a
5
+ SHA512:
6
+ metadata.gz: c29828e3d653be206b029443a129d42275efb17ac760ed17d6d643819774a7c6f41b884aec702f99e0f24238ee1828b15f98fcd623e232d5e362150a9d32e077
7
+ data.tar.gz: 54de3d79f44d5a9146477d185d804cdfdfad9972bc6d5391f257feb42d09db6f9038b4e30529e09d7bb91bc9201327aceb94f24dfb328d1959b1e0d293042ef0
data/CHANGELOG ADDED
@@ -0,0 +1,9 @@
1
+ === 1.0.0
2
+ * Added Vault API.
3
+ * Reorganised directory structure.
4
+ * Increased the configurability.
5
+ * Renamed the configs to secrets.
6
+ * Added ability to add and delete keys.
7
+ * Added ability to clone keys from global to target_users.
8
+ * Added ability to configure capabilities for .
9
+ * Added ability for CRUD operations for Users, Paths, Policies, Secrets, Entries.
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,124 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ vault_api (1.0.0)
5
+ activesupport
6
+ hashie
7
+ nokogiri
8
+ rest-client
9
+ vault
10
+ vcr (= 3.0)
11
+ webmock
12
+
13
+ GEM
14
+ remote: https://rubygems.org/
15
+ specs:
16
+ activesupport (5.2.3)
17
+ concurrent-ruby (~> 1.0, >= 1.0.2)
18
+ i18n (>= 0.7, < 2)
19
+ minitest (~> 5.1)
20
+ tzinfo (~> 1.1)
21
+ addressable (2.6.0)
22
+ public_suffix (>= 2.0.2, < 4.0)
23
+ ast (2.4.0)
24
+ awesome_print (1.8.0)
25
+ aws-eventstream (1.0.3)
26
+ aws-sigv4 (1.1.0)
27
+ aws-eventstream (~> 1.0, >= 1.0.2)
28
+ byebug (10.0.2)
29
+ coderay (1.1.2)
30
+ concurrent-ruby (1.1.5)
31
+ crack (0.4.3)
32
+ safe_yaml (~> 1.0.0)
33
+ diff-lcs (1.3)
34
+ domain_name (0.5.20180417)
35
+ unf (>= 0.0.5, < 1.0.0)
36
+ hashdiff (0.4.0)
37
+ hashie (3.6.0)
38
+ http-cookie (1.0.3)
39
+ domain_name (~> 0.5)
40
+ i18n (1.6.0)
41
+ concurrent-ruby (~> 1.0)
42
+ jaro_winkler (1.5.3)
43
+ method_source (0.9.0)
44
+ mime-types (3.2.2)
45
+ mime-types-data (~> 3.2015)
46
+ mime-types-data (3.2019.0331)
47
+ mini_portile2 (2.4.0)
48
+ minitest (5.11.3)
49
+ netrc (0.11.0)
50
+ nokogiri (1.10.3)
51
+ mini_portile2 (~> 2.4.0)
52
+ parallel (1.17.0)
53
+ parser (2.6.3.0)
54
+ ast (~> 2.4.0)
55
+ pry (0.11.3)
56
+ coderay (~> 1.1.0)
57
+ method_source (~> 0.9.0)
58
+ public_suffix (3.1.1)
59
+ rainbow (3.0.0)
60
+ rake (10.5.0)
61
+ rest-client (2.0.2)
62
+ http-cookie (>= 1.0.2, < 2.0)
63
+ mime-types (>= 1.16, < 4.0)
64
+ netrc (~> 0.8)
65
+ rspec (3.7.0)
66
+ rspec-core (~> 3.7.0)
67
+ rspec-expectations (~> 3.7.0)
68
+ rspec-mocks (~> 3.7.0)
69
+ rspec-core (3.7.1)
70
+ rspec-support (~> 3.7.0)
71
+ rspec-expectations (3.7.0)
72
+ diff-lcs (>= 1.2.0, < 2.0)
73
+ rspec-support (~> 3.7.0)
74
+ rspec-mocks (3.7.0)
75
+ diff-lcs (>= 1.2.0, < 2.0)
76
+ rspec-support (~> 3.7.0)
77
+ rspec-support (3.7.1)
78
+ rspec_junit_formatter (0.4.1)
79
+ rspec-core (>= 2, < 4, != 2.12.0)
80
+ rubocop (0.72.0)
81
+ jaro_winkler (~> 1.5.1)
82
+ parallel (~> 1.10)
83
+ parser (>= 2.6)
84
+ rainbow (>= 2.2.2, < 4.0)
85
+ ruby-progressbar (~> 1.7)
86
+ unicode-display_width (>= 1.4.0, < 1.7)
87
+ rubocop-rspec (1.33.0)
88
+ rubocop (>= 0.60.0)
89
+ ruby-progressbar (1.10.1)
90
+ safe_yaml (1.0.5)
91
+ thread_safe (0.3.6)
92
+ tzinfo (1.2.5)
93
+ thread_safe (~> 0.1)
94
+ unf (0.1.4)
95
+ unf_ext
96
+ unf_ext (0.0.7.6)
97
+ unicode-display_width (1.6.0)
98
+ vault (0.12.0)
99
+ aws-sigv4
100
+ vcr (3.0.0)
101
+ webmock (3.6.0)
102
+ addressable (>= 2.3.6)
103
+ crack (>= 0.3.2)
104
+ hashdiff (>= 0.4.0, < 2.0.0)
105
+
106
+ PLATFORMS
107
+ ruby
108
+
109
+ DEPENDENCIES
110
+ awesome_print
111
+ bundler
112
+ byebug
113
+ pry
114
+ rake (~> 10.0)
115
+ rspec (~> 3.0)
116
+ rspec-expectations
117
+ rspec-mocks
118
+ rspec_junit_formatter
119
+ rubocop
120
+ rubocop-rspec
121
+ vault_api!
122
+
123
+ BUNDLED WITH
124
+ 1.17.1
data/LICENSE.txt ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2019 Sachin Wagh
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
data/README.md ADDED
@@ -0,0 +1,226 @@
1
+ # VaultApi
2
+
3
+ A ruby wrapper for the Vault gem.
4
+
5
+ ## Installation
6
+ Add this line to your application's Gemfile:
7
+
8
+ ```
9
+ gem 'vault_api'
10
+ ```
11
+ And then execute:
12
+ ```
13
+ $ bundle
14
+ ```
15
+ Or install it yourself as:
16
+
17
+ ```
18
+ $ gem build vault_api.gemspec
19
+ $ gem install 'vault_api'
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ### Configuration
25
+
26
+ Before you can make calls to VaultApi you must configure the library with a valid api_token or user/password. You can request a token be generated by VaultApi.
27
+
28
+ There are two ways to configure the gem. You can pass a hash of configuration options when you create a client, or you can use a configure block.
29
+
30
+ I) Passing hash of configuration.
31
+
32
+ #### For admin user
33
+ ```ruby
34
+ client = VaultApi.client({
35
+ address: 'VAULT_SERVER_ADDRESS',
36
+ token: 'VAULT_TOKEN',
37
+ env: 'ENVIRONMENT'
38
+ })
39
+ ```
40
+ #### For normal user
41
+ ```ruby
42
+ client = VaultApi.client({
43
+ address: 'VAULT_SERVER_ADDRESS',
44
+ user: 'VAULT_USER_NAME',
45
+ password: 'VAULT_PASSWORD',
46
+ env: 'ENVIRONMENT'
47
+ })
48
+ ```
49
+
50
+ II) Using a configure block
51
+
52
+ #### For admin user
53
+ ```ruby
54
+ VaultApi.configure do |config|
55
+ config.address = 'VAULT_SERVER_ADDRESS'
56
+ config.token = 'VAULT_TOKEN'
57
+ config.env = 'ENVIRONMENT'
58
+ end
59
+ client = VaultApi.client
60
+ ```
61
+
62
+ #### For normal user
63
+ ```ruby
64
+ VaultApi.configure do |config|
65
+ config.address = 'VAULT_SERVER_ADDRESS'
66
+ config.user = 'VAULT_USER_NAME'
67
+ config.password = 'VAULT_PASSWORD'
68
+ config.env = 'ENVIRONMENT'
69
+ end
70
+ client = VaultApi.client
71
+ ```
72
+ ## Limitations in Configuration
73
+
74
+ To configure Vault as a root user, you must specify 'token' parameter in configuration and do not specify 'user' and 'password' parameters.
75
+
76
+ To configure Vault as a normal user, you must specify 'user' and 'password' parameters
77
+ in configuration not do not specify 'token' parameter.
78
+
79
+ If you specify both i.e. 'token' and 'user-password' configurations then 'user-password' would be prefered over 'token' configuration. Still vault-api may not behave as expected.
80
+
81
+ ##### Example calls
82
+
83
+ ##### 1. Secrets
84
+ ###### i) Add a secret file.
85
+
86
+ ```ruby
87
+ client.add_secret("path/to/secret/file/secret_file_name.yml")
88
+ ```
89
+
90
+ ###### ii) Upload secret files.
91
+
92
+ ```ruby
93
+ client.upload_secrets("path/to/secrets/folder")
94
+ ```
95
+
96
+ ###### iii) Get a secret file.
97
+
98
+ ```ruby
99
+ client.read_secret('secret_file_name')
100
+ ```
101
+
102
+ ###### iv) Get secrets.
103
+
104
+ ```ruby
105
+ client.secrets
106
+ ```
107
+
108
+ ###### v) Delete a secret.
109
+
110
+ ```ruby
111
+ client.delete_secret('secret_file_name')
112
+ ```
113
+
114
+ ##### 2. Policies
115
+ ###### i) Add a policy.
116
+
117
+ ```ruby
118
+ client.create_policy('user', 'policy_path', ['capability_1', 'capability_2'])
119
+ ```
120
+
121
+ ###### ii) Get a policy.
122
+
123
+ ```ruby
124
+ client.read_policy('user')
125
+ ```
126
+
127
+ ###### iii) Update a policy.
128
+
129
+ ```ruby
130
+ client.update_policy('user', 'policy_path', ['capability_3'])
131
+ ```
132
+
133
+ ###### iv) Delete a policy
134
+
135
+ ```ruby
136
+ client.delete_policy('user')
137
+ ```
138
+
139
+ ##### 3. Entries CRUD.
140
+ ###### i) Add an entry.
141
+
142
+ ```ruby
143
+ client.add_entry('secret_name', 'key', 'value')
144
+ ```
145
+
146
+ ###### ii) Get an entry.
147
+
148
+ ```ruby
149
+ client.read_entry('secret_name', 'key')
150
+ ```
151
+
152
+ ###### iii) Update an entry.
153
+
154
+ ```ruby
155
+ client.update_entry('secret_name', 'key', 'value')
156
+ ```
157
+
158
+ ###### iv) Delete an entry.
159
+
160
+ ```ruby
161
+ client.delete_entry('secret_name', 'key')
162
+ ```
163
+
164
+ ##### 4. Clone Entries.
165
+
166
+ ###### i) Clone an entry to single target user.
167
+
168
+ ```ruby
169
+ client.clone_entry('secret_name', 'key', 'target_username')
170
+ ```
171
+
172
+ ###### ii) Clone multiple entries to single target user.
173
+
174
+ ```ruby
175
+ client.clone_entry('secret_name', ['key1', 'key2'], 'target_username')
176
+ ```
177
+
178
+ ###### iii) Clone all entries to single target user.
179
+
180
+ ```ruby
181
+ client.clone_entry('secret_name', 'all', 'target_username')
182
+ ```
183
+
184
+ ###### iv) Clone an entry to multiple target users.
185
+
186
+ ```ruby
187
+ client.clone_entry('secret_name', 'key', ['target_username1', 'target_username2'])
188
+ ```
189
+
190
+ ###### v) Clone multiple entries to multiple target users.
191
+
192
+ ```ruby
193
+ client.clone_entry('secret_name', ['key1', 'key2'], ['target_username1', 'target_username2'])
194
+ ```
195
+
196
+ ###### vi) Clone all entries to multiple target users.
197
+
198
+ ```ruby
199
+ client.clone_entry('secret_name', 'all', ['target_username1', 'target_username2'])
200
+ ```
201
+
202
+ ###### vii) Clone an entry to all target users.
203
+
204
+ ```ruby
205
+ client.clone_entry('secret_name', 'key', 'all')
206
+ ```
207
+
208
+ ###### viii) Clone multiple entries to all target users.
209
+
210
+ ```ruby
211
+ client.clone_entry('secret_name', ['key1', 'key2'], 'all')
212
+ ```
213
+
214
+ ###### ix) Clone all entries to all target users.
215
+
216
+ ```ruby
217
+ client.clone_entry('secret_name', 'all', 'all')
218
+ ```
219
+
220
+ ## Contributing
221
+
222
+ 1. Fork it
223
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
224
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
225
+ 4. Push to the branch (`git push origin my-new-feature`)
226
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
4
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
5
+ require 'vault_api'
6
+ # This task will be upload all *.yml files from config folder to vault
7
+ desc ' upload all *.yml files from config folder to vault'
8
+ task :upload, [:config_folder_path] do |_t, args|
9
+ VaultApi::Config.upload(args.config_folder_path)
10
+ end
11
+ require 'bundler/gem_tasks'
12
+ require 'rspec/core/rake_task'
13
+
14
+ RSpec::Core::RakeTask.new(:spec)
15
+
16
+ task default: :spec
data/bin/vault_conf ADDED
@@ -0,0 +1,43 @@
1
+ # !/bin/bash
2
+
3
+ # Default Values
4
+ env=""
5
+ config_folder_path=""
6
+
7
+ # Show help
8
+ help(){
9
+ echo "(-a) action (EX- upload_files)"
10
+ echo "(-l) config_folder_path having *yml files"
11
+ echo "(-h) help "
12
+ }
13
+
14
+ while getopts a:l:h option;
15
+ do
16
+ case "$option" in
17
+ a)
18
+ action=${OPTARG};;
19
+ l)
20
+ config_folder_path=${optionARG};;
21
+ h)
22
+ helpflag="true"
23
+ help ;;
24
+ esac
25
+ done
26
+
27
+ if [ "$action" == 'upload_files' ]; then
28
+ if [ -z $action ]
29
+ then
30
+ echo " (-a) action (EX- upload_files)"
31
+ exit 1
32
+ fi
33
+
34
+ if [ -z $config_folder_path ]
35
+ then
36
+ echo " (-l) config_folder_path having *yml files"
37
+ exit 1
38
+ fi
39
+ # To upload all config file to vault
40
+ bundle exec rake upload[$config_folder_path]
41
+ elif [ ! helpflag ]; then
42
+ echo "Unknown paramter"
43
+ fi
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path('request', __dir__)
4
+ require File.expand_path('connection', __dir__)
5
+ require File.expand_path('configuration', __dir__)
6
+
7
+ module VaultApi
8
+ class API
9
+ include Request
10
+ include Connection
11
+
12
+ attr_accessor *Configuration::VALID_OPTIONS_KEYS
13
+
14
+ def initialize(options = {})
15
+ options = VaultApi.options.merge(options)
16
+ Configuration::VALID_OPTIONS_KEYS.each do |key|
17
+ send("#{key}=", options[key])
18
+ end
19
+ end
20
+
21
+ def config
22
+ conf = {}
23
+ Configuration::VALID_OPTIONS_KEYS.each do |key|
24
+ conf[key] = send key
25
+ end
26
+ conf
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ # VaultApi::Client::Entries
4
+ module VaultApi
5
+ class Client
6
+ module Entries
7
+ def entries(secret_name, user_name = nil)
8
+ read_secret(secret_name, user_name)
9
+ end
10
+
11
+ def add_entry(secret_name, key, value, user_name = nil)
12
+ process_entry(secret_name, key, value, user_name)
13
+ end
14
+
15
+ def read_entry(secret_name, key, user_name = nil)
16
+ path = config_path(secret_name, user_name)
17
+ config = VaultApi.read(path).data
18
+ config[key.to_sym]
19
+ end
20
+
21
+ def update_entry(secret_name, key, value, user_name = nil)
22
+ process_entry(secret_name, key, value, user_name)
23
+ end
24
+
25
+ def delete_entry(secret_name, key, user_name = nil)
26
+ config = VaultApi.read_secret(secret_name, user_name)
27
+ config = config.dup if config.frozen? # read
28
+ config.delete(key.to_sym)
29
+ path = config_path(secret_name)
30
+ VaultApi.write(path, config) # write
31
+ end
32
+
33
+ def clone_entry(secret_name, key, target)
34
+ if [secret_name, key, target].any?(&:blank?)
35
+ puts 'secret_name can\'t be blank'
36
+ elsif key.blank?
37
+ puts 'key can\'t be blank'
38
+ elsif target.blank?
39
+ puts 'target can\'t be blank'
40
+ else
41
+ if !target.is_a?(Array) && target.to_sym == :all
42
+ clone_entry_to_all_users(secret_name, key)
43
+ elsif target.is_a?(String) || target.is_a?(Symbol)
44
+ clone_entry_to_target_users(secret_name, key, [target])
45
+ elsif target.is_a?(Array)
46
+ clone_entry_to_target_users(secret_name, key, target)
47
+ else
48
+ 'Invalid Target'
49
+ end
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ def clone_entry_to_users(secret_name, key, users)
56
+ secret = VaultApi.read_secret(secret_name)
57
+ secret = secret.dup.symbolize_keys
58
+
59
+ if (key.is_a?(String) && key != 'all') || (key.is_a?(Symbol) && key != :all)
60
+ clone_single_entry_to_users(secret_name, key, secret, users)
61
+ elsif key.is_a?(Array) || key.to_sym == :all
62
+ clone_multiple_entries_to_users(secret_name, key, secret, users)
63
+ end
64
+ end
65
+
66
+ def clone_single_entry_to_users(secret_name, key, secret, users)
67
+ response = {}
68
+
69
+ value = secret[key.to_sym]
70
+ users.map do |user_name|
71
+ # puts "single: user_name: #{user_name}, key: #{key}, #{value}"
72
+ response[user_name] ||= {}
73
+ entry_response = VaultApi.add_entry(secret_name, key, value, user_name)
74
+ response[user_name][key.to_sym] = entry_response
75
+ end
76
+
77
+ # puts "response: #{response}"
78
+
79
+ response
80
+ end
81
+
82
+ def clone_multiple_entries_to_users(secret_name, key, secret, users)
83
+ response = {}
84
+ keys = if key.is_a?(Array)
85
+ key
86
+ else
87
+ (key.to_sym == :all ? secret.keys : [])
88
+ end
89
+
90
+ users.map do |user_name|
91
+ response[user_name] ||= {}
92
+
93
+ keys.each do |k|
94
+ v = secret[k.to_sym]
95
+ entry_response = VaultApi.add_entry(secret_name, k, v, user_name)
96
+ response[user_name][k.to_sym] = entry_response
97
+ end
98
+ end
99
+
100
+ response
101
+ end
102
+
103
+ def clone_entry_to_all_users(secret_name, key)
104
+ users = VaultApi.list(VaultApi.auth_users_path)
105
+ clone_entry_to_users(secret_name, key, users)
106
+ end
107
+
108
+ def clone_entry_to_target_users(secret_name, key, targets)
109
+ targets = targets.map(&:to_sym)
110
+ users = VaultApi.list(VaultApi.auth_users_path) # auth_users_path
111
+ users = users.map(&:to_sym)
112
+ valid_users = (users & targets) # extracts valid target users.
113
+ clone_entry_to_users(secret_name, key, valid_users)
114
+ end
115
+
116
+ def config_path(secret_name, user_name = nil)
117
+ "#{VaultApi.secret_base_path(user_name)}/#{secret_name}"
118
+ end
119
+
120
+ def process_entry(secret_name, key, value, user_name = nil)
121
+ config = VaultApi.read_secret(secret_name, user_name) # read
122
+ config = config.dup if config.frozen?
123
+ config[key.to_sym] = value # merge
124
+ path = config_path(secret_name, user_name)
125
+ VaultApi.write(path, config) # write
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module VaultApi
4
+ class Client
5
+ module Paths
6
+ def delete_path(vault_secret_path)
7
+ config_data = VaultApi.list(vault_secret_path.to_s)
8
+
9
+ if config_data.present?
10
+ config_data.to_a.each do |file_name|
11
+ VaultApi.delete("#{vault_secret_path}/#{file_name}")
12
+ end
13
+ end
14
+
15
+ VaultApi.delete(vault_secret_path.to_s)
16
+ end
17
+ end
18
+ end
19
+ end