chef-vault 2.9.2 → 3.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -11
  3. data/Changelog.md +1 -6
  4. data/Gemfile +4 -5
  5. data/KNIFE_EXAMPLES.md +66 -14
  6. data/LICENSE +201 -177
  7. data/README.md +74 -4
  8. data/Rakefile +1 -1
  9. data/bin/chef-vault +3 -2
  10. data/chef-vault.gemspec +13 -15
  11. data/features/clean.feature +0 -1
  12. data/features/clean_on_refresh.feature +0 -1
  13. data/features/clean_unknown_clients.feature +0 -1
  14. data/features/detect_and_warn_v1_vault.feature +0 -1
  15. data/features/isvault.feature +0 -1
  16. data/features/itemtype.feature +0 -1
  17. data/features/vault_create.feature +1 -2
  18. data/features/vault_list.feature +0 -1
  19. data/features/vault_show.feature +0 -1
  20. data/features/vault_show_vaultname.feature +0 -1
  21. data/features/vault_update.feature +0 -1
  22. data/features/verify_id_matches.feature +0 -1
  23. data/features/wrong_private_key.feature +0 -1
  24. data/hooks/pre-commit +43 -0
  25. data/lib/chef-vault.rb +10 -2
  26. data/lib/chef-vault/actor.rb +149 -0
  27. data/lib/chef-vault/certificate.rb +1 -1
  28. data/lib/chef-vault/chef_api.rb +39 -0
  29. data/lib/chef-vault/item.rb +57 -71
  30. data/lib/chef-vault/item_keys.rb +14 -9
  31. data/lib/chef-vault/user.rb +1 -1
  32. data/lib/chef-vault/version.rb +1 -1
  33. data/lib/chef/knife/vault_base.rb +5 -2
  34. data/lib/chef/knife/{encrypt_delete.rb → vault_clients.rb} +6 -12
  35. data/lib/chef/knife/vault_create.rb +9 -1
  36. data/lib/chef/knife/vault_remove.rb +9 -1
  37. data/lib/chef/knife/vault_rotate_all_keys.rb +1 -1
  38. data/lib/chef/knife/vault_show.rb +4 -4
  39. data/lib/chef/knife/vault_update.rb +13 -5
  40. data/spec/chef-vault/actor_spec.rb +247 -0
  41. data/spec/chef-vault/certificate_spec.rb +2 -9
  42. data/spec/chef-vault/chef_api_spec.rb +39 -0
  43. data/spec/chef-vault/item_keys_spec.rb +52 -0
  44. data/spec/chef-vault/item_spec.rb +139 -85
  45. data/spec/chef-vault/user_spec.rb +2 -9
  46. data/spec/spec_helper.rb +1 -0
  47. metadata +36 -42
  48. data/CONTRIBUTING.md +0 -118
  49. data/lib/chef-vault/chef_patch/api_client.rb +0 -45
  50. data/lib/chef-vault/chef_patch/user.rb +0 -33
  51. data/lib/chef/knife/decrypt.rb +0 -32
  52. data/lib/chef/knife/encrypt_create.rb +0 -51
  53. data/lib/chef/knife/encrypt_remove.rb +0 -42
  54. data/lib/chef/knife/encrypt_rotate_keys.rb +0 -32
  55. data/lib/chef/knife/encrypt_update.rb +0 -51
  56. data/lib/chef/knife/mixin/compat.rb +0 -33
  57. data/lib/chef/knife/vault_decrypt.rb +0 -58
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Chef-Vault
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/chef-vault.png)](http://badge.fury.io/rb/chef-vault)
3
+ [![Gem Version](https://badge.fury.io/rb/chef-vault.svg)](http://badge.fury.io/rb/chef-vault)
4
4
 
5
- [![Build Status](https://travis-ci.org/chef/chef-vault.png?branch=master)](https://travis-ci.org/chef/chef-vault)
5
+ [![Build Status](https://travis-ci.org/chef/chef-vault.svg?branch=master)](https://travis-ci.org/chef/chef-vault)
6
6
 
7
7
  [![Inline docs](http://inch-ci.org/github/chef/chef-vault.svg?branch=master)](http://inch-ci.org/github/chef/chef-vault)
8
8
 
@@ -32,6 +32,69 @@ This plugin is distributed as a Ruby Gem. To install it, run:
32
32
  Depending on your system's configuration, you may need to run this command
33
33
  with root privileges.
34
34
 
35
+ ## DEVELOPMENT:
36
+
37
+ ### Git Hooks
38
+
39
+ There is a git pre-commit hook to help you keep your chefstyle up to date.
40
+ If you wish to use it, simply:
41
+
42
+ ```
43
+ mv hooks/pre-commit .git/hooks/
44
+ chmod +x .git/hooks/pre-commit
45
+ ```
46
+
47
+ ### Running Your Changes
48
+
49
+ To run your changes locally:
50
+
51
+ ```
52
+ bundle install
53
+ bundle exec knife vault
54
+ ```
55
+
56
+ ### Testing
57
+
58
+ #### Rspec Tests
59
+
60
+ There are some unit tests that can be run with:
61
+
62
+ ```
63
+ bundle exec rspec spec/
64
+ ```
65
+
66
+ #### Cucumber Testing
67
+
68
+ There are cucumber tests. Run the whole suite with:
69
+
70
+ ```
71
+ bundle exec rake features
72
+ ```
73
+
74
+ If you get any failures, you can run the specific feature that failed with:
75
+
76
+ ```
77
+ bundle exec cucumber features/<failed>.feature
78
+ ```
79
+
80
+ If you want to test things out directly, after a failure you can go into the test
81
+ directory and try out the commands that failed:
82
+
83
+ ```
84
+ cd tmp/aruba
85
+ bundle exec knife <your command that failed from test with -c knife.rb>
86
+ ```
87
+
88
+ Optionally add `-VV` to the above to get a full stacktrace.
89
+
90
+ ### Rubocop Errors
91
+
92
+ If you are seeing rubocop errors in travis for your pull request, run:
93
+
94
+ `bundle exec chefstyle -a`
95
+
96
+ This will fix up your rubocop errors automatically, and warn you about any it can't.
97
+
35
98
  ## KNIFE COMMANDS:
36
99
 
37
100
  See KNIFE_EXAMPLES.md for examples of commands
@@ -73,12 +136,14 @@ Short | Long | Description | Default | Valid Values | Sub-Commands
73
136
  ------|------|-------------|---------|--------------|-------------
74
137
  -M MODE | --mode MODE | Chef mode to run in. Can be set in knife.rb | solo | solo, client | all
75
138
  -S SEARCH | --search SEARCH | Chef Server SOLR Search Of Nodes | | | create, remove , update
139
+ -C CLIENTS | --clients CLIENTS | Chef clients to be added as clients, can be comma list | | | create, remove , update
76
140
  -A ADMINS | --admins ADMINS | Chef clients or users to be vault admins, can be comma list | | | create, remove, update
77
141
  -J FILE | --json FILE | JSON file to be used for values, will be merged with VALUES if VALUES is passed | | | create, update
78
142
  | --file FILE | File that chef-vault should encrypt. It adds "file-content" & "file-name" keys to the vault item | | | create, update
79
143
  -p DATA | --print DATA | Print extra vault data | | search, clients, admins, all | show
80
144
  -F FORMAT | --format FORMAT | Format for decrypted output | summary | summary, json, yaml, pp | show
81
145
  | --clean-unknown-clients | Remove unknown clients during key rotation | | | refresh, remove, rotate
146
+ | --clean | Clean clients list before performing search | | | refresh, update
82
147
 
83
148
  ## USAGE IN RECIPES
84
149
 
@@ -228,8 +293,9 @@ small pull requests are preferred to large omnibus patches, as the
228
293
  robustness pass is a multi-person effort and we don't want to create merge
229
294
  conflicts unnecessarily.
230
295
 
231
- We also have a [Gitter room](https://gitter.im/Nordstrom/chef-vault)
232
- where you can discuss chef-vault and the robustness improvements.
296
+ ## Contributing
297
+
298
+ For information on contributing to this project see <https://github.com/chef/chef/blob/master/CONTRIBUTING.md>
233
299
 
234
300
  ## Authors
235
301
 
@@ -238,6 +304,7 @@ Author:: Eli Klein - @eliklein<br>
238
304
  Author:: Joey Geiger - @jgeiger<br>
239
305
  Author:: Joshua Timberman - @jtimberman<br>
240
306
  Author:: James FitzGibbon - @jf647<br>
307
+ Author:: Thom May - @thommay<br>
241
308
 
242
309
  ## Contributors
243
310
 
@@ -248,8 +315,10 @@ Contributor:: Reto Hermann<br>
248
315
  ## License
249
316
 
250
317
  Copyright:: Copyright (c) 2013-15 Nordstrom, Inc.<br>
318
+ Copyright:: Copyright (c) 2016 Chef Software, Inc.<br>
251
319
  License:: Apache License, Version 2.0
252
320
 
321
+ ```text
253
322
  Licensed under the Apache License, Version 2.0 (the "License");
254
323
  you may not use this file except in compliance with the License.
255
324
  You may obtain a copy of the License at
@@ -261,3 +330,4 @@ distributed under the License is distributed on an "AS IS" BASIS,
261
330
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
262
331
  See the License for the specific language governing permissions and
263
332
  limitations under the License.
333
+ ```
data/Rakefile CHANGED
@@ -46,5 +46,5 @@ end
46
46
 
47
47
  # test or the default task runs spec, features, style
48
48
  desc "run all tests"
49
- task default: [:spec, :features, :style]
49
+ task default: [:coverage, :features, :style]
50
50
  task test: :default
@@ -86,12 +86,13 @@ require "rubygems"
86
86
  $:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
87
87
  require "chef-vault"
88
88
 
89
+ ChefVault::Log.init(STDOUT)
89
90
  ChefVault.load_config(options[:chef])
90
91
  item = ChefVault::Item.load(options[:vault], options[:item])
91
92
 
92
- $stdout.puts "#{options[:vault]}/#{options[:item]}"
93
+ ChefVault::Log.info "#{options[:vault]}/#{options[:item]}"
93
94
 
94
95
  options[:values].split(",").each do |value|
95
96
  value.strip! # remove white space
96
- $stdout.puts("\t#{value}: #{item[value]}")
97
+ ChefVault::Log.info ("\t#{value}: #{item[value]}")
97
98
  end
@@ -21,32 +21,30 @@ Gem::Specification.new do |s|
21
21
  s.name = "chef-vault"
22
22
  s.version = ChefVault::VERSION
23
23
  s.has_rdoc = true
24
- s.authors = ["Kevin Moser", "James FitzGibbon"]
25
- s.email = ["techcheftm@nordstrom.com"]
24
+ s.authors = ["Thom May"]
25
+ s.email = ["thom@chef.io"]
26
26
  s.summary = "Data encryption support for Chef using data bags"
27
27
  s.description = s.summary
28
28
  s.homepage = "https://github.com/chef/chef-vault"
29
-
30
29
  s.license = "Apache License, v2.0"
31
-
32
30
  s.files = `git ls-files`.split("\n")
33
31
  s.require_paths = ["lib"]
34
32
  s.bindir = "bin"
35
33
  s.executables = %w{ chef-vault }
36
34
 
37
- s.add_development_dependency "rake", "~> 10.4"
38
- s.add_development_dependency "rspec", "~> 3.2"
35
+ s.required_ruby_version = ">= 2.2.0"
36
+
37
+ s.add_development_dependency "rake", "~> 11.0"
38
+ s.add_development_dependency "rspec", "~> 3.4"
39
+ s.add_development_dependency "mutant-rspec"
39
40
  s.add_development_dependency "aruba", "~> 0.6"
40
41
  s.add_development_dependency "simplecov", "~> 0.9"
41
42
  s.add_development_dependency "simplecov-console", "~> 0.2"
42
- s.add_development_dependency "rubocop", "~> 0.30"
43
- # Chef 12 and higher pull in Ohai 8, which needs Ruby v2
44
- # so only in the case of a CI build on ruby v1, we constrain
45
- # chef to 11 or lower so that we can maintain CI test coverage
46
- # of older versions
47
- if ENV.key?("TRAVIS_BUILD") && RUBY_VERSION =~ /^1/
48
- s.add_development_dependency "chef", "~> 11.18"
49
- else
50
- s.add_development_dependency "chef", ">= 0.10.10"
43
+ if ENV.key?("TRAVIS_BUILD") && RUBY_VERSION == "2.1.9"
44
+ # Test version of Chef with Chef Zero before
45
+ # /orgs/org/users/user/keys endpoint was added.
46
+ s.add_development_dependency "chef", "12.8.1"
47
+ else # Test most current version of Chef on 2.2.2
48
+ s.add_dependency :chef, "~> 12"
51
49
  end
52
50
  end
@@ -1,5 +1,4 @@
1
1
  Feature: clean client keys
2
-
3
2
  When updating a vault item, chef-vault normally performs the
4
3
  saved or specified query and encrypts the item for all nodes
5
4
  returned. It does not remove old client keys from the vault
@@ -1,5 +1,4 @@
1
1
  Feature: clean unknown clients on vault refresh
2
-
3
2
  When refreshing a vault, new clients may be added if they match
4
3
  the search query or client list, but old clients that no longer
5
4
  exist will never be removed. The --clean-unknown-clients switch
@@ -1,5 +1,4 @@
1
1
  Feature: clean unknown clients on key rotation
2
-
3
2
  When removing a client from a vault item, chef-vault normally
4
3
  removes the key and then rotates the key. If a client has been
5
4
  deleted in the meantime from the Chef server but not the vault,
@@ -1,5 +1,4 @@
1
1
  Feature: Detect and Warn for v1 Vaults
2
-
3
2
  chef-vault can read a v1 vault, but the management commands
4
3
  tend to break when they try to reference v2 fields like
5
4
  clients and admins. They should detect and warn when trying
@@ -1,5 +1,4 @@
1
1
  Feature: determine if a data bag item is a vault
2
-
3
2
  If a data bag item is a vault, 'knife vault isvault VAULTNAME ITEMNAME'
4
3
  should exit 0. Otherwise it should exit 1.
5
4
 
@@ -1,5 +1,4 @@
1
1
  Feature: determine the type of a data bag item
2
-
3
2
  'knife vault itemtype VAULTNAME ITEMNAME' should output one of
4
3
  'normal', 'encrypted', or 'vault' depending on what type of item
5
4
  it detects
@@ -1,5 +1,4 @@
1
1
  Feature: knife vault create
2
-
3
2
  'knife vault create' creates two Chef data bag items: an
4
3
  encrypted data bag item encrypted with a randomized shared
5
4
  secret, and a side-along data bag item suffixed with _keys
@@ -51,4 +50,4 @@ Feature: knife vault create
51
50
  Given a local mode chef repo with nodes 'one,two'
52
51
  And I create a vault item 'test/item' containing the JSON '{"foo": "bar"}' encrypted for 'one,two,three' with 'alice' as admin
53
52
  Then the exit status should not be 0
54
- And the output should contain "FATAL: Could not find alice in users or clients!"
53
+ And the output should contain "FATAL: Could not find default key for alice in users or clients!"
@@ -1,5 +1,4 @@
1
1
  Feature: list data bags that are vaults
2
-
3
2
  knife vault list should list all data bags that appear to
4
3
  be vaults. This is not an exact science; we assume that
5
4
  any data bag containing an even number of items and for
@@ -1,5 +1,4 @@
1
1
  Feature: knife vault show
2
-
3
2
  'knife vault show' displays the contents of a Chef encrypted
4
3
  data bag by fetching the asymmetrically encrypted shared
5
4
  secret and decrypting it using the private key of the user
@@ -1,5 +1,4 @@
1
1
  Feature: knife vault show [VAULTNAME]
2
-
3
2
  'knife vault show [VAULTNAME]' displays the keys of a vault
4
3
  (i.e. the items that are not suffixed with _keys)
5
4
 
@@ -1,5 +1,4 @@
1
1
  Feature: knife vault update
2
-
3
2
  'knife vault update' is used to add clients, or administrators
4
3
  and to re-run the search query and update the vault's item values.
5
4
 
@@ -1,5 +1,4 @@
1
1
  Feature: knife vault create with mismatched ID
2
-
3
2
  'knife vault create' creates a vault. A JSON file can be passed
4
3
  on the command line. If the vault ID specified on the command line
5
4
  does not match the value of the 'id' key in the JSON file, knife
@@ -1,5 +1,4 @@
1
1
  Feature: Wrong private key during decrypt
2
-
3
2
  https://github.com/Nordstrom/chef-vault/issues/43
4
3
  If a vault is encrypted for a node and then the node's private
5
4
  key is regenerated, the error that comes back from chef-vault
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env ruby
2
+ output = `bundle exec chefstyle -a`
3
+ if !$?.success?
4
+ puts "pre-commit hook: Tried to run `bundle exec chefstyle -a` to autocleanup errors, but it failed with output:"
5
+ puts output
6
+ end
7
+
8
+ detected = /(\d+) offenses detected/.match(output)
9
+ corrected = /(\d+) offenses corrected/.match(output)
10
+
11
+ # no errors detected by chefstyle
12
+ exit 0 if detected.nil?
13
+
14
+ # chefstyle found errors
15
+ if !detected.nil?
16
+ # get the first result from the capture group that isn't the whole capture
17
+ num_detected = detected.to_a[1].to_i
18
+ num_corrected = if corrected.nil?
19
+ 0
20
+ else
21
+ corrected.to_a[1].to_i
22
+ end
23
+ if num_detected == num_corrected
24
+ puts <<EOF
25
+ pre-commit hook: Ran `bundle exec chefstyle -a` to autocleanup errors if any existed and
26
+ #{num_detected} were detected, but all were cleaned up. `git add` all files that were
27
+ autoupdated and try commiting again. New git status:
28
+
29
+ EOF
30
+ puts `git status`
31
+ else
32
+ puts <<EOF
33
+ pre-commit hook: Ran `bundle exec chefstyle -a` to autocleanup errors if any existed and
34
+ #{num_detected} were detected, but #{num_detected - num_corrected} could not be cleaned up
35
+ automatically. Run:
36
+
37
+ bundle exec chefstyle -a
38
+
39
+ to see remaining errors to clean up by hand, add all updated files, and try commiting again.
40
+ EOF
41
+ end
42
+ exit 1
43
+ end
@@ -29,8 +29,10 @@ require "chef-vault/item"
29
29
  require "chef-vault/item_keys"
30
30
  require "chef-vault/user"
31
31
  require "chef-vault/certificate"
32
- require "chef-vault/chef_patch/api_client"
33
- require "chef-vault/chef_patch/user"
32
+ require "chef-vault/chef_api"
33
+ require "chef-vault/actor"
34
+
35
+ require "mixlib/log"
34
36
 
35
37
  class ChefVault
36
38
  attr_accessor :vault
@@ -55,4 +57,10 @@ class ChefVault
55
57
  def self.load_config(chef_config_file)
56
58
  Chef::Config.from_file(chef_config_file)
57
59
  end
60
+
61
+ class Log
62
+ extend Mixlib::Log
63
+ end
64
+
65
+ Log.level = :error
58
66
  end
@@ -0,0 +1,149 @@
1
+ # Author:: Tyler Cloke <tyler@chef.io>
2
+ # Copyright:: Copyright 2016, Chef Software, Inc.
3
+ # License:: Apache License, Version 2.0
4
+
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require "json"
18
+
19
+ class ChefVault
20
+ class Actor
21
+
22
+ attr_accessor :key_string
23
+ attr_reader :type
24
+ attr_reader :name
25
+
26
+ def initialize(actor_type, actor_name)
27
+ if actor_type != "clients" && actor_type != "admins"
28
+ raise "You must pass either 'clients' or 'admins' as the first argument to ChefVault::Actor.new."
29
+ end
30
+ @type = actor_type
31
+ @name = actor_name
32
+ end
33
+
34
+ def key
35
+ @key ||= is_admin? ? get_admin_key : get_client_key
36
+ end
37
+
38
+ def get_admin_key
39
+ # chef vault currently only supports using the default key
40
+ get_key("users")
41
+ rescue Net::HTTPServerException => http_error
42
+ # if we failed to find an admin key, attempt to load a client key by the same name
43
+ case http_error.response.code
44
+ when "403"
45
+ print_forbidden_error
46
+ raise http_error
47
+ when "404"
48
+ begin
49
+ ChefVault::Log.warn "The default key for #{name} not found in users, trying client keys."
50
+ get_key("clients")
51
+ rescue Net::HTTPServerException => http_error
52
+ case http_error.response.code
53
+ when "404"
54
+ raise ChefVault::Exceptions::AdminNotFound,
55
+ "FATAL: Could not find default key for #{name} in users or clients!"
56
+ when "403"
57
+ print_forbidden_error
58
+ raise http_error
59
+ else
60
+ raise http_error
61
+ end
62
+ end
63
+ else
64
+ raise http_error
65
+ end
66
+ end
67
+
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
81
+ end
82
+ end
83
+
84
+ def is_client?
85
+ type == "clients"
86
+ end
87
+
88
+ def is_admin?
89
+ type == "admins"
90
+ end
91
+
92
+ # @private
93
+
94
+ def api
95
+ @api ||= ChefVault::ChefApi.new
96
+ end
97
+
98
+ # Use API V0 to load the public_key directly from the user object
99
+ # using the chef-client code.
100
+ def chef_api_client
101
+ @chef_api_client ||= begin
102
+ require "chef/api_client"
103
+ Chef::ApiClient
104
+ end
105
+ end
106
+
107
+ # Similar thing as above but for client.
108
+ def chef_user
109
+ @chef_user ||= begin
110
+ require "chef/user"
111
+ Chef::User
112
+ end
113
+ end
114
+
115
+ def get_key(request_actor_type)
116
+ api.org_scoped_rest_v1.get("#{request_actor_type}/#{name}/keys/default").fetch("public_key")
117
+ # If the keys endpoint doesn't exist, try getting it directly from the V0 chef object.
118
+ rescue Net::HTTPServerException => http_error
119
+ raise http_error unless http_error.response.code.eql?("404")
120
+ if request_actor_type.eql?("clients")
121
+ chef_api_client.load(name).public_key
122
+ else
123
+ chef_user.load(name).public_key
124
+ end
125
+ end
126
+
127
+ def print_forbidden_error
128
+ ChefVault::Log.error <<EOF
129
+ ERROR: You received a 403 FORBIDDEN while requesting an #{type} key for #{name}.
130
+
131
+ If you are on Chef Server < 12.5:
132
+ Clients do not have access to all public keys within their org.
133
+ Either upgrade to Chef Server >= 12.5 or make this request using a user.
134
+
135
+ If you are on Chef Server == 12.5.0
136
+ All clients and users have access to the public keys endpoint. Getting
137
+ this error on 12.5.0 is unexpected regardless of what your
138
+ public_key_read_access_group contains.
139
+
140
+ If you are on Chef Server > 12.5.1
141
+ Has your public_key_read_access_group been modified? This group controls
142
+ read access on public keys within your org. It defaults to the users
143
+ and client groups, so all org actors should have permission unless
144
+ the defaults have been changed.
145
+
146
+ EOF
147
+ end
148
+ end
149
+ end