chef-vault 2.5.0 → 2.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +5 -1
- data/.travis.yml +5 -1
- data/Changelog.md +36 -3
- data/KNIFE_EXAMPLES.md +49 -74
- data/README.md +166 -104
- data/THEORY.md +4 -2
- data/bin/chef-vault +2 -2
- data/chef-vault.gemspec +2 -2
- data/features/clean_on_refresh.feature +28 -0
- data/features/isvault.feature +24 -0
- data/features/itemtype.feature +25 -0
- data/features/step_definitions/chef-databag.rb +4 -0
- data/features/step_definitions/chef-vault.rb +21 -0
- data/features/step_definitions/chef_databagitem.rb +9 -0
- data/features/vault_show_vaultname.feature +22 -0
- data/features/vault_update.feature +1 -1
- data/features/verify_id_matches.feature +11 -0
- data/lib/chef-vault/certificate.rb +1 -1
- data/lib/chef-vault/exceptions.rb +3 -0
- data/lib/chef-vault/item.rb +161 -18
- data/lib/chef-vault/user.rb +1 -1
- data/lib/chef-vault/version.rb +1 -1
- data/lib/chef/knife/decrypt.rb +1 -1
- data/lib/chef/knife/encrypt_create.rb +1 -1
- data/lib/chef/knife/encrypt_delete.rb +1 -1
- data/lib/chef/knife/encrypt_remove.rb +1 -1
- data/lib/chef/knife/encrypt_rotate_keys.rb +1 -1
- data/lib/chef/knife/encrypt_update.rb +1 -1
- data/lib/chef/knife/vault_base.rb +22 -0
- data/lib/chef/knife/vault_create.rb +0 -1
- data/lib/chef/knife/vault_decrypt.rb +1 -1
- data/lib/chef/knife/vault_isvault.rb +43 -0
- data/lib/chef/knife/vault_itemtype.rb +43 -0
- data/lib/chef/knife/vault_list.rb +7 -18
- data/lib/chef/knife/vault_refresh.rb +6 -12
- data/lib/chef/knife/vault_rotate_all_keys.rb +1 -1
- data/lib/chef/knife/vault_show.rb +15 -1
- data/lib/chef/knife/vault_update.rb +1 -1
- data/spec/chef-vault/certificate_spec.rb +9 -2
- data/spec/chef-vault/item_spec.rb +164 -3
- data/spec/chef-vault/user_spec.rb +9 -2
- metadata +14 -6
data/lib/chef-vault/user.rb
CHANGED
data/lib/chef-vault/version.rb
CHANGED
data/lib/chef/knife/decrypt.rb
CHANGED
@@ -24,7 +24,7 @@ class Chef
|
|
24
24
|
banner "knife decrypt VAULT ITEM [VALUES] (options)"
|
25
25
|
|
26
26
|
def run
|
27
|
-
puts "DEPRECATION WARNING: knife decrypt is deprecated. Please use knife vault decrypt instead."
|
27
|
+
$stdout.puts "DEPRECATION WARNING: knife decrypt is deprecated. Please use knife vault decrypt instead."
|
28
28
|
super
|
29
29
|
end
|
30
30
|
end
|
@@ -43,7 +43,7 @@ class Chef
|
|
43
43
|
:description => 'File to be added to vault item as file-content'
|
44
44
|
|
45
45
|
def run
|
46
|
-
puts "DEPRECATION WARNING: knife encrypt is deprecated. Please use knife vault instead."
|
46
|
+
$stdout.puts "DEPRECATION WARNING: knife encrypt is deprecated. Please use knife vault instead."
|
47
47
|
super
|
48
48
|
end
|
49
49
|
end
|
@@ -24,7 +24,7 @@ class Chef
|
|
24
24
|
banner "knife encrypt delete VAULT ITEM (options)"
|
25
25
|
|
26
26
|
def run
|
27
|
-
puts "DEPRECATION WARNING: knife encrypt is deprecated. Please use knife vault instead."
|
27
|
+
$stdout.puts "DEPRECATION WARNING: knife encrypt is deprecated. Please use knife vault instead."
|
28
28
|
super
|
29
29
|
end
|
30
30
|
end
|
@@ -34,7 +34,7 @@ class Chef
|
|
34
34
|
:description => 'Chef users to be added as admins'
|
35
35
|
|
36
36
|
def run
|
37
|
-
puts "DEPRECATION WARNING: knife encrypt is deprecated. Please use knife vault instead."
|
37
|
+
$stdout.puts "DEPRECATION WARNING: knife encrypt is deprecated. Please use knife vault instead."
|
38
38
|
super
|
39
39
|
end
|
40
40
|
end
|
@@ -24,7 +24,7 @@ class Chef
|
|
24
24
|
banner "knife encrypt rotate keys VAULT ITEM (options)"
|
25
25
|
|
26
26
|
def run
|
27
|
-
puts "DEPRECATION WARNING: knife encrypt is deprecated. Please use knife vault instead."
|
27
|
+
$stdout.puts "DEPRECATION WARNING: knife encrypt is deprecated. Please use knife vault instead."
|
28
28
|
super
|
29
29
|
end
|
30
30
|
end
|
@@ -43,7 +43,7 @@ class Chef
|
|
43
43
|
banner "knife encrypt update VAULT ITEM VALUES (options)"
|
44
44
|
|
45
45
|
def run
|
46
|
-
puts "DEPRECATION WARNING: knife encrypt is deprecated. Please use knife vault instead."
|
46
|
+
$stdout.puts "DEPRECATION WARNING: knife encrypt is deprecated. Please use knife vault instead."
|
47
47
|
super
|
48
48
|
end
|
49
49
|
end
|
@@ -41,6 +41,28 @@ class Chef
|
|
41
41
|
super
|
42
42
|
exit 1
|
43
43
|
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def bag_is_vault?(bagname)
|
48
|
+
bag = Chef::DataBag.load(bagname)
|
49
|
+
# vaults have at even number of keys >= 2
|
50
|
+
return false unless bag.keys.size >= 2 && 0 == bag.keys.size % 2
|
51
|
+
# partition into those that end in _keys
|
52
|
+
keylike, notkeylike = split_vault_keys(bag)
|
53
|
+
# there must be an equal number of keyline and not-keylike items
|
54
|
+
return false unless keylike.size == notkeylike.size
|
55
|
+
# strip the _keys suffix and check if the sets match
|
56
|
+
keylike.map! { |k| k.gsub(/_keys$/, '') }
|
57
|
+
return false unless keylike.sort == notkeylike.sort
|
58
|
+
# it's (probably) a vault
|
59
|
+
true
|
60
|
+
end
|
61
|
+
|
62
|
+
def split_vault_keys(bag)
|
63
|
+
# partition into those that end in _keys
|
64
|
+
bag.keys.partition { |k| k =~ /_keys$/ }
|
65
|
+
end
|
44
66
|
end
|
45
67
|
end
|
46
68
|
end
|
@@ -63,7 +63,6 @@ class Chef
|
|
63
63
|
rescue ChefVault::Exceptions::KeysNotFound,
|
64
64
|
ChefVault::Exceptions::ItemNotFound
|
65
65
|
vault_item = ChefVault::Item.new(vault, item)
|
66
|
-
|
67
66
|
if values || json_file || file
|
68
67
|
merge_values(values, json_file).each do |key, value|
|
69
68
|
vault_item[key] = value
|
@@ -23,7 +23,7 @@ class Chef
|
|
23
23
|
banner "knife vault decrypt VAULT ITEM [VALUES] (options)"
|
24
24
|
|
25
25
|
def run
|
26
|
-
puts "DEPRECATION WARNING: knife vault decrypt is deprecated. Please use knife vault show instead."
|
26
|
+
$stdout.puts "DEPRECATION WARNING: knife vault decrypt is deprecated. Please use knife vault show instead."
|
27
27
|
vault = @name_args[0]
|
28
28
|
item = @name_args[1]
|
29
29
|
values = @name_args[2]
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# Description: Chef-Vault VaultIsvault class
|
2
|
+
# Copyright 2013, Nordstrom, Inc.
|
3
|
+
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
require 'chef/knife/vault_base'
|
17
|
+
|
18
|
+
class Chef
|
19
|
+
class Knife
|
20
|
+
class VaultIsvault < Knife
|
21
|
+
include Chef::Knife::VaultBase
|
22
|
+
|
23
|
+
banner "knife vault isvault VAULT ITEM (options)"
|
24
|
+
|
25
|
+
option :mode,
|
26
|
+
:short => '-M MODE',
|
27
|
+
:long => '--mode MODE',
|
28
|
+
:description => 'Chef mode to run in default - solo'
|
29
|
+
|
30
|
+
def run
|
31
|
+
vault = @name_args[0]
|
32
|
+
item = @name_args[1]
|
33
|
+
|
34
|
+
if vault && item
|
35
|
+
set_mode(config[:vault_mode])
|
36
|
+
exit ChefVault::Item.vault?(vault, item) ? 0 : 1
|
37
|
+
else
|
38
|
+
show_usage
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# Description: Chef-Vault VaultItemtype class
|
2
|
+
# Copyright 2013, Nordstrom, Inc.
|
3
|
+
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
require 'chef/knife/vault_base'
|
17
|
+
|
18
|
+
class Chef
|
19
|
+
class Knife
|
20
|
+
class VaultItemtype < Knife
|
21
|
+
include Chef::Knife::VaultBase
|
22
|
+
|
23
|
+
banner "knife vault itemtype VAULT ITEM (options)"
|
24
|
+
|
25
|
+
option :mode,
|
26
|
+
:short => '-M MODE',
|
27
|
+
:long => '--mode MODE',
|
28
|
+
:description => 'Chef mode to run in default - solo'
|
29
|
+
|
30
|
+
def run
|
31
|
+
vault = @name_args[0]
|
32
|
+
item = @name_args[1]
|
33
|
+
|
34
|
+
if vault && item
|
35
|
+
set_mode(config[:vault_mode])
|
36
|
+
output ChefVault::Item.data_bag_item_type(vault, item)
|
37
|
+
else
|
38
|
+
show_usage
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Description: Chef-Vault
|
1
|
+
# Description: Chef-Vault VaultList class
|
2
2
|
# Copyright 2013, Nordstrom, Inc.
|
3
3
|
|
4
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -22,7 +22,13 @@ class Chef
|
|
22
22
|
|
23
23
|
banner "knife vault list (options)"
|
24
24
|
|
25
|
+
option :mode,
|
26
|
+
:short => '-M MODE',
|
27
|
+
:long => '--mode MODE',
|
28
|
+
:description => 'Chef mode to run in default - solo'
|
29
|
+
|
25
30
|
def run
|
31
|
+
set_mode(config[:vault_mode])
|
26
32
|
vaultbags = []
|
27
33
|
# iterate over all the data bags
|
28
34
|
bags = Chef::DataBag.list
|
@@ -31,23 +37,6 @@ class Chef
|
|
31
37
|
end
|
32
38
|
output vaultbags.join("\n")
|
33
39
|
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
def bag_is_vault?(bagname)
|
38
|
-
bag = Chef::DataBag.load(bagname)
|
39
|
-
# vaults have at even number of keys >= 2
|
40
|
-
return false unless bag.keys.size >= 2 && 0 == bag.keys.size % 2
|
41
|
-
# partition into those that end in _keys
|
42
|
-
keylike, notkeylike = bag.keys.partition { |k| k =~ /_keys$/ }
|
43
|
-
# there must be an equal number of keyline and not-keylike items
|
44
|
-
return false unless keylike.size == notkeylike.size
|
45
|
-
# strip the _keys suffix and check if the sets match
|
46
|
-
keylike.map! { |k| k.gsub(/_keys$/, '') }
|
47
|
-
return false unless keylike.sort == notkeylike.sort
|
48
|
-
# it's (probably) a vault
|
49
|
-
true
|
50
|
-
end
|
51
40
|
end
|
52
41
|
end
|
53
42
|
end
|
@@ -22,27 +22,21 @@ class Chef
|
|
22
22
|
|
23
23
|
banner "knife vault refresh VAULT ITEM"
|
24
24
|
|
25
|
+
option :clean_unknown_clients,
|
26
|
+
:long => '--clean-unknown-clients',
|
27
|
+
:description => 'Remove unknown clients during refresh'
|
28
|
+
|
25
29
|
def run
|
26
30
|
vault = @name_args[0]
|
27
31
|
item = @name_args[1]
|
32
|
+
clean = config[:clean_unknown_clients]
|
28
33
|
|
29
34
|
set_mode(config[:vault_mode])
|
30
35
|
|
31
36
|
if vault && item
|
32
37
|
begin
|
33
38
|
vault_item = ChefVault::Item.load(vault, item)
|
34
|
-
|
35
|
-
|
36
|
-
unless search
|
37
|
-
raise ChefVault::Exceptions::SearchNotFound,
|
38
|
-
"#{vault}/#{item} does not have a stored search_query, "\
|
39
|
-
"probably because it was created with an older version "\
|
40
|
-
"of chef-vault. Use 'knife vault update' to update the "\
|
41
|
-
"databag with the search query."
|
42
|
-
end
|
43
|
-
|
44
|
-
vault_item.clients(search)
|
45
|
-
vault_item.save
|
39
|
+
vault_item.refresh(clean)
|
46
40
|
rescue ChefVault::Exceptions::KeysNotFound,
|
47
41
|
ChefVault::Exceptions::ItemNotFound
|
48
42
|
|
@@ -52,7 +52,7 @@ class Chef
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def rotate_vault_item_keys(vault, item, clean_unknown_clients)
|
55
|
-
puts "Rotating keys for: #{vault} #{item}"
|
55
|
+
$stdout.puts "Rotating keys for: #{vault} #{item}"
|
56
56
|
ChefVault::Item.load(vault, item).rotate_keys!(clean_unknown_clients)
|
57
57
|
end
|
58
58
|
end
|
@@ -20,7 +20,7 @@ class Chef
|
|
20
20
|
class VaultShow < Knife
|
21
21
|
include Chef::Knife::VaultBase
|
22
22
|
|
23
|
-
banner "knife vault show VAULT ITEM [VALUES] (options)"
|
23
|
+
banner "knife vault show VAULT [ITEM] [VALUES] (options)"
|
24
24
|
|
25
25
|
option :mode,
|
26
26
|
:short => '-M MODE',
|
@@ -40,6 +40,9 @@ class Chef
|
|
40
40
|
if vault && item
|
41
41
|
set_mode(config[:vault_mode])
|
42
42
|
print_values(vault, item, values)
|
43
|
+
elsif vault
|
44
|
+
set_mode(config[:vault_mode])
|
45
|
+
print_keys(vault)
|
43
46
|
else
|
44
47
|
show_usage
|
45
48
|
end
|
@@ -83,6 +86,17 @@ class Chef
|
|
83
86
|
end
|
84
87
|
output(output_data)
|
85
88
|
end
|
89
|
+
|
90
|
+
def print_keys(vault)
|
91
|
+
if bag_is_vault?(vault)
|
92
|
+
bag = Chef::DataBag.load(vault)
|
93
|
+
split_vault_keys(bag)[1].each do |item|
|
94
|
+
output item
|
95
|
+
end
|
96
|
+
else
|
97
|
+
output "data bag #{vault} is not a chef-vault"
|
98
|
+
end
|
99
|
+
end
|
86
100
|
end
|
87
101
|
end
|
88
102
|
end
|
@@ -6,6 +6,12 @@ RSpec.describe ChefVault::Certificate do
|
|
6
6
|
allow(ChefVault::Item).to receive(:load).with("foo", "bar"){ item }
|
7
7
|
allow(item).to receive(:[]).with("id"){ "bar" }
|
8
8
|
allow(item).to receive(:[]).with("contents"){ "baz" }
|
9
|
+
@orig_stdout = $stdout
|
10
|
+
$stdout = File.open(File::NULL, 'w')
|
11
|
+
end
|
12
|
+
|
13
|
+
after do
|
14
|
+
$stdout = @orig_stdout
|
9
15
|
end
|
10
16
|
|
11
17
|
describe '#new' do
|
@@ -22,8 +28,9 @@ RSpec.describe ChefVault::Certificate do
|
|
22
28
|
|
23
29
|
describe 'decrypt_contents' do
|
24
30
|
it 'echoes warning' do
|
25
|
-
expect
|
26
|
-
|
31
|
+
expect { cert.decrypt_contents }
|
32
|
+
.to output("WARNING: This method is deprecated, please switch to item['value'] calls\n")
|
33
|
+
.to_stdout
|
27
34
|
end
|
28
35
|
|
29
36
|
it 'returns items contents' do
|
@@ -51,9 +51,84 @@ module BorkedNodeWithoutPublicKey
|
|
51
51
|
end
|
52
52
|
|
53
53
|
RSpec.describe ChefVault::Item do
|
54
|
+
before do
|
55
|
+
@orig_stdout = $stdout
|
56
|
+
$stdout = File.open(File::NULL, 'w')
|
57
|
+
end
|
58
|
+
|
59
|
+
after do
|
60
|
+
$stdout = @orig_stdout
|
61
|
+
end
|
62
|
+
|
54
63
|
subject(:item) { ChefVault::Item.new("foo", "bar") }
|
55
64
|
|
56
|
-
describe '
|
65
|
+
describe 'vault probe predicates' do
|
66
|
+
before do
|
67
|
+
# a normal data bag item
|
68
|
+
@db = { 'foo' => '...' }
|
69
|
+
@dbi = Chef::DataBagItem.new
|
70
|
+
@dbi.data_bag('normal')
|
71
|
+
@dbi.raw_data = { 'id' => 'foo', 'foo' => 'bar' }
|
72
|
+
allow(@db).to receive(:load).with('foo').and_return(@dbi)
|
73
|
+
allow(Chef::DataBag).to receive(:load).with('normal').and_return(@db)
|
74
|
+
allow(Chef::DataBagItem).to receive(:load).with('normal', 'foo').and_return(@dbi)
|
75
|
+
|
76
|
+
# an encrypted data bag item (non-vault)
|
77
|
+
@encdb = { 'foo' => '...' }
|
78
|
+
@encdbi = Chef::DataBagItem.new
|
79
|
+
@encdbi.data_bag('encrypted')
|
80
|
+
@encdbi.raw_data = {
|
81
|
+
'id' => 'foo',
|
82
|
+
'foo' => { 'encrypted_data' => '...' }
|
83
|
+
}
|
84
|
+
allow(@encdb).to receive(:load).with('foo').and_return(@encdbi)
|
85
|
+
allow(Chef::DataBag).to receive(:load).with('encrypted').and_return(@encdb)
|
86
|
+
allow(Chef::DataBagItem).to receive(:load).with('encrypted', 'foo').and_return(@encdbi)
|
87
|
+
|
88
|
+
# two items that make up a vault
|
89
|
+
@vaultdb = { 'foo' => '...', 'foo_keys' => '...' }
|
90
|
+
@vaultdbi = Chef::DataBagItem.new
|
91
|
+
@vaultdbi.data_bag('vault')
|
92
|
+
@vaultdbi.raw_data = {
|
93
|
+
'id' => 'foo',
|
94
|
+
'foo' => { 'encrypted_data' => '...' }
|
95
|
+
}
|
96
|
+
allow(@vaultdb).to receive(:load).with('foo').and_return(@vaultdbi)
|
97
|
+
@vaultdbki = Chef::DataBagItem.new
|
98
|
+
@vaultdbki.data_bag('vault')
|
99
|
+
@vaultdbki.raw_data = { 'id' => 'foo_keys' }
|
100
|
+
allow(@vaultdb).to receive(:load).with('foo_keys').and_return(@vaultdbki)
|
101
|
+
allow(Chef::DataBag).to receive(:load).with('vault').and_return(@vaultdb)
|
102
|
+
allow(Chef::DataBagItem).to receive(:load).with('vault', 'foo').and_return(@vaultdbi)
|
103
|
+
end
|
104
|
+
|
105
|
+
describe '::vault?' do
|
106
|
+
it 'should detect a vault item' do
|
107
|
+
expect(ChefVault::Item.vault?('vault', 'foo')).to be_truthy
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'should detect non-vault items' do
|
111
|
+
expect(ChefVault::Item.vault?('normal', 'foo')).not_to be_truthy
|
112
|
+
expect(ChefVault::Item.vault?('encrypted', 'foo')).not_to be_truthy
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe '::data_bag_item_type' do
|
117
|
+
it 'should detect a vault item' do
|
118
|
+
expect(ChefVault::Item.data_bag_item_type('vault', 'foo')).to eq(:vault)
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'should detect an encrypted data bag item' do
|
122
|
+
expect(ChefVault::Item.data_bag_item_type('encrypted', 'foo')).to eq(:encrypted)
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'should detect a normal data bag item' do
|
126
|
+
expect(ChefVault::Item.data_bag_item_type('normal', 'foo')).to eq(:normal)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe '::new' do
|
57
132
|
it { should be_an_instance_of ChefVault::Item }
|
58
133
|
|
59
134
|
its(:keys) { should be_an_instance_of ChefVault::ItemKeys }
|
@@ -65,14 +140,80 @@ RSpec.describe ChefVault::Item do
|
|
65
140
|
specify { expect(item.keys['id']).to eq 'bar_keys' }
|
66
141
|
|
67
142
|
specify { expect(item.keys.data_bag).to eq 'foo' }
|
143
|
+
|
144
|
+
it 'defaults the node name' do
|
145
|
+
item = ChefVault::Item.new('foo', 'bar')
|
146
|
+
expect(item.node_name).to eq(Chef::Config[:node_name])
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'defaults the client key path' do
|
150
|
+
item = ChefVault::Item.new('foo', 'bar')
|
151
|
+
expect(item.client_key_path).to eq(Chef::Config[:client_key])
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'allows for a node name override' do
|
155
|
+
item = ChefVault::Item.new('foo', 'bar', node_name: 'baz')
|
156
|
+
expect(item.node_name).to eq('baz')
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'allows for a client key path override' do
|
160
|
+
item = ChefVault::Item.new('foo', 'bar', client_key_path: '/foo/client.pem')
|
161
|
+
expect(item.client_key_path).to eq('/foo/client.pem')
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'allows for both node name and client key overrides' do
|
165
|
+
item = ChefVault::Item.new(
|
166
|
+
'foo', 'bar',
|
167
|
+
node_name: 'baz',
|
168
|
+
client_key_path: '/foo/client.pem'
|
169
|
+
)
|
170
|
+
expect(item.node_name).to eq('baz')
|
171
|
+
expect(item.client_key_path).to eq('/foo/client.pem')
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
describe '::load' do
|
176
|
+
it 'allows for both node name and client key overrides' do
|
177
|
+
keys_db = Chef::DataBagItem.new
|
178
|
+
keys_db.raw_data = {
|
179
|
+
'id' => 'bar_keys',
|
180
|
+
'baz' => '...'
|
181
|
+
}
|
182
|
+
allow(ChefVault::ItemKeys)
|
183
|
+
.to receive(:load)
|
184
|
+
.and_return(keys_db)
|
185
|
+
fh = double 'private key handle'
|
186
|
+
allow(fh).to receive(:read).and_return('...')
|
187
|
+
allow(File).to receive(:open).and_return(fh)
|
188
|
+
privkey = double 'private key contents'
|
189
|
+
allow(privkey).to receive(:private_decrypt).and_return('sekrit')
|
190
|
+
allow(OpenSSL::PKey::RSA).to receive(:new).and_return(privkey)
|
191
|
+
allow(Chef::EncryptedDataBagItem).to receive(:load).and_return(
|
192
|
+
'id' => 'bar',
|
193
|
+
'password' => '12345'
|
194
|
+
)
|
195
|
+
item = ChefVault::Item.load(
|
196
|
+
'foo', 'bar',
|
197
|
+
node_name: 'baz',
|
198
|
+
client_key_path: '/foo/client.pem'
|
199
|
+
)
|
200
|
+
expect(item.node_name).to eq('baz')
|
201
|
+
expect(item.client_key_path).to eq('/foo/client.pem')
|
202
|
+
end
|
68
203
|
end
|
69
204
|
|
70
205
|
describe '#save' do
|
71
206
|
context 'when item["id"] is bar.bar' do
|
72
207
|
let(:item) { ChefVault::Item.new("foo", "bar.bar") }
|
73
|
-
|
74
208
|
specify { expect { item.save }.to raise_error }
|
75
209
|
end
|
210
|
+
|
211
|
+
it 'should validate that the id of the vault matches the id of the keys data bag' do
|
212
|
+
item = ChefVault::Item.new('foo', 'bar')
|
213
|
+
item['id'] = 'baz'
|
214
|
+
item.keys['clients'] = %w(admin)
|
215
|
+
expect { item.save }.to raise_error(ChefVault::Exceptions::IdMismatch)
|
216
|
+
end
|
76
217
|
end
|
77
218
|
|
78
219
|
describe '#clients' do
|
@@ -87,7 +228,19 @@ RSpec.describe ChefVault::Item do
|
|
87
228
|
it 'should emit a warning if search returns a node without a public key' do
|
88
229
|
# it should however emit a warning that you have a borked node
|
89
230
|
expect { @vaultitem.clients('*:*') }
|
90
|
-
.to output(/node 'bar' has no private key; skipping/).
|
231
|
+
.to output(/node 'bar' has no private key; skipping/).to_stdout
|
232
|
+
end
|
233
|
+
|
234
|
+
it 'should accept a client object and not perform a search' do
|
235
|
+
client = Chef::ApiClient.new
|
236
|
+
client.name 'foo'
|
237
|
+
privkey = OpenSSL::PKey::RSA.new(1024)
|
238
|
+
pubkey = privkey.public_key
|
239
|
+
client.public_key(pubkey.to_pem)
|
240
|
+
expect(Chef::Search::Query).not_to receive(:new)
|
241
|
+
expect(ChefVault::ChefPatch::User).not_to receive(:load)
|
242
|
+
@vaultitem.clients(client)
|
243
|
+
expect(@vaultitem.clients).to include('foo')
|
91
244
|
end
|
92
245
|
end
|
93
246
|
|
@@ -99,4 +252,12 @@ RSpec.describe ChefVault::Item do
|
|
99
252
|
.to raise_error(ChefVault::Exceptions::AdminNotFound)
|
100
253
|
end
|
101
254
|
end
|
255
|
+
|
256
|
+
describe '#raw_keys' do
|
257
|
+
it 'should return the keys of the underlying data bag item' do
|
258
|
+
item = ChefVault::Item.new('foo', 'bar')
|
259
|
+
item['foo'] = 'bar'
|
260
|
+
expect(item.raw_keys).to eq(%w(id foo))
|
261
|
+
end
|
262
|
+
end
|
102
263
|
end
|