chef-vault 2.6.1 → 2.7.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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +6 -1
  3. data/.travis.yml +5 -6
  4. data/CONTRIBUTING.md +2 -2
  5. data/Gemfile +3 -1
  6. data/README.md +3 -3
  7. data/Rakefile +16 -20
  8. data/THEORY.md +1 -1
  9. data/UPGRADE.md +55 -0
  10. data/bin/chef-vault +8 -8
  11. data/chef-vault.gemspec +21 -21
  12. data/features/detect_and_warn_v1_vault.feature +15 -0
  13. data/features/step_definitions/chef-databag.rb +1 -1
  14. data/features/step_definitions/chef-repo.rb +7 -7
  15. data/features/step_definitions/chef-vault.rb +30 -22
  16. data/features/step_definitions/chef_databagitem.rb +2 -2
  17. data/features/support/env.rb +3 -3
  18. data/lib/chef-vault.rb +15 -15
  19. data/lib/chef-vault/chef_patch/api_client.rb +5 -5
  20. data/lib/chef-vault/chef_patch/user.rb +5 -5
  21. data/lib/chef-vault/exceptions.rb +3 -0
  22. data/lib/chef-vault/item.rb +13 -19
  23. data/lib/chef-vault/item_keys.rb +13 -13
  24. data/lib/chef-vault/mixins.rb +36 -0
  25. data/lib/chef-vault/version.rb +3 -2
  26. data/lib/chef/knife/decrypt.rb +2 -2
  27. data/lib/chef/knife/encrypt_create.rb +13 -13
  28. data/lib/chef/knife/encrypt_delete.rb +2 -2
  29. data/lib/chef/knife/encrypt_remove.rb +8 -8
  30. data/lib/chef/knife/encrypt_rotate_keys.rb +2 -2
  31. data/lib/chef/knife/encrypt_update.rb +13 -13
  32. data/lib/chef/knife/mixin/compat.rb +2 -2
  33. data/lib/chef/knife/vault_admins.rb +3 -3
  34. data/lib/chef/knife/vault_base.rb +9 -9
  35. data/lib/chef/knife/vault_create.rb +13 -13
  36. data/lib/chef/knife/vault_decrypt.rb +2 -2
  37. data/lib/chef/knife/vault_delete.rb +1 -1
  38. data/lib/chef/knife/vault_download.rb +2 -2
  39. data/lib/chef/knife/vault_edit.rb +6 -6
  40. data/lib/chef/knife/vault_isvault.rb +4 -4
  41. data/lib/chef/knife/vault_itemtype.rb +4 -4
  42. data/lib/chef/knife/vault_list.rb +4 -4
  43. data/lib/chef/knife/vault_refresh.rb +3 -3
  44. data/lib/chef/knife/vault_remove.rb +9 -9
  45. data/lib/chef/knife/vault_rotate_all_keys.rb +4 -4
  46. data/lib/chef/knife/vault_rotate_keys.rb +3 -3
  47. data/lib/chef/knife/vault_show.rb +12 -12
  48. data/lib/chef/knife/vault_update.rb +15 -15
  49. data/spec/chef-vault/certificate_spec.rb +7 -7
  50. data/spec/chef-vault/item_keys_spec.rb +53 -6
  51. data/spec/chef-vault/item_spec.rb +110 -110
  52. data/spec/chef-vault/user_spec.rb +6 -6
  53. data/spec/chef-vault_spec.rb +10 -10
  54. data/spec/spec_helper.rb +3 -3
  55. metadata +7 -6
  56. data/.rubocop_todo.yml +0 -101
@@ -1,9 +1,9 @@
1
1
  Given(/^I create a data bag item '(.+)\/(.+)' containing the JSON '(.+)'$/) do |databag, _, json|
2
- write_file 'item.json', json
2
+ write_file "item.json", json
3
3
  run_simple "knife data bag from file #{databag} item.json -z -c knife.rb", false
4
4
  end
5
5
 
6
6
  Given(/^I create an encrypted data bag item '(.+)\/(.+)' containing the JSON '(.+)' with the secret '(.+)'$/) do |databag, _, json, secret|
7
- write_file 'item.json', json
7
+ write_file "item.json", json
8
8
  run_simple "knife data bag from file #{databag} item.json -s #{secret} -z -c knife.rb", false
9
9
  end
@@ -1,8 +1,8 @@
1
- if ENV['COVERAGE']
2
- require 'simplecov'
1
+ if ENV["COVERAGE"]
2
+ require "simplecov"
3
3
  end
4
4
 
5
- require 'aruba/cucumber'
5
+ require "aruba/cucumber"
6
6
 
7
7
  # Travis runs tests in a limited environment which takes a long time to invoke
8
8
  # the knife command. Up the timeout when we're in a travis build based on the
@@ -16,21 +16,21 @@
16
16
  # limitations under the License.
17
17
  #
18
18
 
19
- require 'chef/search/query'
20
- require 'chef/version'
21
- require 'chef/config'
22
- require 'chef/api_client'
23
- require 'chef/data_bag_item'
24
- require 'chef/encrypted_data_bag_item'
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_patch/api_client'
33
- require 'chef-vault/chef_patch/user'
19
+ require "chef/search/query"
20
+ require "chef/version"
21
+ require "chef/config"
22
+ require "chef/api_client"
23
+ require "chef/data_bag_item"
24
+ require "chef/encrypted_data_bag_item"
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_patch/api_client"
33
+ require "chef-vault/chef_patch/user"
34
34
 
35
35
  class ChefVault
36
36
  attr_accessor :vault
@@ -25,15 +25,15 @@ class ChefVault
25
25
  response
26
26
  else
27
27
  client = Chef::ApiClient.new
28
- client.name(response['clientname'])
28
+ client.name(response["clientname"] || response["name"])
29
29
 
30
- if response['certificate']
31
- der = OpenSSL::X509::Certificate.new response['certificate']
30
+ if response["certificate"]
31
+ der = OpenSSL::X509::Certificate.new response["certificate"]
32
32
  client.public_key der.public_key.to_s
33
33
  end
34
34
 
35
- if response['public_key']
36
- der = OpenSSL::PKey::RSA.new response['public_key']
35
+ if response["public_key"]
36
+ der = OpenSSL::PKey::RSA.new response["public_key"]
37
37
  client.public_key der.public_key.to_s
38
38
  end
39
39
 
@@ -21,11 +21,11 @@ class ChefVault
21
21
  # set correctly for Chef 10 server
22
22
  def superclass.from_hash(user_hash)
23
23
  user = Chef::User.new
24
- user.name user_hash['username'] ? user_hash['username'] : user_hash['name']
25
- user.private_key user_hash['private_key'] if user_hash.key?('private_key')
26
- user.password user_hash['password'] if user_hash.key?('password')
27
- user.public_key user_hash['public_key']
28
- user.admin user_hash['admin']
24
+ user.name user_hash["username"] ? user_hash["username"] : user_hash["name"]
25
+ user.private_key user_hash["private_key"] if user_hash.key?("private_key")
26
+ user.password user_hash["password"] if user_hash.key?("password")
27
+ user.public_key user_hash["public_key"]
28
+ user.admin user_hash["admin"]
29
29
  user
30
30
  end
31
31
  end
@@ -48,5 +48,8 @@ class ChefVault
48
48
 
49
49
  class IdMismatch < Exceptions
50
50
  end
51
+
52
+ class V1Format < Exceptions
53
+ end
51
54
  end
52
55
  end
@@ -14,10 +14,13 @@
14
14
  # See the License for the specific language governing permissions and
15
15
  # limitations under the License.
16
16
 
17
- require 'securerandom'
17
+ require "securerandom"
18
+ require "chef-vault/mixins"
18
19
 
19
20
  class ChefVault
20
21
  class Item < Chef::DataBagItem
22
+ include ChefVault::Mixins
23
+
21
24
  # @!attribute [rw] keys
22
25
  # @return [ChefVault::ItemKeys] the keys associated with this vault
23
26
  attr_accessor :keys
@@ -60,7 +63,7 @@ class ChefVault
60
63
  @encrypted = false
61
64
  opts = {
62
65
  :node_name => Chef::Config[:node_name],
63
- :client_key_path => Chef::Config[:client_key]
66
+ :client_key_path => Chef::Config[:client_key],
64
67
  }.merge(opts)
65
68
  @node_name = opts[:node_name]
66
69
  @client_key_path = opts[:client_key_path]
@@ -192,13 +195,13 @@ class ChefVault
192
195
  super
193
196
  end
194
197
 
195
- def save(item_id=@raw_data['id'])
198
+ def save(item_id=@raw_data["id"])
196
199
  # validate the format of the id before attempting to save
197
200
  validate_id!(item_id)
198
201
 
199
202
  # ensure that the ID of the vault hasn't changed since the keys
200
203
  # data bag item was created
201
- keys_id = keys['id'].match(/^(.+)_keys/)[1]
204
+ keys_id = keys["id"].match(/^(.+)_keys/)[1]
202
205
  if keys_id != item_id
203
206
  raise ChefVault::Exceptions::IdMismatch,
204
207
  "id mismatch - input JSON has id '#{item_id}' but vault item has id '#{keys_id}'"
@@ -217,16 +220,7 @@ class ChefVault
217
220
 
218
221
  # Now save the encrypted data
219
222
  if Chef::Config[:solo]
220
- data_bag_path = File.join(Chef::Config[:data_bag_path],
221
- data_bag)
222
- data_bag_item_path = File.join(data_bag_path, item_id)
223
-
224
- FileUtils.mkdir(data_bag_path) unless File.exist?(data_bag_path)
225
- File.open("#{data_bag_item_path}.json", 'w') do |file|
226
- file.write(JSON.pretty_generate(raw_data))
227
- end
228
-
229
- raw_data
223
+ save_solo(item_id)
230
224
  else
231
225
  begin
232
226
  Chef::DataBag.load(data_bag)
@@ -317,7 +311,7 @@ class ChefVault
317
311
  # and https://github.com/sensu/sensu-chef/blob/2.9.0/libraries/sensu_helpers.rb
318
312
  dbi = Chef::DataBagItem.load(vault, name)
319
313
  encrypted = dbi.detect do |_, v|
320
- v.is_a?(Hash) && v.key?('encrypted_data')
314
+ v.is_a?(Hash) && v.key?("encrypted_data")
321
315
  end
322
316
 
323
317
  # return a symbol describing the type of item we detected
@@ -340,9 +334,9 @@ class ChefVault
340
334
  unless search
341
335
  raise ChefVault::Exceptions::SearchNotFound,
342
336
  "#{vault}/#{item} does not have a stored search_query, "\
343
- 'probably because it was created with an older version '\
337
+ "probably because it was created with an older version "\
344
338
  "of chef-vault. Use 'knife vault update' to update the "\
345
- 'databag with the search query.'
339
+ "databag with the search query."
346
340
  end
347
341
 
348
342
  # a bit of a misnomer; this doesn't remove unknown
@@ -474,14 +468,14 @@ class ChefVault
474
468
  # @param client [Chef::ApiClient] the API client to add
475
469
  # @return [void]
476
470
  def add_client(client)
477
- keys.add(client, @secret, 'clients')
471
+ keys.add(client, @secret, "clients")
478
472
  end
479
473
 
480
474
  # removes a client to the vault item keys
481
475
  # @param client_or_node [Chef::ApiClient,Chef::Node] the API client or node to remove
482
476
  # @return [void]
483
477
  def delete_client_or_node(client_or_node)
484
- keys.delete(client_or_node.name, 'clients')
478
+ keys.delete(client_or_node.name, "clients")
485
479
  end
486
480
  end
487
481
  end
@@ -14,8 +14,13 @@
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"
18
+
17
19
  class ChefVault
18
20
  class ItemKeys < Chef::DataBagItem
21
+
22
+ include ChefVault::Mixins
23
+
19
24
  def initialize(vault, name)
20
25
  super() # parentheses required to strip off parameters
21
26
  @data_bag = vault
@@ -30,6 +35,10 @@ class ChefVault
30
35
  end
31
36
 
32
37
  def add(chef_client, data_bag_shared_secret, type)
38
+ unless @raw_data.key?(type)
39
+ raise ChefVault::Exceptions::V1Format,
40
+ "cannot manage a v1 vault. See UPGRADE.md for help"
41
+ end
33
42
  public_key = OpenSSL::PKey::RSA.new chef_client.public_key
34
43
  self[chef_client.name] =
35
44
  Base64.encode64(public_key.public_encrypt(data_bag_shared_secret))
@@ -59,18 +68,9 @@ class ChefVault
59
68
  @raw_data["admins"]
60
69
  end
61
70
 
62
- def save(item_id=@raw_data['id'])
71
+ def save(item_id=@raw_data["id"])
63
72
  if Chef::Config[:solo]
64
- data_bag_path = File.join(Chef::Config[:data_bag_path],
65
- data_bag)
66
- data_bag_item_path = File.join(data_bag_path, item_id)
67
-
68
- FileUtils.mkdir(data_bag_path) unless File.exist?(data_bag_path)
69
- File.open("#{data_bag_item_path}.json", 'w') do |file|
70
- file.write(JSON.pretty_generate(raw_data))
71
- end
72
-
73
- raw_data
73
+ save_solo(item_id)
74
74
  else
75
75
  begin
76
76
  Chef::DataBag.load(data_bag)
@@ -117,13 +117,13 @@ class ChefVault
117
117
  rescue Net::HTTPServerException => http_error
118
118
  if http_error.response.code == "404"
119
119
  raise ChefVault::Exceptions::KeysNotFound,
120
- "#{vault}/#{name} could not be found"
120
+ "#{vault}/#{name} could not be found"
121
121
  else
122
122
  raise http_error
123
123
  end
124
124
  rescue Chef::Exceptions::ValidationFailed
125
125
  raise ChefVault::Exceptions::KeysNotFound,
126
- "#{vault}/#{name} could not be found"
126
+ "#{vault}/#{name} could not be found"
127
127
  end
128
128
 
129
129
  from_data_bag_item(data_bag_item)
@@ -0,0 +1,36 @@
1
+ class ChefVault
2
+ module Mixins
3
+ # In Chef 12, Chef Solo can have an array of data_bag paths, rather
4
+ # than just a string. To cope with that, we'll:
5
+ # 1. Look for an existing data bag item in any of the configured
6
+ # paths and use that by preference
7
+ # 1. Otherwise, just use the first location in the array
8
+ def find_solo_path(item_id)
9
+ if Chef::Config[:data_bag_path].kind_of?(Array)
10
+ path = Chef::Config[:data_bag_path].find { |dir|
11
+ File.exist?(File.join(dir, data_bag, "#{item_id}.json"))
12
+ }
13
+
14
+ path ||= Chef::Config[:data_bag_path].first
15
+ data_bag_path = File.join(path, data_bag)
16
+ else
17
+ data_bag_path = File.join(Chef::Config[:data_bag_path],
18
+ data_bag)
19
+ end
20
+ data_bag_item_path = File.join(data_bag_path, item_id) + ".json"
21
+
22
+ [data_bag_path, data_bag_item_path]
23
+ end
24
+
25
+ def save_solo(item_id=@raw_data["id"])
26
+ data_bag_path, data_bag_item_path = find_solo_path(item_id)
27
+
28
+ FileUtils.mkdir(data_bag_path) unless File.exist?(data_bag_path)
29
+ File.open(data_bag_item_path, "w") do |file|
30
+ file.write(JSON.pretty_generate(raw_data))
31
+ end
32
+
33
+ raw_data
34
+ end
35
+ end
36
+ end
@@ -1,5 +1,6 @@
1
1
  # Description: ChefVault VERSION file
2
2
  # Copyright 2013-15, Nordstrom, Inc.
3
+ # Copyright 2015-2016, Chef Software, Inc.
3
4
 
4
5
  # Licensed under the Apache License, Version 2.0 (the "License");
5
6
  # you may not use this file except in compliance with the License.
@@ -14,6 +15,6 @@
14
15
  # limitations under the License.
15
16
 
16
17
  class ChefVault
17
- VERSION = '2.6.1'
18
- MAJOR, MINOR, TINY = VERSION.split('.')
18
+ VERSION = "2.7.1"
19
+ MAJOR, MINOR, TINY = VERSION.split(".")
19
20
  end
@@ -13,8 +13,8 @@
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_decrypt'
16
+ require "chef/knife/vault_base"
17
+ require "chef/knife/vault_decrypt"
18
18
 
19
19
  class Chef
20
20
  class Knife
@@ -13,8 +13,8 @@
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_create'
16
+ require "chef/knife/vault_base"
17
+ require "chef/knife/vault_create"
18
18
 
19
19
  class Chef
20
20
  class Knife
@@ -24,23 +24,23 @@ class Chef
24
24
  banner "knife encrypt create VAULT ITEM VALUES (options)"
25
25
 
26
26
  option :search,
27
- :short => '-S SEARCH',
28
- :long => '--search SEARCH',
29
- :description => 'Chef SOLR search for clients'
27
+ :short => "-S SEARCH",
28
+ :long => "--search SEARCH",
29
+ :description => "Chef SOLR search for clients"
30
30
 
31
31
  option :admins,
32
- :short => '-A ADMINS',
33
- :long => '--admins ADMINS',
34
- :description => 'Chef users to be added as admins'
32
+ :short => "-A ADMINS",
33
+ :long => "--admins ADMINS",
34
+ :description => "Chef users to be added as admins"
35
35
 
36
36
  option :json,
37
- :short => '-J FILE',
38
- :long => '--json FILE',
39
- :description => 'File containing JSON data to encrypt'
37
+ :short => "-J FILE",
38
+ :long => "--json FILE",
39
+ :description => "File containing JSON data to encrypt"
40
40
 
41
41
  option :file,
42
- :long => '--file FILE',
43
- :description => 'File to be added to vault item as file-content'
42
+ :long => "--file FILE",
43
+ :description => "File to be added to vault item as file-content"
44
44
 
45
45
  def run
46
46
  $stdout.puts "DEPRECATION WARNING: knife encrypt is deprecated. Please use knife vault instead."
@@ -13,8 +13,8 @@
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_delete'
16
+ require "chef/knife/vault_base"
17
+ require "chef/knife/vault_delete"
18
18
 
19
19
  class Chef
20
20
  class Knife
@@ -13,8 +13,8 @@
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_remove'
16
+ require "chef/knife/vault_base"
17
+ require "chef/knife/vault_remove"
18
18
 
19
19
  class Chef
20
20
  class Knife
@@ -24,14 +24,14 @@ class Chef
24
24
  banner "knife encrypt remove VAULT ITEM VALUES (options)"
25
25
 
26
26
  option :search,
27
- :short => '-S SEARCH',
28
- :long => '--search SEARCH',
29
- :description => 'Chef SOLR search for clients'
27
+ :short => "-S SEARCH",
28
+ :long => "--search SEARCH",
29
+ :description => "Chef SOLR search for clients"
30
30
 
31
31
  option :admins,
32
- :short => '-A ADMINS',
33
- :long => '--admins ADMINS',
34
- :description => 'Chef users to be added as admins'
32
+ :short => "-A ADMINS",
33
+ :long => "--admins ADMINS",
34
+ :description => "Chef users to be added as admins"
35
35
 
36
36
  def run
37
37
  $stdout.puts "DEPRECATION WARNING: knife encrypt is deprecated. Please use knife vault instead."
@@ -13,8 +13,8 @@
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_rotate_keys'
16
+ require "chef/knife/vault_base"
17
+ require "chef/knife/vault_rotate_keys"
18
18
 
19
19
  class Chef
20
20
  class Knife
@@ -13,8 +13,8 @@
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_update'
16
+ require "chef/knife/vault_base"
17
+ require "chef/knife/vault_update"
18
18
 
19
19
  class Chef
20
20
  class Knife
@@ -22,23 +22,23 @@ class Chef
22
22
  include Knife::VaultBase
23
23
 
24
24
  option :search,
25
- :short => '-S SEARCH',
26
- :long => '--search SEARCH',
27
- :description => 'Chef SOLR search for clients'
25
+ :short => "-S SEARCH",
26
+ :long => "--search SEARCH",
27
+ :description => "Chef SOLR search for clients"
28
28
 
29
29
  option :admins,
30
- :short => '-A ADMINS',
31
- :long => '--admins ADMINS',
32
- :description => 'Chef users to be added as admins'
30
+ :short => "-A ADMINS",
31
+ :long => "--admins ADMINS",
32
+ :description => "Chef users to be added as admins"
33
33
 
34
34
  option :json,
35
- :short => '-J FILE',
36
- :long => '--json FILE',
37
- :description => 'File containing JSON data to encrypt'
35
+ :short => "-J FILE",
36
+ :long => "--json FILE",
37
+ :description => "File containing JSON data to encrypt"
38
38
 
39
39
  option :file,
40
- :long => '--file FILE',
41
- :description => 'File to be added to vault item as file-content'
40
+ :long => "--file FILE",
41
+ :description => "File to be added to vault item as file-content"
42
42
 
43
43
  banner "knife encrypt update VAULT ITEM VALUES (options)"
44
44