chef-encrypted-attributes 0.3.0 → 0.4.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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.yardopts +8 -0
  5. data/CHANGELOG.md +40 -4
  6. data/CONTRIBUTING.md +7 -6
  7. data/KNIFE.md +151 -0
  8. data/README.md +70 -192
  9. data/Rakefile +27 -14
  10. data/TESTING.md +18 -7
  11. data/TODO.md +2 -5
  12. data/lib/chef-encrypted-attributes.rb +7 -1
  13. data/lib/chef/encrypted_attribute.rb +282 -121
  14. data/lib/chef/encrypted_attribute/api.rb +521 -0
  15. data/lib/chef/encrypted_attribute/assertions.rb +16 -6
  16. data/lib/chef/encrypted_attribute/cache_lru.rb +54 -13
  17. data/lib/chef/encrypted_attribute/config.rb +198 -89
  18. data/lib/chef/encrypted_attribute/encrypted_mash.rb +127 -33
  19. data/lib/chef/encrypted_attribute/encrypted_mash/version0.rb +236 -48
  20. data/lib/chef/encrypted_attribute/encrypted_mash/version1.rb +249 -36
  21. data/lib/chef/encrypted_attribute/encrypted_mash/version2.rb +133 -19
  22. data/lib/chef/encrypted_attribute/exceptions.rb +19 -3
  23. data/lib/chef/encrypted_attribute/local_node.rb +15 -4
  24. data/lib/chef/encrypted_attribute/remote_clients.rb +33 -17
  25. data/lib/chef/encrypted_attribute/remote_node.rb +84 -29
  26. data/lib/chef/encrypted_attribute/remote_nodes.rb +62 -11
  27. data/lib/chef/encrypted_attribute/remote_users.rb +58 -19
  28. data/lib/chef/encrypted_attribute/search_helper.rb +214 -74
  29. data/lib/chef/encrypted_attribute/version.rb +3 -1
  30. data/lib/chef/encrypted_attributes.rb +20 -0
  31. data/lib/chef/knife/core/config.rb +4 -1
  32. data/lib/chef/knife/core/encrypted_attribute_base.rb +179 -0
  33. data/lib/chef/knife/core/encrypted_attribute_depends.rb +43 -0
  34. data/lib/chef/knife/core/encrypted_attribute_editor_options.rb +125 -61
  35. data/lib/chef/knife/encrypted_attribute_create.rb +51 -31
  36. data/lib/chef/knife/encrypted_attribute_delete.rb +32 -40
  37. data/lib/chef/knife/encrypted_attribute_edit.rb +51 -32
  38. data/lib/chef/knife/encrypted_attribute_show.rb +30 -55
  39. data/lib/chef/knife/encrypted_attribute_update.rb +43 -28
  40. data/spec/benchmark_helper.rb +2 -1
  41. data/spec/integration_helper.rb +1 -0
  42. data/spec/spec_helper.rb +21 -7
  43. metadata +75 -36
  44. metadata.gz.sig +1 -1
  45. data/API.md +0 -174
  46. data/INTERNAL.md +0 -166
data/Rakefile CHANGED
@@ -1,5 +1,8 @@
1
- #!/usr/bin/env rake
2
- # encoding: utf-8
1
+ # encoding: UTF-8
2
+ # -*- mode: ruby -*-
3
+ # vi: set ft=ruby :
4
+
5
+ # More info at https://github.com/jimweirich/rake/blob/master/doc/rakefile.rdoc
3
6
 
4
7
  #
5
8
  # Author:: Xabier de Zuazo (<xabier@onddo.com>)
@@ -24,23 +27,33 @@ Bundler::GemHelper.install_tasks
24
27
 
25
28
  require 'rake/testtask'
26
29
 
30
+ desc 'Run RuboCop style checks'
31
+ task :rubocop do
32
+ require 'rubocop/rake_task'
33
+ RuboCop::RakeTask.new
34
+ end
35
+
36
+ desc 'Run all style checks'
37
+ task style: %w(rubocop)
38
+
27
39
  {
28
- :test => '{unit,integration}',
29
- :unit => 'unit',
30
- :integration => 'integration',
31
- :benchmark => 'benchmark',
40
+ test: '{unit,integration}',
41
+ unit: 'unit',
42
+ integration: 'integration',
43
+ benchmark: 'benchmark'
32
44
  }.each do |test, dir|
33
- Rake::TestTask.new(test) do |test|
34
- test.libs << 'lib' << 'spec'
35
- test.pattern = "spec/#{dir}/**/*.rb"
36
- test.verbose = true
45
+ Rake::TestTask.new(test) do |t|
46
+ t.libs << 'lib' << 'spec'
47
+ t.pattern = "spec/#{dir}/**/*.rb"
48
+ t.verbose = true
37
49
  end
38
50
  end
39
51
 
40
52
  if RUBY_VERSION < '1.9.3'
41
- # integration tests are broken in 1.9.2 due to a chef-zero bug
42
- # https://github.com/opscode/chef-zero/issues/65
43
- task :default => :unit
53
+ # Integration tests are broken in 1.9.2 due to a chef-zero bug:
54
+ # https://github.com/opscode/chef-zero/issues/65
55
+ # RuboCop require Ruby 1.9.3.
56
+ task default: %w(unit)
44
57
  else
45
- task :default => :test
58
+ task default: %w(style test)
46
59
  end
data/TESTING.md CHANGED
@@ -1,22 +1,33 @@
1
1
  # Testing
2
2
 
3
+ ## Installing the Requirements
4
+
5
+ You can install gem dependencies with bundler:
6
+
7
+ $ gem install bundler
8
+ $ bundler install
9
+
3
10
  ## All the Tests
4
11
 
5
- $ rake test
12
+ $ bundle exec rake test
13
+
14
+ ## Running the Syntax Style Tests
15
+
16
+ $ bundle exec rake style
6
17
 
7
- ## Unit Tests
18
+ ## Running the Unit Tests
8
19
 
9
- $ rake unit
20
+ $ bundle exec rake unit
10
21
 
11
- ## Integration Tests
22
+ ## Running the Integration Tests
12
23
 
13
- $ rake integration
24
+ $ bundle exec rake integration
14
25
 
15
- ## Benchmarks
26
+ ## Running the Benchmarks
16
27
 
17
28
  You can run some simple benchmarks, not at all realistic:
18
29
 
19
- $ rspec spec/benchmark/*
30
+ $ bundle exec rspec spec/benchmark/*
20
31
  user system total real
21
32
  Local EncryptedAttribute read (v=0) 0.410000 0.000000 0.410000 ( 0.417956)
22
33
  Local EncryptedAttribute read (v=1) 0.390000 0.010000 0.400000 ( 0.398934)
data/TODO.md CHANGED
@@ -1,20 +1,17 @@
1
1
  TODO
2
2
  ====
3
3
 
4
+ * Fix all RuboCop offenses.
4
5
  * knife encrypted attribute create/edit from file.
5
6
  * Save config inside encrypted data: `:client_search`, `:node_search` and `:keys` (including user keys).
6
7
  * Chef internal node attribute integration monkey-patch. It may require some `EncryptedMash` class rewrite or adding some methods.
7
8
  * Support for Chef `< 11.4` (add `JSONCompat#map_to_rb_obj`, disable `Chef::User` for `< 11.2`, ...).
8
- * Test with Chef `10`.
9
- * Add Ruby `1.8` support?
10
- * Document the Ruby code.
11
9
  * Add more info/debug prints.
12
10
  * Space-optimized `EncryptedMash::Version3` class.
13
11
  * Tests: Add test helper functions (key generation, ApiClients including priv keys, Node creation...).
14
12
  * Tests: Add more tests for `EncryptedMash::Version1` and `EncryptedMash::Version2`.
15
13
  * Tests: Add unit tests for `EncryptedAttribute`.
16
14
  * Tests: Add unit tests for all knife commands.
17
- * Tests: Tests `raise_error` always include regex.
18
- * Tests: Review and clean some tests.
15
+ * Tests: `raise_error` tests always include regex.
19
16
  * Add `chef-vault` to benchmarks.
20
17
  * Signed attributes?
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  #
2
3
  # Author:: Xabier de Zuazo (<xabier@onddo.com>)
3
4
  # Copyright:: Copyright (c) 2014 Onddo Labs, SL. (www.onddo.com)
@@ -16,4 +17,9 @@
16
17
  # limitations under the License.
17
18
  #
18
19
 
19
- require 'chef/encrypted_attribute'
20
+ warn(
21
+ '[DEPRECATION] The required "chef-encrypted-attributes" file has been moved '\
22
+ 'to "chef/encrypted_attributes" and will be removed in a future release. '\
23
+ 'Please switch to "chef/encrypted_attributes" as soon as possible.'
24
+ )
25
+ require 'chef/encrypted_attributes'
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  #
2
3
  # Author:: Xabier de Zuazo (<xabier@onddo.com>)
3
4
  # Copyright:: Copyright (c) 2014 Onddo Labs, SL. (www.onddo.com)
@@ -21,6 +22,7 @@ require 'chef/encrypted_attribute/encrypted_mash'
21
22
  require 'chef/config'
22
23
  require 'chef/mash'
23
24
 
25
+ require 'chef/encrypted_attribute/api'
24
26
  require 'chef/encrypted_attribute/local_node'
25
27
  require 'chef/encrypted_attribute/remote_node'
26
28
  require 'chef/encrypted_attribute/remote_nodes'
@@ -30,60 +32,227 @@ require 'chef/encrypted_attribute/encrypted_mash/version0'
30
32
  require 'chef/encrypted_attribute/encrypted_mash/version1'
31
33
  require 'chef/encrypted_attribute/encrypted_mash/version2'
32
34
 
33
- Chef::Config[:encrypted_attributes] = Mash.new unless Chef::Config[:encrypted_attributes].kind_of?(Hash)
35
+ unless Chef::Config[:encrypted_attributes].is_a?(Hash)
36
+ Chef::Config[:encrypted_attributes] = Mash.new
37
+ end
34
38
 
35
39
  class Chef
40
+ # Main EncryptedAttribute class.
41
+ #
42
+ # This class contains both static and instance level public methods.
43
+ # Internally, all work with {EncryptedMash} object instances.
44
+ #
45
+ # # Class Methods
46
+ #
47
+ # The *class methods* (or static methods) are normally used **from Chef
48
+ # cookbooks**.
49
+ #
50
+ # The attributes create with the class methods are encrypted **only for the
51
+ # local node** by default.
52
+ #
53
+ # The static `*_on_node` methods can be used, although they have not been
54
+ # designed for this purpose (have not been tested).
55
+ #
56
+ # They are # documented in the {Chef::EncryptedAttribute::API} class.
57
+ #
58
+ # # Instance Methods
59
+ #
60
+ # The *instance methods* are normally used **by other libraries or gems**. For
61
+ # example, the knife extensions included in this gem uses these methods.
62
+ #
63
+ # The instance methods will grant encrypted attribute access **only to the
64
+ # remote node** by default.
65
+ #
66
+ # Usually only the `*_from_node/*_on_node` instance methods will be used.
67
+ #
68
+ # @see EncryptedAttribute::API
36
69
  class EncryptedAttribute
70
+ # Include the *class methods* for the recipe API.
71
+ extend Chef::EncryptedAttribute::API
37
72
 
38
- def initialize(c=nil)
73
+ # Chef::EncryptedAttribute constructor.
74
+ #
75
+ # @param c [Config, Hash] configuration to use.
76
+ def initialize(c = nil)
39
77
  config(c)
40
78
  end
41
79
 
42
- def config(arg=nil)
43
- @config ||= EncryptedAttribute::Config.new(Chef::Config[:encrypted_attributes])
80
+ # Sets or gets the encrypted attribute configuration.
81
+ #
82
+ # Reads the default configuration from
83
+ # `Chef::Config[:encrypted_attributes]`.
84
+ #
85
+ # When setting using a {Chef::EncryptedAttribute::Config} class, all the
86
+ # configuration options will be replaced.
87
+ #
88
+ # When setting using a _Hash_, only the provided keys will be replaced.
89
+ #
90
+ # @param arg [Config, Hash] the configuration to set.
91
+ # @return [Config] the read or set configuration object.
92
+ def config(arg = nil)
93
+ @config ||= EncryptedAttribute::Config.new(
94
+ Chef::Config[:encrypted_attributes]
95
+ )
44
96
  @config.update!(arg) unless arg.nil?
45
97
  @config
46
98
  end
47
99
 
48
- # Decrypts an encrypted attribute from a (encrypted) Hash
49
- def load(enc_hs, key=nil)
100
+ # Decrypts an encrypted attribute from a local node attribute.
101
+ #
102
+ # @param enc_hs [Mash] the encrypted hash as read from the node attributes.
103
+ # @param key [String, OpenSSL::PKey::RSA] private key to use in the
104
+ # decryption process, uses the local node key by default.
105
+ # @return [Hash, Array, String, ...] decrypted attribute value.
106
+ # @raise [UnacceptableEncryptedAttributeFormat] if encrypted attribute
107
+ # format is wrong.
108
+ # @raise [UnsupportedEncryptedAttributeFormat] if encrypted attribute
109
+ # format is not supported or unknown.
110
+ def load(enc_hs, key = nil)
50
111
  enc_attr = EncryptedMash.json_create(enc_hs)
51
112
  decrypted = enc_attr.decrypt(key || local_key)
52
- decrypted['content'] # TODO check this Hash
113
+ decrypted['content'] # TODO: check this Hash
53
114
  end
54
115
 
55
- # Decrypts a encrypted attribute from a remote node
56
- def load_from_node(name, attr_ary, key=nil)
116
+ # Decrypts a encrypted attribute from a remote node.
117
+ #
118
+ # @param name [String] node name.
119
+ # @param attr_ary [Array<String>] node attribute path as Array.
120
+ # @param key [String, OpenSSL::PKey::RSA] private key to use in the
121
+ # decryption process, uses the local key by default.
122
+ # @return [Hash, Array, String, ...] decrypted attribute value.
123
+ # @raise [ArgumentError] if the attribute path format is wrong.
124
+ # @raise [UnacceptableEncryptedAttributeFormat] if encrypted attribute
125
+ # format is wrong.
126
+ # @raise [UnsupportedEncryptedAttributeFormat] if encrypted attribute
127
+ # format is not supported or unknown.
128
+ # @raise [SearchFailure] if there is a Chef search error.
129
+ # @raise [SearchFatalError] if the Chef search response is wrong.
130
+ # @raise [InvalidSearchKeys] if search keys structure is wrong.
131
+ def load_from_node(name, attr_ary, key = nil)
57
132
  remote_node = RemoteNode.new(name)
58
- self.load(remote_node.load_attribute(attr_ary, config.partial_search), key)
133
+ load(remote_node.load_attribute(attr_ary, config.partial_search), key)
59
134
  end
60
135
 
61
- # Creates an encrypted attribute from a Hash
62
- def create(value, keys=nil)
136
+ # Creates an encrypted attribute from a Hash.
137
+ #
138
+ # Only the **keys passed as parameter and the configured keys** will be able
139
+ # to decrypt the attribute, so beware of including your local key if you
140
+ # need to decrypt it in the future.
141
+ #
142
+ # @param value [Hash, Array, String, Fixnum, ...] the value to encrypt in
143
+ # clear.
144
+ # @param keys [String, OpenSSL::PKey::RSA] public keys that will be able to
145
+ # decrypt the attribute.
146
+ # @raise [ArgumentError] if user list is wrong.
147
+ # @return [EncryptedMash] encrypted attribute value. This is usually what is
148
+ # saved in the node attributes.
149
+ # @raise [UnacceptableEncryptedAttributeFormat] if encrypted attribute
150
+ # format is wrong or does not exist.
151
+ # @raise [UnsupportedEncryptedAttributeFormat] if encrypted attribute
152
+ # format is not supported or unknown.
153
+ # @raise [EncryptionFailure] if there are encryption errors.
154
+ # @raise [MessageAuthenticationFailure] if HMAC calculation error.
155
+ # @raise [InvalidPublicKey] if it is not a valid RSA public key.
156
+ # @raise [InvalidKey] if the RSA key format is wrong.
157
+ # @raise [InsufficientPrivileges] if you lack enough privileges to read
158
+ # the keys from the Chef Server.
159
+ # @raise [ClientNotFound] if client does not exist.
160
+ # @raise [Net::HTTPServerException] for Chef Server HTTP errors.
161
+ # @raise [RequirementsFailure] if the specified encrypted attribute
162
+ # version cannot be used.
163
+ # @raise [SearchFailure] if there is a Chef search error.
164
+ # @raise [SearchFatalError] if the Chef search response is wrong.
165
+ # @raise [InvalidSearchKeys] if search keys structure is wrong.
166
+ def create(value, keys = nil)
63
167
  decrypted = { 'content' => value }
64
168
 
65
169
  enc_attr = EncryptedMash.create(config.version)
66
170
  enc_attr.encrypt(decrypted, target_keys(keys))
67
171
  end
68
172
 
173
+ # Creates an encrypted attribute on a remote node.
174
+ #
175
+ # The remote node will always be able to decrypt it. The local node will
176
+ # not be able to decrypt it by default, you must remember to include the key
177
+ # in the configuration.
178
+ #
179
+ # @param name [String] node name.
180
+ # @param attr_ary [Array<String>] node attribute path as Array.
181
+ # @param value [Hash, Array, String, Fixnum, ...] the value to encrypt.
182
+ # @return [EncryptedMash] encrypted attribute value.
183
+ # @raise [ArgumentError] if the attribute path format or the user list is
184
+ # wrong.
185
+ # @raise [UnacceptableEncryptedAttributeFormat] if encrypted attribute
186
+ # format is wrong or does not exist.
187
+ # @raise [UnsupportedEncryptedAttributeFormat] if encrypted attribute
188
+ # format is not supported or unknown.
189
+ # @raise [EncryptionFailure] if there are encryption errors.
190
+ # @raise [MessageAuthenticationFailure] if HMAC calculation error.
191
+ # @raise [InvalidPublicKey] if it is not a valid RSA public key.
192
+ # @raise [InvalidKey] if the RSA key format is wrong.
193
+ # @raise [InsufficientPrivileges] if you lack enough privileges to read
194
+ # the keys from the Chef Server.
195
+ # @raise [ClientNotFound] if client does not exist.
196
+ # @raise [Net::HTTPServerException] for Chef Server HTTP errors.
197
+ # @raise [RequirementsFailure] if the specified encrypted attribute
198
+ # version cannot be used.
199
+ # @raise [SearchFailure] if there is a Chef search error.
200
+ # @raise [SearchFatalError] if the Chef search response is wrong.
201
+ # @raise [InvalidSearchKeys] if search keys structure is wrong.
69
202
  def create_on_node(name, attr_ary, value)
70
203
  # read the client public key
71
204
  node_public_key = RemoteClients.get_public_key(name)
72
205
 
73
206
  # create the encrypted attribute
74
- enc_attr = self.create(value, [ node_public_key ])
207
+ enc_attr = create(value, [node_public_key])
75
208
 
76
209
  # save encrypted attribute
77
210
  remote_node = RemoteNode.new(name)
78
211
  remote_node.save_attribute(attr_ary, enc_attr)
79
212
  end
80
213
 
81
- # Updates the keys for which the attribute is encrypted
82
- def update(enc_hs, keys=nil)
214
+ # Updates the keys for which a local attribute is encrypted.
215
+ #
216
+ # In case new keys are added or some keys are removed, the attribute will
217
+ # be re-created again.
218
+ #
219
+ # Only the **keys passed as parameter and the configured keys** will be able
220
+ # to decrypt the attribute, so beware of including your local key if you
221
+ # need to decrypt it in the future.
222
+ #
223
+ # Uses the local key to decrypt the attribute, so the local key should be
224
+ # able to read the attribute. At least before updating.
225
+ #
226
+ # @param enc_hs [Mash] encrypted attribute. This parameter value will be
227
+ # modified on updates.
228
+ # @param keys [Array<String, OpenSSL::PKey::RSA> public keys that should be
229
+ # able to read the attribute.
230
+ # @return [Boolean] Returns `true` if the encrypted attribute (the *Mash*
231
+ # parameter) has been updated.
232
+ # @raise [ArgumentError] if user list is wrong.
233
+ # @raise [UnacceptableEncryptedAttributeFormat] if encrypted attribute
234
+ # format is wrong or does not exist.
235
+ # @raise [UnsupportedEncryptedAttributeFormat] if encrypted attribute
236
+ # format is not supported or unknown.
237
+ # @raise [EncryptionFailure] if there are encryption errors.
238
+ # @raise [MessageAuthenticationFailure] if HMAC calculation error.
239
+ # @raise [InvalidPublicKey] if it is not a valid RSA public key.
240
+ # @raise [InvalidKey] if the RSA key format is wrong.
241
+ # @raise [InsufficientPrivileges] if you lack enough privileges to read
242
+ # the keys from the Chef Server.
243
+ # @raise [ClientNotFound] if client does not exist.
244
+ # @raise [Net::HTTPServerException] for Chef Server HTTP errors.
245
+ # @raise [RequirementsFailure] if the specified encrypted attribute
246
+ # version cannot be used.
247
+ # @raise [SearchFailure] if there is a Chef search error.
248
+ # @raise [SearchFatalError] if the Chef search response is wrong.
249
+ # @raise [InvalidSearchKeys] if search keys structure is wrong.
250
+ # @see #config
251
+ def update(enc_hs, keys = nil)
83
252
  old_enc_attr = EncryptedMash.json_create(enc_hs)
84
253
  if old_enc_attr.needs_update?(target_keys(keys))
85
254
  hs = old_enc_attr.decrypt(local_key)
86
- new_enc_attr = create(hs['content'], keys) # TODO check this Hash
255
+ new_enc_attr = create(hs['content'], keys) # TODO: check this Hash
87
256
  enc_hs.replace(new_enc_attr)
88
257
  true
89
258
  else
@@ -91,6 +260,42 @@ class Chef
91
260
  end
92
261
  end
93
262
 
263
+ # Updates the keys for which a remote attribute is encrypted.
264
+ #
265
+ # In case new keys are added or some keys are removed, the attribute will
266
+ # be re-created again.
267
+ #
268
+ # Only the **remote node and the configured keys** will be able to decrypt
269
+ # the attribute, so beware of including your local key if you need to
270
+ # decrypt it in the future.
271
+ #
272
+ # Uses the local key to decrypt the attribute, so the local key should be
273
+ # able to read the attribute. At least before updating.
274
+ #
275
+ # @param name [String] node name.
276
+ # @param attr_ary [Array<String>] node attribute path as Array.
277
+ # @return [Boolean] Returns `true` if the remote encrypted attribute has
278
+ # been updated.
279
+ # @raise [ArgumentError] if the attribute path format or the user list is
280
+ # wrong.
281
+ # @raise [UnacceptableEncryptedAttributeFormat] if encrypted attribute
282
+ # format is wrong or does not exist.
283
+ # @raise [UnsupportedEncryptedAttributeFormat] if encrypted attribute
284
+ # format is not supported or unknown.
285
+ # @raise [EncryptionFailure] if there are encryption errors.
286
+ # @raise [MessageAuthenticationFailure] if HMAC calculation error.
287
+ # @raise [InvalidPublicKey] if it is not a valid RSA public key.
288
+ # @raise [InvalidKey] if the RSA key format is wrong.
289
+ # @raise [InsufficientPrivileges] if you lack enough privileges to read
290
+ # the keys from the Chef Server.
291
+ # @raise [ClientNotFound] if client does not exist.
292
+ # @raise [Net::HTTPServerException] for Chef Server HTTP errors.
293
+ # @raise [RequirementsFailure] if the specified encrypted attribute
294
+ # version cannot be used.
295
+ # @raise [SearchFailure] if there is a Chef search error.
296
+ # @raise [SearchFatalError] if the Chef search response is wrong.
297
+ # @raise [InvalidSearchKeys] if search keys structure is wrong.
298
+ # @see #config
94
299
  def update_on_node(name, attr_ary)
95
300
  # read the client public key
96
301
  node_public_key = RemoteClients.get_public_key(name)
@@ -98,11 +303,11 @@ class Chef
98
303
  # update the encrypted attribute
99
304
  remote_node = RemoteNode.new(name)
100
305
  enc_hs = remote_node.load_attribute(attr_ary, config.partial_search)
101
- updated = update(enc_hs, [ node_public_key ])
306
+ updated = update(enc_hs, [node_public_key])
102
307
 
103
308
  # save encrypted attribute
104
309
  if updated
105
- # TODO Node is accessed twice (here and RemoteNode#load_attribute above)
310
+ # TODO: Node is accessed twice (RemoteNode#load_attribute above)
106
311
  remote_node.save_attribute(attr_ary, enc_hs)
107
312
  end
108
313
  updated
@@ -110,124 +315,80 @@ class Chef
110
315
 
111
316
  protected
112
317
 
318
+ # Gets remote client public keys using the *client search* query included in
319
+ # the configuration.
320
+ #
321
+ # @return [Array<String>] list of client public keys.
322
+ # @raise [ClientNotFound] if client does not exist.
323
+ # @raise [Net::HTTPServerException] for Chef Server HTTP errors.
324
+ # @raise [SearchFailure] if there is a Chef search error.
325
+ # @raise [SearchFatalError] if the Chef search response is wrong.
326
+ # @raise [InvalidSearchKeys] if search keys structure is wrong.
327
+ # @see #config
113
328
  def remote_client_keys
114
- RemoteClients.search_public_keys(config.client_search, config.partial_search)
329
+ RemoteClients.search_public_keys(
330
+ config.client_search, config.partial_search
331
+ )
115
332
  end
116
333
 
334
+ # Gets remote node public keys using the *node search* query included in the
335
+ # configuration.
336
+ #
337
+ # @return [Array<String>] list of node public keys.
338
+ # @raise [InsufficientPrivileges] if you lack enough privileges to read
339
+ # the keys from the Chef Server.
340
+ # @raise [ClientNotFound] if client does not exist.
341
+ # @raise [Net::HTTPServerException] for Chef Server HTTP errors.
342
+ # @raise [SearchFailure] if there is a Chef search error.
343
+ # @raise [SearchFatalError] if the Chef search response is wrong.
344
+ # @raise [InvalidSearchKeys] if search keys structure is wrong.
345
+ # @see #config
117
346
  def remote_node_keys
118
347
  RemoteNodes.search_public_keys(config.node_search, config.partial_search)
119
348
  end
120
349
 
350
+ # Gets remote user keys using the configured user list.
351
+ #
352
+ # @return [Array<String>] list of user public keys.
353
+ # @raise [ArgumentError] if user list is wrong.
354
+ # @see #config
121
355
  def remote_user_keys
122
356
  RemoteUsers.get_public_keys(config.users)
123
357
  end
124
358
 
125
- def target_keys(keys=nil)
126
- target_keys = config.keys + remote_client_keys + remote_node_keys + remote_user_keys
127
- target_keys += keys if keys.kind_of?(Array)
359
+ # Gets the public keys that should be able to read the attribute based on
360
+ # the configuration.
361
+ #
362
+ # This includes keys passed as parameter, configured keys,
363
+ # #remote_client_keys, #remote_node_keys and remote_user_keys.
364
+ #
365
+ # @param keys [Array<String>] list of public keys to include in addition to
366
+ # the configured.
367
+ # @return [Array<String>] list of user public keys.
368
+ # @raise [ArgumentError] if user list is wrong.
369
+ # @raise [InsufficientPrivileges] if you lack enough privileges to read
370
+ # the keys from the Chef Server.
371
+ # @raise [ClientNotFound] if client does not exist.
372
+ # @raise [Net::HTTPServerException] for Chef Server HTTP errors.
373
+ # @raise [SearchFailure] if there is a Chef search error.
374
+ # @raise [SearchFatalError] if the Chef search response is wrong.
375
+ # @raise [InvalidSearchKeys] if search keys structure is wrong.
376
+ # @see #config
377
+ # @see #remote_client_keys
378
+ # @see #remote_node_keys
379
+ # @see #remote_user_keys
380
+ def target_keys(keys = nil)
381
+ target_keys =
382
+ config.keys + remote_client_keys + remote_node_keys + remote_user_keys
383
+ target_keys += keys if keys.is_a?(Array)
128
384
  target_keys
129
385
  end
130
386
 
387
+ # Gets the local private key.
388
+ #
389
+ # @return [OpenSSL::PKey::RSA.new] local private (and public) key object.
131
390
  def local_key
132
- self.class.local_node.key
133
- end
134
-
135
- def self.local_node
136
- LocalNode.new
137
- end
138
-
139
- def self.config(arg)
140
- config = EncryptedAttribute::Config.new(Chef::Config[:encrypted_attributes])
141
- config.update!(arg)
142
- config.keys(config.keys + [ self.local_node.public_key ])
143
- config
144
- end
145
-
146
- public
147
-
148
- def self.load(hs, c={})
149
- Chef::Log.debug("#{self.class.name}: Loading Local Encrypted Attribute from: #{hs.to_s}")
150
- enc_attr = EncryptedAttribute.new(self.config(c))
151
- result = enc_attr.load(hs)
152
- Chef::Log.debug("#{self.class.name}: Local Encrypted Attribute loaded.")
153
- result
154
- end
155
-
156
- def self.load_from_node(name, attr_ary, c={})
157
- Chef::Log.debug("#{self.class.name}: Loading Remote Encrypted Attribute from #{name}: #{attr_ary.to_s}")
158
- enc_attr = EncryptedAttribute.new(self.config(c))
159
- result = enc_attr.load_from_node(name, attr_ary)
160
- Chef::Log.debug("#{self.class.name}: Remote Encrypted Attribute loaded.")
161
- result
162
- end
163
-
164
- def self.create(value, c={})
165
- Chef::Log.debug("#{self.class.name}: Creating Encrypted Attribute.")
166
- enc_attr = EncryptedAttribute.new(self.config(c))
167
- result = enc_attr.create(value)
168
- Chef::Log.debug("#{self.class.name}: Encrypted Attribute created.")
169
- result
170
- end
171
-
172
- def self.create_on_node(name, attr_ary, value, c={})
173
- Chef::Log.debug("#{self.class.name}: Creating Remote Encrypted Attribute on #{name}: #{attr_ary.to_s}")
174
- enc_attr = EncryptedAttribute.new(self.config(c))
175
- result = enc_attr.create_on_node(name, attr_ary, value)
176
- Chef::Log.debug("#{self.class.name}: Encrypted Remote Attribute created.")
177
- result
178
- end
179
-
180
- def self.update(hs, c={})
181
- Chef::Log.debug("#{self.class.name}: Updating Encrypted Attribute: #{hs.to_s}")
182
- enc_attr = EncryptedAttribute.new(self.config(c))
183
- result = enc_attr.update(hs)
184
- if result
185
- Chef::Log.debug("#{self.class.name}: Encrypted Attribute updated.")
186
- else
187
- Chef::Log.debug("#{self.class.name}: Encrypted Attribute not updated.")
188
- end
189
- result
190
- end
191
-
192
- def self.update_on_node(name, attr_ary, c={})
193
- Chef::Log.debug("#{self.class.name}: Updating Remote Encrypted Attribute on #{name}: #{attr_ary.to_s}")
194
- enc_attr = EncryptedAttribute.new(self.config(c))
195
- result = enc_attr.update_on_node(name, attr_ary)
196
- if result
197
- Chef::Log.debug("#{self.class.name}: Encrypted Remote Attribute updated.")
198
- else
199
- Chef::Log.debug("#{self.class.name}: Encrypted Remote Attribute not updated.")
200
- end
201
- result
202
- end
203
-
204
- def self.exist?(hs)
205
- Chef::Log.debug("#{self.class.name}: Checking if Encrypted Attribute exists here: #{hs.to_s}")
206
- result = EncryptedMash.exist?(hs)
207
- if result
208
- Chef::Log.debug("#{self.class.name}: Encrypted Attribute found.")
209
- else
210
- Chef::Log.debug("#{self.class.name}: Encrypted Attribute not found.")
211
- end
212
- result
391
+ LocalNode.new.key
213
392
  end
214
-
215
- def self.exists?(*args)
216
- Chef::Log.warn("#{self.name}.exists? is deprecated in favor of #{self.name}.exist?.")
217
- exist?(*args)
218
- end
219
-
220
- def self.exist_on_node?(name, attr_ary, c={})
221
- Chef::Log.debug("#{self.class.name}: Checking if Remote Encrypted Attribute exists on #{name}")
222
- remote_node = RemoteNode.new(name)
223
- node_attr = remote_node.load_attribute(attr_ary, self.config(c).partial_search)
224
- Chef::EncryptedAttribute.exist?(node_attr)
225
- end
226
-
227
- def self.exists_on_node?(*args)
228
- Chef::Log.warn("#{self.name}.exists_on_node? is deprecated in favor of #{self.name}.exist_on_node?.")
229
- exist_on_node?(*args)
230
- end
231
-
232
393
  end
233
394
  end