chef-vault 3.3.0 → 4.1.11

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.
Files changed (71) hide show
  1. checksums.yaml +5 -5
  2. data/Gemfile +32 -6
  3. data/bin/chef-vault +5 -5
  4. data/chef-vault.gemspec +7 -26
  5. data/lib/chef/knife/mixin/helper.rb +29 -1
  6. data/lib/chef/knife/vault_admins.rb +5 -1
  7. data/lib/chef/knife/vault_base.rb +23 -13
  8. data/lib/chef/knife/vault_create.rb +26 -23
  9. data/lib/chef/knife/vault_delete.rb +4 -2
  10. data/lib/chef/knife/vault_download.rb +2 -2
  11. data/lib/chef/knife/vault_edit.rb +4 -4
  12. data/lib/chef/knife/vault_isvault.rb +4 -4
  13. data/lib/chef/knife/vault_itemtype.rb +4 -4
  14. data/lib/chef/knife/vault_list.rb +5 -5
  15. data/lib/chef/knife/vault_refresh.rb +7 -7
  16. data/lib/chef/knife/vault_remove.rb +19 -16
  17. data/lib/chef/knife/vault_rotate_all_keys.rb +5 -4
  18. data/lib/chef/knife/vault_rotate_keys.rb +3 -3
  19. data/lib/chef/knife/vault_show.rb +8 -10
  20. data/lib/chef/knife/vault_update.rb +38 -24
  21. data/lib/chef-vault/actor.rb +9 -7
  22. data/lib/chef-vault/chef_api.rb +4 -4
  23. data/lib/chef-vault/exceptions.rb +3 -0
  24. data/lib/chef-vault/item.rb +57 -21
  25. data/lib/chef-vault/item_keys.rb +35 -9
  26. data/lib/chef-vault/mixins.rb +2 -2
  27. data/lib/chef-vault/version.rb +1 -1
  28. data/lib/chef-vault.rb +8 -8
  29. metadata +8 -135
  30. data/.github/CODEOWNERS +0 -2
  31. data/.gitignore +0 -33
  32. data/.rspec +0 -2
  33. data/.rubocop.yml +0 -6
  34. data/.simplecov +0 -6
  35. data/.travis.yml +0 -19
  36. data/Changelog.md +0 -134
  37. data/DEMO.md +0 -60
  38. data/KNIFE_EXAMPLES.md +0 -256
  39. data/README.md +0 -333
  40. data/Rakefile +0 -50
  41. data/THEORY.md +0 -363
  42. data/UPGRADE.md +0 -55
  43. data/appveyor.yml +0 -32
  44. data/features/clean.feature +0 -23
  45. data/features/clean_on_refresh.feature +0 -27
  46. data/features/clean_unknown_clients.feature +0 -45
  47. data/features/detect_and_warn_v1_vault.feature +0 -14
  48. data/features/isvault.feature +0 -29
  49. data/features/itemtype.feature +0 -24
  50. data/features/step_definitions/chef-databag.rb +0 -9
  51. data/features/step_definitions/chef-repo.rb +0 -72
  52. data/features/step_definitions/chef-vault.rb +0 -151
  53. data/features/step_definitions/chef_databagitem.rb +0 -9
  54. data/features/support/env.rb +0 -14
  55. data/features/vault_create.feature +0 -63
  56. data/features/vault_list.feature +0 -31
  57. data/features/vault_show.feature +0 -45
  58. data/features/vault_show_vaultname.feature +0 -21
  59. data/features/vault_update.feature +0 -18
  60. data/features/verify_id_matches.feature +0 -10
  61. data/features/wrong_private_key.feature +0 -13
  62. data/hooks/pre-commit +0 -43
  63. data/spec/chef-vault/actor_spec.rb +0 -247
  64. data/spec/chef-vault/certificate_spec.rb +0 -37
  65. data/spec/chef-vault/chef_api_spec.rb +0 -39
  66. data/spec/chef-vault/item_keys_spec.rb +0 -263
  67. data/spec/chef-vault/item_spec.rb +0 -360
  68. data/spec/chef-vault/user_spec.rb +0 -36
  69. data/spec/chef-vault_spec.rb +0 -65
  70. data/spec/spec_helper.rb +0 -91
  71. data/tasks/github_changelog_generator.rb +0 -30
@@ -13,7 +13,7 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
- require "chef/knife/vault_base"
16
+ require_relative "vault_base"
17
17
 
18
18
  class Chef
19
19
  class Knife
@@ -23,8 +23,8 @@ class Chef
23
23
  banner "knife vault rotate keys VAULT ITEM (options)"
24
24
 
25
25
  option :clean_unknown_clients,
26
- :long => "--clean-unknown-clients",
27
- :description => "Remove unknown clients during key rotation"
26
+ long: "--clean-unknown-clients",
27
+ description: "Remove unknown clients during key rotation"
28
28
 
29
29
  def run
30
30
  vault = @name_args[0]
@@ -13,7 +13,7 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
- require "chef/knife/vault_base"
16
+ require_relative "vault_base"
17
17
 
18
18
  class Chef
19
19
  class Knife
@@ -23,14 +23,14 @@ class Chef
23
23
  banner "knife vault show VAULT [ITEM] [VALUES] (options)"
24
24
 
25
25
  option :mode,
26
- :short => "-M MODE",
27
- :long => "--mode MODE",
28
- :description => "Chef mode to run in default - solo"
26
+ short: "-M MODE",
27
+ long: "--mode MODE",
28
+ description: "Chef mode to run in default - solo"
29
29
 
30
30
  option :print,
31
- :short => "-p TYPE",
32
- :long => "--print TYPE",
33
- :description => "Print extra vault data, can be search, admins, clients or all"
31
+ short: "-p TYPE",
32
+ long: "--print TYPE",
33
+ description: "Print extra vault data, can be search, admins, clients or all"
34
34
 
35
35
  def run
36
36
  vault = @name_args[0]
@@ -90,9 +90,7 @@ class Chef
90
90
  def print_keys(vault)
91
91
  if bag_is_vault?(vault)
92
92
  bag = Chef::DataBag.load(vault)
93
- split_vault_keys(bag)[1].each do |item|
94
- output item
95
- end
93
+ output split_vault_keys(bag)[1]
96
94
  else
97
95
  output "data bag #{vault} is not a chef-vault"
98
96
  end
@@ -13,46 +13,54 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
- require "chef/knife/vault_base"
17
- require "chef/knife/vault_admins"
18
- require "chef/knife/vault_clients"
16
+ require_relative "vault_base"
19
17
 
20
18
  class Chef
21
19
  class Knife
22
20
  class VaultUpdate < Knife
23
21
  include Chef::Knife::VaultBase
24
- include Chef::Knife::VaultAdmins
25
- include Chef::Knife::VaultClients
26
22
 
27
23
  banner "knife vault update VAULT ITEM VALUES (options)"
28
24
 
29
25
  option :search,
30
- :short => "-S SEARCH",
31
- :long => "--search SEARCH",
32
- :description => "Chef SOLR search for clients"
26
+ short: "-S SEARCH",
27
+ long: "--search SEARCH",
28
+ description: "Chef SOLR search for clients"
33
29
 
34
30
  option :clients,
35
- :short => "-C CLIENTS",
36
- :long => "--clients CLIENTS",
37
- :description => "Chef clients to be added as clients"
31
+ short: "-C CLIENTS",
32
+ long: "--clients CLIENTS",
33
+ description: "Chef clients to be added as clients"
38
34
 
39
35
  option :admins,
40
- :short => "-A ADMINS",
41
- :long => "--admins ADMINS",
42
- :description => "Chef users to be added as admins"
36
+ short: "-A ADMINS",
37
+ long: "--admins ADMINS",
38
+ description: "Chef users to be added as admins"
43
39
 
44
40
  option :json,
45
- :short => "-J FILE",
46
- :long => "--json FILE",
47
- :description => "File containing JSON data to encrypt"
41
+ short: "-J FILE",
42
+ long: "--json FILE",
43
+ description: "File containing JSON data to encrypt"
48
44
 
49
45
  option :file,
50
- :long => "--file FILE",
51
- :description => "File to be added to vault item as file-content"
46
+ long: "--file FILE",
47
+ description: "File to be added to vault item as file-content"
52
48
 
53
49
  option :clean,
54
- :long => "--clean",
55
- :description => "Clean clients before performing search"
50
+ long: "--clean",
51
+ description: "Clean clients before performing search"
52
+
53
+ option :keys_mode,
54
+ short: "-K KEYS_MODE",
55
+ long: "--keys-mode KEYS_MODE",
56
+ description: "Mode in which to save vault keys"
57
+
58
+ deps do
59
+ require_relative "vault_admins"
60
+ require_relative "vault_clients"
61
+ include Chef::Knife::VaultAdmins
62
+ include Chef::Knife::VaultClients
63
+ end
56
64
 
57
65
  def run
58
66
  vault = @name_args[0]
@@ -62,16 +70,17 @@ class Chef
62
70
  json_file = config[:json]
63
71
  file = config[:file]
64
72
  clean = config[:clean]
73
+ keys_mode = config[:keys_mode]
65
74
 
66
75
  set_mode(config[:vault_mode])
67
76
 
68
- if vault && item && ((values || json_file || file) || (search || clients || admins))
77
+ if vault && item && ((values || json_file || file) || (search || clients || admins) || (keys_mode))
69
78
  begin
70
79
  vault_item = ChefVault::Item.load(vault, item)
71
80
 
72
81
  # Keys management first
73
82
  if clean
74
- vault_clients = vault_item.get_clients.clone().sort()
83
+ vault_clients = vault_item.get_clients.clone.sort
75
84
  vault_clients.each do |client|
76
85
  ui.info "Deleting #{client}"
77
86
  vault_item.delete_client(client)
@@ -91,7 +100,7 @@ class Chef
91
100
 
92
101
  if file
93
102
  vault_item["file-name"] = File.basename(file)
94
- vault_item["file-content"] = File.open(file) { |f| f.read() }
103
+ vault_item["file-content"] = File.open(file, &:read)
95
104
  end
96
105
 
97
106
  vault_item.save
@@ -105,6 +114,11 @@ class Chef
105
114
  "#{vault}/#{item} does not exist, "\
106
115
  "use 'knife vault create' to create."
107
116
  end
117
+
118
+ if keys_mode
119
+ vault_item.mode(keys_mode)
120
+ vault_item.save_keys
121
+ end
108
122
  else
109
123
  show_usage
110
124
  end
@@ -14,7 +14,7 @@
14
14
  # See the License for the specific language governing permissions and
15
15
  # limitations under the License.
16
16
 
17
- require "json"
17
+ require "json" unless defined?(JSON)
18
18
 
19
19
  class ChefVault
20
20
  class Actor
@@ -27,6 +27,7 @@ class ChefVault
27
27
  if actor_type != "clients" && actor_type != "admins"
28
28
  raise "You must pass either 'clients' or 'admins' as the first argument to ChefVault::Actor.new."
29
29
  end
30
+
30
31
  @type = actor_type
31
32
  @name = actor_name
32
33
  end
@@ -38,7 +39,7 @@ class ChefVault
38
39
  def get_admin_key
39
40
  # chef vault currently only supports using the default key
40
41
  get_key("users")
41
- rescue Net::HTTPServerException => http_error
42
+ rescue Net::HTTPClientException => http_error
42
43
  # if we failed to find an admin key, attempt to load a client key by the same name
43
44
  case http_error.response.code
44
45
  when "403"
@@ -48,11 +49,11 @@ class ChefVault
48
49
  begin
49
50
  ChefVault::Log.warn "The default key for #{name} not found in users, trying client keys."
50
51
  get_key("clients")
51
- rescue Net::HTTPServerException => http_error
52
+ rescue Net::HTTPClientException => http_error
52
53
  case http_error.response.code
53
54
  when "404"
54
55
  raise ChefVault::Exceptions::AdminNotFound,
55
- "FATAL: Could not find default key for #{name} in users or clients!"
56
+ "FATAL: Could not find default key for #{name} in users or clients!"
56
57
  when "403"
57
58
  print_forbidden_error
58
59
  raise http_error
@@ -67,13 +68,13 @@ class ChefVault
67
68
 
68
69
  def get_client_key
69
70
  get_key("clients")
70
- rescue Net::HTTPServerException => http_error
71
+ rescue Net::HTTPClientException => http_error
71
72
  if http_error.response.code.eql?("403")
72
73
  print_forbidden_error
73
74
  raise http_error
74
75
  elsif http_error.response.code.eql?("404")
75
76
  raise ChefVault::Exceptions::ClientNotFound,
76
- "#{name} is not a valid chef client and/or node"
77
+ "#{name} is not a valid chef client and/or node"
77
78
  else
78
79
  raise http_error
79
80
  end
@@ -113,8 +114,9 @@ class ChefVault
113
114
  def get_key(request_actor_type)
114
115
  api.org_scoped_rest_v1.get("#{request_actor_type}/#{name}/keys/default").fetch("public_key")
115
116
  # If the keys endpoint doesn't exist, try getting it directly from the V0 chef object.
116
- rescue Net::HTTPServerException => http_error
117
+ rescue Net::HTTPClientException => http_error
117
118
  raise http_error unless http_error.response.code.eql?("404")
119
+
118
120
  if request_actor_type.eql?("clients")
119
121
  chef_api_client.load(name).public_key
120
122
  else
@@ -20,19 +20,19 @@ class ChefVault
20
20
  class ChefApi
21
21
 
22
22
  def rest_v0
23
- @rest_v0 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_root], { :api_version => "0" })
23
+ @rest_v0 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_root], { api_version: "0" })
24
24
  end
25
25
 
26
26
  def rest_v1
27
- @rest_v1 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_root], { :api_version => "1" })
27
+ @rest_v1 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_root], { api_version: "1" })
28
28
  end
29
29
 
30
30
  def org_scoped_rest_v0
31
- @org_scoped_rest_v0 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], { :api_version => "0" })
31
+ @org_scoped_rest_v0 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], { api_version: "0" })
32
32
  end
33
33
 
34
34
  def org_scoped_rest_v1
35
- @org_scoped_rest_v1 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], { :api_version => "1" })
35
+ @org_scoped_rest_v1 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], { api_version: "1" })
36
36
  end
37
37
 
38
38
  end
@@ -51,5 +51,8 @@ class ChefVault
51
51
 
52
52
  class V1Format < Exceptions
53
53
  end
54
+
55
+ class InvalidValue < Exceptions
56
+ end
54
57
  end
55
58
  end
@@ -15,8 +15,8 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "securerandom"
19
- require "chef-vault/mixins"
18
+ require "securerandom" unless defined?(SecureRandom)
19
+ require_relative "mixins"
20
20
 
21
21
  class ChefVault
22
22
  class Item < Chef::DataBagItem
@@ -40,6 +40,11 @@ class ChefVault
40
40
  # decrypt secrets. Defaults to the value of Chef::Config[:client_key]
41
41
  attr_accessor :client_key_path
42
42
 
43
+ # @!attribute [rw] client_key_contents
44
+ # @return [String] the contents of the private key that is used to
45
+ # decrypt secrets. Defaults to the value of Chef::Config[:client_key_contents]
46
+ attr_accessor :client_key_contents
47
+
43
48
  # returns the raw keys of the underlying Chef::DataBagItem. chef-vault v2
44
49
  # defined #keys as a public accessor that returns the ChefVault::ItemKeys
45
50
  # object for the vault. Ideally, #keys would provide Hash-like behaviour
@@ -58,6 +63,8 @@ class ChefVault
58
63
  # as. Defaults to the :node_name value of Chef::Config
59
64
  # @option opts [String] :client_key_path the name of the node to decrypt
60
65
  # secrets as. Defaults to the :client_key value of Chef::Config
66
+ # @option opts [String] :client_key_contents the private key to decrypt
67
+ # secrets as. Defaults to the :client_key_contents value of Chef::Config
61
68
  def initialize(vault, name, opts = {})
62
69
  super() # Don't pass parameters
63
70
  @data_bag = vault
@@ -66,11 +73,13 @@ class ChefVault
66
73
  @secret = generate_secret
67
74
  @encrypted = false
68
75
  opts = {
69
- :node_name => Chef::Config[:node_name],
70
- :client_key_path => Chef::Config[:client_key],
76
+ node_name: Chef::Config[:node_name],
77
+ client_key_path: Chef::Config[:client_key],
78
+ client_key_contents: Chef::Config[:client_key_contents],
71
79
  }.merge(opts)
72
80
  @node_name = opts[:node_name]
73
81
  @client_key_path = opts[:client_key_path]
82
+ @client_key_contents = opts[:client_key_contents]
74
83
  @current_query = search
75
84
  end
76
85
 
@@ -89,12 +98,14 @@ class ChefVault
89
98
  handle_client_action(search_or_client, action)
90
99
  else
91
100
  search_or_client.each do |name|
101
+ # rubocop:disable all
92
102
  begin
93
103
  client = load_actor(name, "clients")
94
104
  handle_client_action(client, action)
95
105
  rescue ChefVault::Exceptions::ClientNotFound
96
- ChefVault::Log.warn "node '#{name}' has no private key; skipping"
106
+ ChefVault::Log.warn "node '#{name}' has no 'default' public key; skipping"
97
107
  end
108
+ # rubocop:enable all
98
109
  end
99
110
  end
100
111
  end
@@ -131,6 +142,10 @@ class ChefVault
131
142
  end
132
143
  end
133
144
 
145
+ def mode(mode)
146
+ keys.mode(mode) if mode
147
+ end
148
+
134
149
  def admins(admin_string, action = :add)
135
150
  admin_string.split(",").each do |admin|
136
151
  admin.strip!
@@ -142,7 +157,7 @@ class ChefVault
142
157
  keys.delete(admin_key)
143
158
  else
144
159
  raise ChefVault::Exceptions::KeysActionNotValid,
145
- "#{action} is not a valid action"
160
+ "#{action} is not a valid action"
146
161
  end
147
162
  end
148
163
  end
@@ -156,8 +171,12 @@ class ChefVault
156
171
  end
157
172
 
158
173
  def secret
159
- if @keys.include?(@node_name)
160
- private_key = OpenSSL::PKey::RSA.new(File.open(@client_key_path).read())
174
+ if @keys.include?(@node_name) && !@keys[@node_name].nil?
175
+ unless @client_key_contents.nil?
176
+ private_key = OpenSSL::PKey::RSA.new(@client_key_contents)
177
+ else
178
+ private_key = OpenSSL::PKey::RSA.new(File.open(@client_key_path).read)
179
+ end
161
180
  begin
162
181
  private_key.private_decrypt(Base64.decode64(@keys[@node_name]))
163
182
  rescue OpenSSL::PKey::RSAError
@@ -225,7 +244,7 @@ class ChefVault
225
244
  else
226
245
  begin
227
246
  Chef::DataBag.load(data_bag)
228
- rescue Net::HTTPServerException => http_error
247
+ rescue Net::HTTPClientException => http_error
229
248
  if http_error.response.code == "404"
230
249
  chef_data_bag = Chef::DataBag.new
231
250
  chef_data_bag.name data_bag
@@ -268,7 +287,7 @@ class ChefVault
268
287
 
269
288
  if Chef::Config[:solo_legacy_mode]
270
289
  data_bag_path = File.join(Chef::Config[:data_bag_path],
271
- data_bag)
290
+ data_bag)
272
291
  data_bag_item_path = File.join(data_bag_path, @raw_data["id"])
273
292
 
274
293
  FileUtils.rm("#{data_bag_item_path}.json")
@@ -289,7 +308,7 @@ class ChefVault
289
308
  begin
290
309
  item.raw_data =
291
310
  Chef::EncryptedDataBagItem.load(vault, name, item.secret).to_hash
292
- rescue Net::HTTPServerException => http_error
311
+ rescue Net::HTTPClientException => http_error
293
312
  if http_error.response.code == "404"
294
313
  raise ChefVault::Exceptions::ItemNotFound,
295
314
  "#{vault}/#{name} could not be found"
@@ -300,10 +319,17 @@ class ChefVault
300
319
  raise ChefVault::Exceptions::ItemNotFound,
301
320
  "#{vault}/#{name} could not be found"
302
321
  end
303
-
322
+ format_output(opts[:values], item) if opts[:values]
304
323
  item
305
324
  end
306
325
 
326
+ def self.format_output(values, item)
327
+ values.split(",").each do |value|
328
+ value.strip!
329
+ $stdout.puts("#{value}: #{item[value]}")
330
+ end
331
+ end
332
+
307
333
  def delete_client(client_name)
308
334
  client_key = load_actor(client_name, "clients")
309
335
  keys.delete(client_key)
@@ -336,7 +362,16 @@ class ChefVault
336
362
  def self.data_bag_item_type(vault, name)
337
363
  # adapted from https://github.com/opscode-cookbooks/chef-vault/blob/v1.3.0/libraries/chef_vault_item.rb
338
364
  # and https://github.com/sensu/sensu-chef/blob/2.9.0/libraries/sensu_helpers.rb
339
- dbi = Chef::DataBagItem.load(vault, name)
365
+ begin
366
+ dbi = Chef::DataBagItem.load(vault, name)
367
+ rescue Net::HTTPClientException => http_error
368
+ if http_error.response.code == "404"
369
+ raise ChefVault::Exceptions::ItemNotFound,
370
+ "#{vault}/#{name} not found"
371
+ else
372
+ raise http_error
373
+ end
374
+ end
340
375
  encrypted = dbi.detect do |_, v|
341
376
  v.is_a?(Hash) && v.key?("encrypted_data")
342
377
  end
@@ -358,12 +393,12 @@ class ChefVault
358
393
  # no longer be found
359
394
  # @return [void]
360
395
  def refresh(clean_unknown_clients = false)
361
- unless search
396
+ if search.empty?
362
397
  raise ChefVault::Exceptions::SearchNotFound,
363
- "#{vault}/#{item} does not have a stored search_query, "\
364
- "probably because it was created with an older version "\
365
- "of chef-vault. Use 'knife vault update' to update the "\
366
- "databag with the search query."
398
+ "#{@data_bag}/#{@raw_data["id"]} does not have a stored "\
399
+ "search_query, probably because it was created with an "\
400
+ "older version of chef-vault. Use 'knife vault update' "\
401
+ "to update the databag with the search query."
367
402
  end
368
403
 
369
404
  # a bit of a misnomer; this doesn't remove unknown
@@ -432,13 +467,14 @@ class ChefVault
432
467
  def client_exists?(clientname)
433
468
  Chef::ApiClient.load(clientname)
434
469
  true
435
- rescue Net::HTTPServerException => http_error
470
+ rescue Net::HTTPClientException => http_error
436
471
  return false if http_error.response.code == "404"
472
+
437
473
  raise http_error
438
474
  end
439
475
 
440
476
  # adds or deletes an API client from the vault item keys
441
- # @param client [Chef::ApiClient] the API client to operate on
477
+ # @param api_client [Chef::ApiClient] the API client to operate on
442
478
  # @param action [Symbol] :add or :delete
443
479
  # @return [void]
444
480
  def handle_client_action(api_client, action)
@@ -460,7 +496,7 @@ class ChefVault
460
496
  end
461
497
 
462
498
  # removes a client to the vault item keys
463
- # @param client_or_node [String] the name of the API client or node to remove
499
+ # @param name [String] the name of the API client or node to remove
464
500
  # @return [void]
465
501
  def delete_client_or_node(name)
466
502
  client = load_actor(name, "clients")
@@ -14,7 +14,7 @@
14
14
  # See the License for the specific language governing permissions and
15
15
  # limitations under the License.
16
16
 
17
- require "chef-vault/mixins"
17
+ require_relative "mixins"
18
18
 
19
19
  class ChefVault
20
20
  class ItemKeys < Chef::DataBagItem
@@ -39,9 +39,11 @@ class ChefVault
39
39
  def [](key)
40
40
  # return options immediately
41
41
  return @raw_data[key] if %w{id admins clients search_query mode}.include?(key)
42
+
42
43
  # check if the key is in the write-back cache
43
44
  ckey = @cache[key]
44
45
  return ckey unless ckey.nil?
46
+
45
47
  # check if the key is saved in sparse mode
46
48
  skey = sparse_key(sparse_id(key)) if sparse?
47
49
  if skey
@@ -58,6 +60,7 @@ class ChefVault
58
60
  return (ckey ? true : false) unless ckey.nil?
59
61
  # check if the key is saved in sparse mode
60
62
  return true if sparse? && sparse_key(sparse_id(key))
63
+
61
64
  # fallback to non-sparse mode if sparse key is not found
62
65
  @raw_data.keys.include?(key)
63
66
  end
@@ -66,10 +69,14 @@ class ChefVault
66
69
  type = chef_key.type
67
70
  unless @raw_data.key?(type)
68
71
  raise ChefVault::Exceptions::V1Format,
69
- "cannot manage a v1 vault. See UPGRADE.md for help"
72
+ "cannot manage a v1 vault. See UPGRADE.md for help"
70
73
  end
71
74
  @cache[chef_key.name] = skip_reencryption ? self[chef_key.name] : nil
72
- @cache[chef_key.name] ||= ChefVault::ItemKeys.encode_key(chef_key.key, data_bag_shared_secret)
75
+ begin
76
+ @cache[chef_key.name] ||= ChefVault::ItemKeys.encode_key(chef_key.key, data_bag_shared_secret)
77
+ rescue OpenSSL::PKey::RSAError
78
+ raise OpenSSL::PKey::RSAError, "While adding #{chef_key.type} an invalid or old (pre chef-server 12) format public key was found for #{chef_key.name}"
79
+ end
73
80
  @raw_data[type] << chef_key.name unless @raw_data[type].include?(chef_key.name)
74
81
  @raw_data[type]
75
82
  end
@@ -115,7 +122,7 @@ class ChefVault
115
122
  unless Chef::Config[:solo_legacy_mode]
116
123
  begin
117
124
  Chef::DataBag.load(data_bag)
118
- rescue Net::HTTPServerException => http_error
125
+ rescue Net::HTTPClientException => http_error
119
126
  if http_error.response.code == "404"
120
127
  chef_data_bag = Chef::DataBag.new
121
128
  chef_data_bag.name data_bag
@@ -135,8 +142,8 @@ class ChefVault
135
142
  begin
136
143
  Chef::DataBagItem.from_hash("data_bag" => data_bag,
137
144
  "id" => sparse_id(key))
138
- .destroy(data_bag, sparse_id(key))
139
- rescue Net::HTTPServerException => http_error
145
+ .destroy(data_bag, sparse_id(key))
146
+ rescue Net::HTTPClientException => http_error
140
147
  raise http_error unless http_error.response.code == "404"
141
148
  end
142
149
  end
@@ -161,6 +168,25 @@ class ChefVault
161
168
  end
162
169
  end
163
170
  end
171
+
172
+ if @raw_data["mode"] == "sparse"
173
+ @raw_data.each do |key, val|
174
+ next if %w{ id clients admins search_query mode }.include?(key)
175
+
176
+ skey = Chef::DataBagItem.from_hash(
177
+ "data_bag" => data_bag,
178
+ "id" => sparse_id(key),
179
+ key => val
180
+ )
181
+ @raw_data.delete(key)
182
+ if Chef::Config[:solo_legacy_mode]
183
+ save_solo(skey.id, skey.raw_data)
184
+ else
185
+ skey.save
186
+ end
187
+ end
188
+ end
189
+
164
190
  # save raw data
165
191
  if Chef::Config[:solo_legacy_mode]
166
192
  save_solo(item_id)
@@ -187,7 +213,7 @@ class ChefVault
187
213
  items = Chef::DataBag.load(data_bag).keys.select { |item| item =~ rgx }
188
214
  items.each do |id|
189
215
  Chef::DataBagItem.from_hash("data_bag" => data_bag, "id" => id)
190
- .destroy(data_bag, id)
216
+ .destroy(data_bag, id)
191
217
  end
192
218
  # destroy this metadata
193
219
  super(data_bag, id)
@@ -208,7 +234,7 @@ class ChefVault
208
234
  def self.load(vault, name)
209
235
  begin
210
236
  data_bag_item = Chef::DataBagItem.load(vault, name)
211
- rescue Net::HTTPServerException => http_error
237
+ rescue Net::HTTPClientException => http_error
212
238
  if http_error.response.code == "404"
213
239
  raise ChefVault::Exceptions::KeysNotFound,
214
240
  "#{vault}/#{name} could not be found"
@@ -239,7 +265,7 @@ class ChefVault
239
265
  else
240
266
  begin
241
267
  Chef::DataBagItem.load(@data_bag, sid)
242
- rescue Net::HTTPServerException => http_error
268
+ rescue Net::HTTPClientException => http_error
243
269
  nil if http_error.response.code == "404"
244
270
  end
245
271
  end
@@ -6,7 +6,7 @@ class ChefVault
6
6
  # paths and use that by preference
7
7
  # 1. Otherwise, just use the first location in the array
8
8
  def find_solo_path(item_id)
9
- if Chef::Config[:data_bag_path].kind_of?(Array)
9
+ if Chef::Config[:data_bag_path].is_a?(Array)
10
10
  path = Chef::Config[:data_bag_path].find do |dir|
11
11
  File.exist?(File.join(dir, data_bag, "#{item_id}.json"))
12
12
  end
@@ -15,7 +15,7 @@ class ChefVault
15
15
  data_bag_path = File.join(path, data_bag)
16
16
  else
17
17
  data_bag_path = File.join(Chef::Config[:data_bag_path],
18
- data_bag)
18
+ data_bag)
19
19
  end
20
20
  data_bag_item_path = File.join(data_bag_path, item_id) + ".json"
21
21
 
@@ -15,6 +15,6 @@
15
15
  # limitations under the License.
16
16
 
17
17
  class ChefVault
18
- VERSION = "3.3.0"
18
+ VERSION = "4.1.11"
19
19
  MAJOR, MINOR, TINY = VERSION.split(".")
20
20
  end
data/lib/chef-vault.rb CHANGED
@@ -23,14 +23,14 @@ require "chef/api_client"
23
23
  require "chef/data_bag_item"
24
24
  require "chef/encrypted_data_bag_item"
25
25
  require "chef/user"
26
- require "chef-vault/version"
27
- require "chef-vault/exceptions"
28
- require "chef-vault/item"
29
- require "chef-vault/item_keys"
30
- require "chef-vault/user"
31
- require "chef-vault/certificate"
32
- require "chef-vault/chef_api"
33
- require "chef-vault/actor"
26
+ require_relative "chef-vault/version"
27
+ require_relative "chef-vault/exceptions"
28
+ require_relative "chef-vault/item"
29
+ require_relative "chef-vault/item_keys"
30
+ require_relative "chef-vault/user"
31
+ require_relative "chef-vault/certificate"
32
+ require_relative "chef-vault/chef_api"
33
+ require_relative "chef-vault/actor"
34
34
 
35
35
  require "mixlib/log"
36
36