chef-vault 3.0.0.rc2 → 3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a6dd267f10f94be45c16f2a088e476226b4b0cf5
4
- data.tar.gz: 27fc5a1ee95c7be2ad1af5f967d4bbda96427b6a
3
+ metadata.gz: 52a4a35874db5011ab58dc856935a50d9f5bd0b1
4
+ data.tar.gz: 3515ba7b52b188fe1851cd2a7d2585b8268f8a9a
5
5
  SHA512:
6
- metadata.gz: 9397b282b2497e73b1fef2cb86f09f84df98bc9333513cd4648767436e15138f9c9cee187c56854ee3e2197a61ee992e6cdd4f502145b89d194eb428c0ccb07c
7
- data.tar.gz: 6a978b6a18e4a1a4b4eb8e3ddd3ce48318126e3f152dd5080ee20e19993afece13540df9b33b9a64b6873b483876c9041653ba91739a64ca3d0bc94b632a4dfd
6
+ metadata.gz: dda2609409ba281e63da7dacf34063c9efc65e5ad50a0652f11a75d4f97a56346b32e5580cc853d64933e01ec3edddbe2e67b8b48690e6fecd08a7af9cafca6c
7
+ data.tar.gz: ce93841b5ecbd3176a1cc7b5c4ce04735fddcc6a7b7b70cb9739b61e53a40a84c884676dea5a75bb33930d8d50250da2e5d11caa784b80466c649c3b9a639f3d
@@ -1,7 +1,39 @@
1
1
  # Change Log
2
2
 
3
- ## [2.9.0](https://github.com/chef/chef-vault/tree/2.9.0) (2016-04-06)
4
- [Full Changelog](https://github.com/chef/chef-vault/compare/v2.8.0...2.9.0)
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
@@ -6,7 +6,7 @@ group :development do
6
6
  end
7
7
 
8
8
  group :changelog do
9
- gem "github_changelog_generator", "1.11.3"
9
+ gem "github_changelog_generator", git: "https://github.com/chef/github-changelog-generator"
10
10
  end
11
11
 
12
12
  gemspec
@@ -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
- run_simple "knife vault create #{vault} #{item} -z -c knife.rb #{adminarg} -S '#{query}' -J item.json", false
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 '(.+)'$/) do |vault, item, neg, nodelist|
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
- nodes.each do |node|
51
- if neg
52
- expect(data).not_to include(node)
53
- else
54
- expect(data).to include(node)
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
@@ -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'
@@ -66,18 +66,16 @@ class ChefVault
66
66
  end
67
67
 
68
68
  def get_client_key
69
- begin
70
- get_key("clients")
71
- rescue Net::HTTPServerException => http_error
72
- if http_error.response.code.eql?("403")
73
- print_forbidden_error
74
- raise http_error
75
- elsif http_error.response.code.eql?("404")
76
- raise ChefVault::Exceptions::ClientNotFound,
77
- "#{name} is not a valid chef client and/or node"
78
- else
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
 
@@ -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)
@@ -15,6 +15,6 @@
15
15
  # limitations under the License.
16
16
 
17
17
  class ChefVault
18
- VERSION = "3.0.0.rc2"
18
+ VERSION = "3.0.0"
19
19
  MAJOR, MINOR, TINY = VERSION.split(".")
20
20
  end
@@ -49,8 +49,12 @@ class Chef
49
49
 
50
50
  def bag_is_vault?(bagname)
51
51
  bag = Chef::DataBag.load(bagname)
52
- # vaults have at even number of keys >= 2
53
- return false unless bag.keys.size >= 2 && 0 == bag.keys.size % 2
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
- # partition into those that end in _keys
67
- bag.keys.partition { |k| k =~ /_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) { ChefVault::Actor.new("clients", client_name) }
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.enhancement_labels = "enhancement,Enhancement,New Feature,Feature".split(",")
26
- config.bug_labels = "bug,Bug,Improvement,Upstream Bug".split(",")
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.rc2
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: 2016-12-05 00:00:00.000000000 Z
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: 1.3.1
207
+ version: '0'
208
208
  requirements: []
209
209
  rubyforge_project:
210
- rubygems_version: 2.5.1
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