chef-vault 3.0.0.rc2 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Changelog.md +34 -2
- data/Gemfile +1 -1
- data/features/isvault.feature +6 -0
- data/features/step_definitions/chef-vault.rb +19 -8
- data/features/vault_create.feature +10 -0
- data/features/vault_list.feature +6 -0
- data/lib/chef-vault/actor.rb +10 -12
- data/lib/chef-vault/item_keys.rb +14 -5
- data/lib/chef-vault/version.rb +1 -1
- data/lib/chef/knife/vault_base.rb +15 -4
- data/lib/chef/knife/vault_create.rb +7 -0
- data/spec/chef-vault/item_keys_spec.rb +53 -5
- data/tasks/github_changelog_generator.rb +3 -4
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 52a4a35874db5011ab58dc856935a50d9f5bd0b1
|
4
|
+
data.tar.gz: 3515ba7b52b188fe1851cd2a7d2585b8268f8a9a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dda2609409ba281e63da7dacf34063c9efc65e5ad50a0652f11a75d4f97a56346b32e5580cc853d64933e01ec3edddbe2e67b8b48690e6fecd08a7af9cafca6c
|
7
|
+
data.tar.gz: ce93841b5ecbd3176a1cc7b5c4ce04735fddcc6a7b7b70cb9739b61e53a40a84c884676dea5a75bb33930d8d50250da2e5d11caa784b80466c649c3b9a639f3d
|
data/Changelog.md
CHANGED
@@ -1,7 +1,39 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
-
## [
|
4
|
-
[Full Changelog](https://github.com/chef/chef-vault/compare/v2.
|
3
|
+
## [v3.0.0](https://github.com/chef/chef-vault/tree/v3.0.0) (2017-04-10)
|
4
|
+
[Full Changelog](https://github.com/chef/chef-vault/compare/v2.9.1...v3.0.0)
|
5
|
+
|
6
|
+
**Implemented enhancements:**
|
7
|
+
|
8
|
+
- Vault creation, list, and destruction in sparse mode [\#252](https://github.com/chef/chef-vault/pull/252) ([rveznaver](https://github.com/rveznaver))
|
9
|
+
|
10
|
+
## [v3.0.0.rc2](https://github.com/chef/chef-vault/tree/v3.0.0.rc2) (2016-12-05)
|
11
|
+
[Full Changelog](https://github.com/chef/chef-vault/compare/v3.0.0.rc1...v3.0.0.rc2)
|
12
|
+
|
13
|
+
**Implemented enhancements:**
|
14
|
+
|
15
|
+
- Add feature to save each key in different data bag item [\#246](https://github.com/chef/chef-vault/pull/246) ([rveznaver](https://github.com/rveznaver))
|
16
|
+
- Enable testing with Chef Zero [\#244](https://github.com/chef/chef-vault/pull/244) ([rveznaver](https://github.com/rveznaver))
|
17
|
+
- Minimize the number of searches [\#243](https://github.com/chef/chef-vault/pull/243) ([thommay](https://github.com/thommay))
|
18
|
+
- Optimise queries when finding nodes [\#240](https://github.com/chef/chef-vault/pull/240) ([thommay](https://github.com/thommay))
|
19
|
+
|
20
|
+
**Fixed bugs:**
|
21
|
+
|
22
|
+
- Use solo\_legacy\_mode fully [\#242](https://github.com/chef/chef-vault/pull/242) ([thommay](https://github.com/thommay))
|
23
|
+
- Use legacy solo mode [\#241](https://github.com/chef/chef-vault/pull/241) ([thommay](https://github.com/thommay))
|
24
|
+
|
25
|
+
## [v3.0.0.rc1](https://github.com/chef/chef-vault/tree/v3.0.0.rc1) (2016-10-21)
|
26
|
+
[Full Changelog](https://github.com/chef/chef-vault/compare/v2.9.0...v3.0.0.rc1)
|
27
|
+
|
28
|
+
**Implemented enhancements:**
|
29
|
+
|
30
|
+
- Removed deprecated knife commands [\#236](https://github.com/chef/chef-vault/pull/236) ([thommay](https://github.com/thommay))
|
31
|
+
- rename ChefKey to Actor [\#234](https://github.com/chef/chef-vault/pull/234) ([thommay](https://github.com/thommay))
|
32
|
+
- Move to using a logger for all user output [\#232](https://github.com/chef/chef-vault/pull/232) ([thommay](https://github.com/thommay))
|
33
|
+
- Add support for clients [\#227](https://github.com/chef/chef-vault/pull/227) ([svanharmelen](https://github.com/svanharmelen))
|
34
|
+
|
35
|
+
## [v2.9.0](https://github.com/chef/chef-vault/tree/v2.9.0) (2016-04-08)
|
36
|
+
[Full Changelog](https://github.com/chef/chef-vault/compare/v2.8.0...v2.9.0)
|
5
37
|
|
6
38
|
**Implemented enhancements:**
|
7
39
|
|
data/Gemfile
CHANGED
data/features/isvault.feature
CHANGED
@@ -8,6 +8,12 @@ Feature: determine if a data bag item is a vault
|
|
8
8
|
And I check if the data bag item 'test/item' is a vault
|
9
9
|
Then the exit status should be 0
|
10
10
|
|
11
|
+
Scenario: detect vault item with keys in sparse mode
|
12
|
+
Given a local mode chef repo with nodes 'one,two,three'
|
13
|
+
And I create a vault item 'test/item' with keys in sparse mode containing the JSON '{"foo": "bar"}' encrypted for 'one,two,three'
|
14
|
+
And I check if the data bag item 'test/item' is a vault
|
15
|
+
Then the exit status should be 0
|
16
|
+
|
11
17
|
Scenario: detect non-vault item (encrypted data bag)
|
12
18
|
Given a local mode chef repo with nodes 'one,two,three'
|
13
19
|
And I create an empty data bag 'test'
|
@@ -1,10 +1,11 @@
|
|
1
1
|
require "json"
|
2
2
|
|
3
|
-
Given(/^I create a vault item '(.+)\/(.+)' containing the JSON '(.+)' encrypted for '(.+)'(?: with '(.+)' as admins?)?$/) do |vault, item, json, nodelist, admins|
|
3
|
+
Given(/^I create a vault item '(.+)\/(.+)'( with keys in sparse mode)? containing the JSON '(.+)' encrypted for '(.+)'(?: with '(.+)' as admins?)?$/) do |vault, item, sparse, json, nodelist, admins|
|
4
4
|
write_file "item.json", json
|
5
5
|
query = nodelist.split(/,/).map { |e| "name:#{e}" }.join(" OR ")
|
6
6
|
adminarg = admins.nil? ? "-A admin" : "-A #{admins}"
|
7
|
-
|
7
|
+
sparseopt = sparse.nil? ? "" : "-K sparse"
|
8
|
+
run_simple "knife vault create #{vault} #{item} -z -c knife.rb #{adminarg} #{sparseopt} -S '#{query}' -J item.json", false
|
8
9
|
end
|
9
10
|
|
10
11
|
Given(/^I update the vault item '(.+)\/(.+)' to be encrypted for '(.+)'( with the clean option)?$/) do |vault, item, nodelist, cleanopt|
|
@@ -41,18 +42,28 @@ Given(/^I try to decrypt the vault item '(.+)\/(.+)' as '(.+)'$/) do |vault, ite
|
|
41
42
|
run_simple "knife vault show #{vault} #{item} -z -c knife.rb -u #{node} -k #{node}.pem", false
|
42
43
|
end
|
43
44
|
|
44
|
-
Then(/^the vault item '(.+)\/(.+)' should( not)? be encrypted for '(.+)'
|
45
|
+
Then(/^the vault item '(.+)\/(.+)' should( not)? be encrypted for '(.+)'( with keys in sparse mode)?$/) do |vault, item, neg, nodelist, sparse|
|
45
46
|
nodes = nodelist.split(/,/)
|
46
47
|
command = "knife data bag show #{vault} #{item}_keys -z -c knife.rb -F json"
|
47
48
|
run_simple(command)
|
48
49
|
output = last_command_started.stdout
|
49
50
|
data = JSON.parse(output)
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
51
|
+
if sparse
|
52
|
+
expect(data).to include("mode" => "sparse")
|
53
|
+
nodes.each do |node|
|
54
|
+
command = "knife data bag show #{vault} #{item}_key_#{node} -z -c knife.rb -F json"
|
55
|
+
run_simple(command, fail_on_error: false)
|
56
|
+
if neg
|
57
|
+
error = last_command_started.stderr
|
58
|
+
expect(error).to include("ERROR: The object you are looking for could not be found")
|
59
|
+
else
|
60
|
+
data = JSON.parse(last_command_started.stdout)
|
61
|
+
expect(data).to include("id" => "#{item}_key_#{node}")
|
62
|
+
end
|
55
63
|
end
|
64
|
+
else
|
65
|
+
expect(data).to include("mode" => "default")
|
66
|
+
nodes.each { |node| neg ? (expect(data).not_to include(node)) : (expect(data).to include(node)) }
|
56
67
|
end
|
57
68
|
end
|
58
69
|
|
@@ -46,6 +46,16 @@ Feature: knife vault create
|
|
46
46
|
And 'alice' should be an admin for the vault item 'test/item'
|
47
47
|
And 'bob' should not be an admin for the vault item 'test/item'
|
48
48
|
|
49
|
+
Scenario: create vault with several admins in sparse mode
|
50
|
+
Given a local mode chef repo with nodes 'one,two' with admins 'alice,bob'
|
51
|
+
And I create a vault item 'test/item' with keys in sparse mode containing the JSON '{"foo": "bar"}' encrypted for 'one,two,three' with 'alice' as admin
|
52
|
+
Then the vault item 'test/item' should be encrypted for 'one,two' with keys in sparse mode
|
53
|
+
And the vault item 'test/item' should not be encrypted for 'three' with keys in sparse mode
|
54
|
+
And 'one,two' should be a client for the vault item 'test/item'
|
55
|
+
And 'three' should not be a client for the vault item 'test/item'
|
56
|
+
And 'alice' should be an admin for the vault item 'test/item'
|
57
|
+
And 'bob' should not be an admin for the vault item 'test/item'
|
58
|
+
|
49
59
|
Scenario: create vault with an unknown admin
|
50
60
|
Given a local mode chef repo with nodes 'one,two'
|
51
61
|
And I create a vault item 'test/item' containing the JSON '{"foo": "bar"}' encrypted for 'one,two,three' with 'alice' as admin
|
data/features/vault_list.feature
CHANGED
@@ -10,6 +10,12 @@ Feature: list data bags that are vaults
|
|
10
10
|
And I list the vaults
|
11
11
|
Then the output should match /(?m:^test$)/
|
12
12
|
|
13
|
+
Scenario: List bags that are vaults with keys in sparse mode
|
14
|
+
Given a local mode chef repo with nodes 'one,two,three'
|
15
|
+
And I create a vault item 'test/item' with keys in sparse mode containing the JSON '{"foo": "bar"}' encrypted for 'one,two,three'
|
16
|
+
And I list the vaults
|
17
|
+
Then the output should match /(?m:^test$)/
|
18
|
+
|
13
19
|
Scenario: Skip data bags that are not vaults
|
14
20
|
Given a local mode chef repo with nodes 'one,two,three'
|
15
21
|
And I create a vault item 'test/item' containing the JSON '{"foo": "bar"}' encrypted for 'one,two,three'
|
data/lib/chef-vault/actor.rb
CHANGED
@@ -66,18 +66,16 @@ class ChefVault
|
|
66
66
|
end
|
67
67
|
|
68
68
|
def get_client_key
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
raise http_error
|
80
|
-
end
|
69
|
+
get_key("clients")
|
70
|
+
rescue Net::HTTPServerException => http_error
|
71
|
+
if http_error.response.code.eql?("403")
|
72
|
+
print_forbidden_error
|
73
|
+
raise http_error
|
74
|
+
elsif http_error.response.code.eql?("404")
|
75
|
+
raise ChefVault::Exceptions::ClientNotFound,
|
76
|
+
"#{name} is not a valid chef client and/or node"
|
77
|
+
else
|
78
|
+
raise http_error
|
81
79
|
end
|
82
80
|
end
|
83
81
|
|
data/lib/chef-vault/item_keys.rb
CHANGED
@@ -161,14 +161,23 @@ class ChefVault
|
|
161
161
|
|
162
162
|
def destroy
|
163
163
|
if Chef::Config[:solo_legacy_mode]
|
164
|
-
data_bag_path = File.join(Chef::Config[:data_bag_path],
|
165
|
-
data_bag)
|
164
|
+
data_bag_path = File.join(Chef::Config[:data_bag_path], data_bag)
|
166
165
|
data_bag_item_path = File.join(data_bag_path, @raw_data["id"])
|
167
|
-
|
166
|
+
data_bag_sparse_keys_path = File.join(data_bag_path, sparse_id("*"))
|
167
|
+
# destroy all sparse keys
|
168
|
+
FileUtils.rm(Dir.glob("#{data_bag_sparse_keys_path}.json"))
|
169
|
+
# destroy this metadata
|
168
170
|
FileUtils.rm("#{data_bag_item_path}.json")
|
169
|
-
|
170
171
|
nil
|
171
172
|
else
|
173
|
+
# destroy all sparse keys
|
174
|
+
rgx = Regexp.new("^#{sparse_id(".*")}")
|
175
|
+
items = Chef::DataBag.load(data_bag).keys.select { |item| item =~ rgx }
|
176
|
+
items.each do |id|
|
177
|
+
Chef::DataBagItem.from_hash("data_bag" => data_bag, "id" => id)
|
178
|
+
.destroy(data_bag, id)
|
179
|
+
end
|
180
|
+
# destroy this metadata
|
172
181
|
super(data_bag, id)
|
173
182
|
end
|
174
183
|
end
|
@@ -205,7 +214,7 @@ class ChefVault
|
|
205
214
|
# @private
|
206
215
|
|
207
216
|
def sparse_id(key, item_id = @raw_data["id"])
|
208
|
-
"#{item_id}_key_#{key}"
|
217
|
+
"#{item_id.chomp("_keys")}_key_#{key}"
|
209
218
|
end
|
210
219
|
|
211
220
|
def sparse_key(sid)
|
data/lib/chef-vault/version.rb
CHANGED
@@ -49,8 +49,12 @@ class Chef
|
|
49
49
|
|
50
50
|
def bag_is_vault?(bagname)
|
51
51
|
bag = Chef::DataBag.load(bagname)
|
52
|
-
#
|
53
|
-
|
52
|
+
# a data bag is a vault if and only if:
|
53
|
+
# - it has at least one item with item_keys
|
54
|
+
# - every item has a matching item_keys
|
55
|
+
# - item_keys has zero or more keys in sparse mode
|
56
|
+
# vaults have a number of keys >= 2
|
57
|
+
return false unless bag.keys.size >= 2
|
54
58
|
# partition into those that end in _keys
|
55
59
|
keylike, notkeylike = split_vault_keys(bag)
|
56
60
|
# there must be an equal number of keyline and not-keylike items
|
@@ -63,8 +67,15 @@ class Chef
|
|
63
67
|
end
|
64
68
|
|
65
69
|
def split_vault_keys(bag)
|
66
|
-
#
|
67
|
-
bag.keys.
|
70
|
+
# get all item keys
|
71
|
+
keys = bag.keys.select { |k| k =~ /_keys$/ }
|
72
|
+
# get all sparse keys
|
73
|
+
r = Regexp.union(keys.map { |k| Regexp.new("^#{k.chomp('_keys')}_key_.*") })
|
74
|
+
sparse = bag.keys.select { |k| k =~ r }
|
75
|
+
# the rest
|
76
|
+
items = bag.keys - keys - sparse
|
77
|
+
# return item keys and items
|
78
|
+
[keys, items]
|
68
79
|
end
|
69
80
|
end
|
70
81
|
end
|
@@ -26,6 +26,11 @@ class Chef
|
|
26
26
|
|
27
27
|
banner "knife vault create VAULT ITEM VALUES (options)"
|
28
28
|
|
29
|
+
option :keys_mode,
|
30
|
+
:short => "-K KEYS_MODE",
|
31
|
+
:long => "--keys-mode KEYS_MODE",
|
32
|
+
:description => "Mode in which to save vault keys"
|
33
|
+
|
29
34
|
option :search,
|
30
35
|
:short => "-S SEARCH",
|
31
36
|
:long => "--search SEARCH",
|
@@ -57,6 +62,7 @@ class Chef
|
|
57
62
|
search = config[:search]
|
58
63
|
json_file = config[:json]
|
59
64
|
file = config[:file]
|
65
|
+
keys_mode = config[:keys_mode]
|
60
66
|
|
61
67
|
set_mode(config[:vault_mode])
|
62
68
|
|
@@ -91,6 +97,7 @@ class Chef
|
|
91
97
|
vault_item.clients if search
|
92
98
|
vault_item.clients(clients) if clients
|
93
99
|
vault_item.admins(admins) if admins
|
100
|
+
vault_item.keys.mode(keys_mode) if keys_mode
|
94
101
|
|
95
102
|
vault_item.save
|
96
103
|
end
|
@@ -81,11 +81,8 @@ RSpec.describe ChefVault::ItemKeys do
|
|
81
81
|
|
82
82
|
describe "#save" do
|
83
83
|
let(:client_name) { "client_name" }
|
84
|
-
let(:chef_key)
|
85
|
-
|
86
|
-
before do
|
87
|
-
allow(chef_key).to receive(:key) { public_key_string }
|
88
|
-
end
|
84
|
+
let(:chef_key) { ChefVault::Actor.new("clients", client_name) }
|
85
|
+
before { allow(chef_key).to receive(:key) { public_key_string } }
|
89
86
|
|
90
87
|
it "should save the key data" do
|
91
88
|
keys.add(chef_key, shared_secret)
|
@@ -110,6 +107,29 @@ RSpec.describe ChefVault::ItemKeys do
|
|
110
107
|
keys.mode("default")
|
111
108
|
end
|
112
109
|
end
|
110
|
+
|
111
|
+
describe "#destroy" do
|
112
|
+
let(:client_name) { "client_name" }
|
113
|
+
let(:chef_key) { ChefVault::Actor.new("clients", client_name) }
|
114
|
+
before { allow(chef_key).to receive(:key) { public_key_string } }
|
115
|
+
|
116
|
+
it "should destroy the keys" do
|
117
|
+
keys.add(chef_key, shared_secret)
|
118
|
+
keys.save("bar")
|
119
|
+
keys.destroy
|
120
|
+
expect { Chef::DataBagItem.load("foo", "bar") }.to raise_error(Net::HTTPServerException)
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should destroy the keys in sparse mode" do
|
124
|
+
keys.add(chef_key, shared_secret)
|
125
|
+
keys.mode("sparse")
|
126
|
+
keys.save("bar")
|
127
|
+
keys.destroy
|
128
|
+
expect { Chef::DataBagItem.load("foo", "bar") }.to raise_error(Net::HTTPServerException)
|
129
|
+
expect { Chef::DataBagItem.load("foo", "bar_key_client_name") }.to raise_error(Net::HTTPServerException)
|
130
|
+
keys.mode("default")
|
131
|
+
end
|
132
|
+
end
|
113
133
|
end
|
114
134
|
|
115
135
|
context "when running with chef-solo" do
|
@@ -182,6 +202,34 @@ RSpec.describe ChefVault::ItemKeys do
|
|
182
202
|
keys.mode("default")
|
183
203
|
end
|
184
204
|
end
|
205
|
+
|
206
|
+
describe "#destroy" do
|
207
|
+
let(:client_name) { "client_name" }
|
208
|
+
let(:chef_key) { ChefVault::Actor.new("clients", client_name) }
|
209
|
+
let(:data_bag_path) { Dir.mktmpdir("vault_item_keys") }
|
210
|
+
|
211
|
+
before do
|
212
|
+
Chef::Config[:data_bag_path] = data_bag_path
|
213
|
+
allow(chef_key).to receive(:key) { public_key_string }
|
214
|
+
end
|
215
|
+
|
216
|
+
it "should destroy the keys" do
|
217
|
+
keys.add(chef_key, shared_secret)
|
218
|
+
keys.save("bar")
|
219
|
+
keys.destroy
|
220
|
+
expect(File.exist?(File.join(data_bag_path, "foo", "bar.json"))).to be(false)
|
221
|
+
end
|
222
|
+
|
223
|
+
it "should destroy the keys in sparse mode" do
|
224
|
+
keys.add(chef_key, shared_secret)
|
225
|
+
keys.mode("sparse")
|
226
|
+
keys.save("bar")
|
227
|
+
keys.destroy
|
228
|
+
expect(File.exist?(File.join(data_bag_path, "foo", "bar.json"))).to be(false)
|
229
|
+
expect(File.exist?(File.join(data_bag_path, "foo", "bar_key_client_name.json"))).to be(false)
|
230
|
+
keys.mode("default")
|
231
|
+
end
|
232
|
+
end
|
185
233
|
end
|
186
234
|
end
|
187
235
|
end
|
@@ -21,10 +21,9 @@ begin
|
|
21
21
|
require "github_changelog_generator/task"
|
22
22
|
|
23
23
|
GitHubChangelogGenerator::RakeTask.new :changelog do |config|
|
24
|
-
config.future_release = ChefVault::VERSION
|
25
|
-
config.
|
26
|
-
config.
|
27
|
-
config.exclude_labels = "duplicate,question,invalid,wontfix,no_changelog,Exclude From Changelog,Question,Discussion".split(",")
|
24
|
+
config.future_release = "v#{ChefVault::VERSION}"
|
25
|
+
config.max_issues = 0
|
26
|
+
config.add_issues_wo_labels = false
|
28
27
|
end
|
29
28
|
rescue LoadError
|
30
29
|
puts "github_changelog_generator is not available. gem install github_changelog_generator to generate changelogs"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chef-vault
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.0
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thom May
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-04-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -202,12 +202,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
202
202
|
version: 2.2.0
|
203
203
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
204
204
|
requirements:
|
205
|
-
- - "
|
205
|
+
- - ">="
|
206
206
|
- !ruby/object:Gem::Version
|
207
|
-
version:
|
207
|
+
version: '0'
|
208
208
|
requirements: []
|
209
209
|
rubyforge_project:
|
210
|
-
rubygems_version: 2.
|
210
|
+
rubygems_version: 2.6.11
|
211
211
|
signing_key:
|
212
212
|
specification_version: 4
|
213
213
|
summary: Data encryption support for Chef using data bags
|