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 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