chef-encrypted-attributes 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,521 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Author:: Xabier de Zuazo (<xabier@onddo.com>)
4
+ # Copyright:: Copyright (c) 2014 Onddo Labs, SL. (www.onddo.com)
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require 'chef/encrypted_attribute/config'
21
+ require 'chef/encrypted_attribute/encrypted_mash'
22
+ require 'chef/config'
23
+
24
+ require 'chef/encrypted_attribute/local_node'
25
+ require 'chef/encrypted_attribute/remote_node'
26
+ require 'chef/encrypted_attribute/encrypted_mash/version0'
27
+ require 'chef/encrypted_attribute/encrypted_mash/version1'
28
+ require 'chef/encrypted_attribute/encrypted_mash/version2'
29
+
30
+ class Chef
31
+ class EncryptedAttribute
32
+ # Main EncryptedAttribute class methods API module.
33
+ #
34
+ # All these methods are available as static methods in the
35
+ # {Chef::EncryptedAttribute} class.
36
+ #
37
+ # These methods are intended to be used from Chef
38
+ # [Recipes](http://docs.getchef.com/recipes.html) or
39
+ # [Resources](https://docs.getchef.com/resource.html).
40
+ #
41
+ # The attributes created by these methods are encrypted **only for the local
42
+ # node** by default.
43
+ #
44
+ # The static `*_on_node` methods can be used, although they have not been
45
+ # designed for this purpose (have not been tested).
46
+ #
47
+ # This module uses the {Chef::EncryptedAttribute} instance methods
48
+ # internally.
49
+ #
50
+ # # Configuration
51
+ #
52
+ # All the methods read the default configuration from the
53
+ # `Chef::Config[:encrypted_attributes]` hash. Most of methods also support
54
+ # setting some configuration parameters as last argument. Both the global
55
+ # and the method argument configuration will be merged.
56
+ #
57
+ # If the configuration value to be merged is an array or a hash (for example
58
+ # `keys`), the method argument configuration value has preference over the
59
+ # global configuration. arrays and hashes are not merged.
60
+ #
61
+ # Both `Chef::Config[:encrypted_attributes]` and method's `config` parameter
62
+ # should be a hash which may have any of the following keys:
63
+ #
64
+ # * `:version` - `EncryptedMash` format version to use, by default `1` is
65
+ # used which is recommended. The version `2` uses [GCM]
66
+ # (http://en.wikipedia.org/wiki/Galois/Counter_Mode) and probably should
67
+ # be considered the most secure, but it is disabled by default because it
68
+ # has some more requirements: Ruby `>= 2` and OpenSSL `>= 1.0.1`.
69
+ # * `:partial_search` - Whether to use Chef Server partial search, enabled
70
+ # by default. It may not work in some old versions of Chef Server.
71
+ # * `:client_search` - Search query for clients allowed to read the
72
+ # encrypted attribute. Can be a simple string or an array of queries to be
73
+ # *OR*-ed.
74
+ # * `:node_search` - Search query for nodes allowed to read the encrypted
75
+ # attribute. Can be a simple string or an array of queries to be *OR*-ed.
76
+ # * `:users` - Array of user names to be allowed to read the encrypted
77
+ # attribute(s). `"*"` to allow access to all users. Keep in mind that only
78
+ # admin clients or admin users are allowed to read user public keys. It is
79
+ # **not recommended** to use this from cookbooks unless you know what you
80
+ # are doing.
81
+ # * `:keys` - raw RSA public keys to be allowed to read encrypted
82
+ # attributes(s), in PEM (string) format. Can be client public keys, user
83
+ # public keys or any other RSA public key.
84
+ #
85
+ # @see Config
86
+ #
87
+ # For example, to disable Partial Search globally:
88
+ #
89
+ # ```ruby
90
+ # Chef::Config[:encrypted_attributes][:partial_search] = false
91
+ #
92
+ # # ftp_pass = Chef::EncryptedAttribute.load(node['myapp']['ftp_password'])
93
+ # # ...
94
+ # ```
95
+ #
96
+ # To disable Partial Search locally:
97
+ #
98
+ # ```ruby
99
+ # ftp_pass = Chef::EncryptedAttribute.load(
100
+ # node['myapp']['ftp_password'], { :partial_search => false }
101
+ # )
102
+ # ```
103
+ #
104
+ # To use protocol version 2 globally, which uses [GCM]
105
+ # (http://en.wikipedia.org/wiki/Galois/Counter_Mode):
106
+ #
107
+ # ```ruby
108
+ # Chef::Config[:encrypted_attributes][:version] = 2
109
+ # # ...
110
+ # ```
111
+ #
112
+ # If you want to use knife to work with encrypted attributes, surely you
113
+ # will need to save your Chef User public keys in a Data Bag (there is no
114
+ # need to encrypt them because they are public) and add them to the `:keys`
115
+ # configuration option. See the [Example Using User Keys Data Bag]
116
+ # (README.md#example-using-user-keys-data-bag) in the README for more
117
+ # information on this.
118
+ #
119
+ # # Caches
120
+ #
121
+ # This API uses some LRU caches to avoid making many requests to the Chef
122
+ # Server. All the caches are global and has the following methods:
123
+ #
124
+ # * `max_size` - Gets or sets the cache maximum item size.
125
+ # * `clear` - To empty the cache.
126
+ # * `[]` - To read a cache value (used internally).
127
+ # * `[]=` - To set a cache value (used internally).
128
+ #
129
+ # @see CacheLru
130
+ #
131
+ # This are the currently available caches:
132
+ #
133
+ # * `Chef::EncryptedAttribute::RemoteClients.cache` - Caches the
134
+ # `:client_search` query results (max_size: `1024`).
135
+ # * `Chef::EncryptedAttribute::RemoteNodes.cache` - Caches the
136
+ # `:node_search` query results (max_size: `1024`).
137
+ # * `Chef::EncryptedAttribute::RemoteUsers.cache` - Caches the Chef Users
138
+ # public keys (max_size: `1024`).
139
+ # * `Chef::EncryptedAttribute::RemoteNode.cache` - Caches the node
140
+ # (encrypted) attributes. Disabled by default (max_size: `0`).
141
+ #
142
+ # ### Clear All the Caches
143
+ #
144
+ # You can clear all the caches with the following code:
145
+ #
146
+ # ```ruby
147
+ # Chef::EncryptedAttribute::RemoteClients.cache.clear
148
+ # Chef::EncryptedAttribute::RemoteNodes.cache.clear
149
+ # Chef::EncryptedAttribute::RemoteUsers.cache.clear
150
+ # Chef::EncryptedAttribute::RemoteNode.cache.clear
151
+ # ```
152
+ #
153
+ # ### Disable All the Caches
154
+ #
155
+ # You can disable all the caches with the following code:
156
+ #
157
+ # ```ruby
158
+ # Chef::EncryptedAttribute::RemoteClients.cache.max_size(0)
159
+ # Chef::EncryptedAttribute::RemoteNodes.cache.max_size(0)
160
+ # Chef::EncryptedAttribute::RemoteUsers.cache.max_size(0)
161
+ # Chef::EncryptedAttribute::RemoteNode.cache.max_size(0)
162
+ # ```
163
+ #
164
+ # @see RemoteClients.cache
165
+ # @see RemoteNodes.cache
166
+ # @see RemoteUsers.cache
167
+ # @see RemoteNode.cache
168
+ module API
169
+ # Prints a Chef debug message.
170
+ #
171
+ # @param msg [String] message to print.
172
+ # @return void
173
+ # @api private
174
+ def debug(msg)
175
+ Chef::Log.debug("Chef::EncryptedAttribute: #{msg}")
176
+ end
177
+
178
+ # Prints a Chef warning message.
179
+ #
180
+ # @param msg [String] message to print.
181
+ # @return void
182
+ # @api private
183
+ def warn(msg)
184
+ Chef::Log.warn(msg)
185
+ end
186
+
187
+ # Gets local node object.
188
+ #
189
+ # @return [LocalNode] local node object.
190
+ # @api private
191
+ def local_node
192
+ LocalNode.new
193
+ end
194
+
195
+ # Creates a new {Config} object.
196
+ #
197
+ # Reads the default configuration from
198
+ # `Chef::Config[:encrypted_attributes]`.
199
+ #
200
+ # When the parameter is a {Chef::EncryptedAttribute::Config} class, all
201
+ # the configuration options will be replaced.
202
+ #
203
+ # When the parameter is a _Hash_, only the provided keys will be replaced.
204
+ #
205
+ # The local node public key will always be added to the provided
206
+ # configuration keys.
207
+ #
208
+ # @param arg [Config, Hash] the configuration to set.
209
+ # @return [Config] the read or set configuration object.
210
+ # @api private
211
+ def config(arg)
212
+ config =
213
+ EncryptedAttribute::Config.new(Chef::Config[:encrypted_attributes])
214
+ config.update!(arg)
215
+ config.keys(config.keys + [local_node.public_key])
216
+ config
217
+ end
218
+
219
+ # Reads an encrypted attribute from a hash, usually a node attribute.
220
+ #
221
+ # Uses the local private key to decrypt the attribute.
222
+ #
223
+ # An exception is thrown if the attribute cannot be decrypted or no
224
+ # encrypted attribute is found.
225
+ #
226
+ # @param enc_hs [Mash] an encrypted hash, usually a node attribute. For
227
+ # example: `node['myapp']['ftp_password']`.
228
+ # @param c [Config, Hash] a configuration hash. For example:
229
+ # `{ :partial_search => false }`.
230
+ # @return [Hash, Array, String, ...] the attribute in clear text,
231
+ # decrypted.
232
+ # @raise [UnacceptableEncryptedAttributeFormat] if encrypted attribute
233
+ # format is wrong.
234
+ # @raise [UnsupportedEncryptedAttributeFormat] if encrypted attribute
235
+ # format is not supported or unknown.
236
+ def load(enc_hs, c = {})
237
+ debug("Loading Local Encrypted Attribute from: #{enc_hs.inspect}")
238
+ enc_attr = EncryptedAttribute.new(config(c))
239
+ result = enc_attr.load(enc_hs)
240
+ debug('Local Encrypted Attribute loaded.')
241
+ result
242
+ end
243
+
244
+ # Reads an encrypted attribute from a remote node.
245
+ #
246
+ # Uses the local private key to decrypt the attribute.
247
+ #
248
+ # An exception is thrown if the attribute cannot be decrypted or no
249
+ # encrypted attribute is found.
250
+ #
251
+ # @param name [String] the node name.
252
+ # @param attr_ary [Array<String>] the attribute path as *array of
253
+ # strings*. For example: `%w(myapp ftp_password)`.
254
+ # @param c [Config, Hash] a configuration hash. For example:
255
+ # `{ :partial_search => false }`.
256
+ # @return [Hash, Array, String, ...] decrypted attribute value.
257
+ # @raise [ArgumentError] if the attribute path format is wrong.
258
+ # @raise [UnacceptableEncryptedAttributeFormat] if encrypted attribute
259
+ # format is wrong.
260
+ # @raise [UnsupportedEncryptedAttributeFormat] if encrypted attribute
261
+ # format is not supported or unknown.
262
+ # @raise [SearchFailure] if there is a Chef search error.
263
+ # @raise [SearchFatalError] if the Chef search response is wrong.
264
+ # @raise [InvalidSearchKeys] if search keys structure is wrong.
265
+ def load_from_node(name, attr_ary, c = {})
266
+ debug(
267
+ "Loading Remote Encrypted Attribute from #{name}: #{attr_ary.inspect}"
268
+ )
269
+ enc_attr = EncryptedAttribute.new(config(c))
270
+ result = enc_attr.load_from_node(name, attr_ary)
271
+ debug('Remote Encrypted Attribute loaded.')
272
+ result
273
+ end
274
+
275
+ # Creates an encrypted attribute.
276
+ #
277
+ # The returned value should be saved in a node attribute, like
278
+ # `node.normal[...] = Chef::EncryptedAttribute.create(...)`.
279
+ #
280
+ # The local node will always be able to decrypt the attribute.
281
+ #
282
+ # An exception is thrown if any error arises in the encryption process.
283
+ #
284
+ # @param value [Hash, Array, String, ...] the value to be encrypted. Can
285
+ # be a boolean, a number, a string, an array or a hash (the value will
286
+ # be converted to JSON internally).
287
+ # @param c [Config, Hash] a configuration hash. For example:
288
+ # `{ :client_search => "admin:true" }`.
289
+ # @return [EncryptedMash] encrypted attribute value. This is usually what
290
+ # is saved in the node attributes.
291
+ # @raise [ArgumentError] if user list is wrong.
292
+ # @raise [UnacceptableEncryptedAttributeFormat] if encrypted attribute
293
+ # format is wrong or does not exist.
294
+ # @raise [UnsupportedEncryptedAttributeFormat] if encrypted attribute
295
+ # format is not supported or unknown.
296
+ # @raise [EncryptionFailure] if there are encryption errors.
297
+ # @raise [MessageAuthenticationFailure] if HMAC calculation error.
298
+ # @raise [InvalidPublicKey] if it is not a valid RSA public key.
299
+ # @raise [InvalidKey] if the RSA key format is wrong.
300
+ # @raise [InsufficientPrivileges] if you lack enough privileges to read
301
+ # the keys from the Chef Server.
302
+ # @raise [ClientNotFound] if client does not exist.
303
+ # @raise [Net::HTTPServerException] for Chef Server HTTP errors.
304
+ # @raise [RequirementsFailure] if the specified encrypted attribute
305
+ # version cannot be used.
306
+ # @raise [SearchFailure] if there is a Chef search error.
307
+ # @raise [SearchFatalError] if the Chef search response is wrong.
308
+ # @raise [InvalidSearchKeys] if search keys structure is wrong.
309
+ def create(value, c = {})
310
+ debug('Creating Encrypted Attribute.')
311
+ enc_attr = EncryptedAttribute.new(config(c))
312
+ result = enc_attr.create(value)
313
+ debug('Encrypted Attribute created.')
314
+ result
315
+ end
316
+
317
+ # Creates an encrypted attribute on a remote node.
318
+ #
319
+ # Both the local node and the remote node will be able to decrypt the
320
+ # attribute.
321
+ #
322
+ # This method **requires admin privileges**. So in most cases, cannot be
323
+ # used from cookbooks.
324
+ #
325
+ # An exception is thrown if any error arises in the encryption process.
326
+ #
327
+ # @param name [String] the node name.
328
+ # @param attr_ary [Array<String>] the attribute path as *array of
329
+ # strings*. For example: `%w(myapp ftp_password)`.
330
+ # @param value [Hash, Array, String, Fixnum, ...] the value to be
331
+ # encrypted. Can be a boolean, a number, a string, an array or a hash
332
+ # (the value will be converted to JSON internally).
333
+ # @param c [Config, Hash] a configuration hash. For example:
334
+ # `{ :client_search => 'admin:true' }`.
335
+ # @return [EncryptedMash] encrypted attribute value.
336
+ # @raise [ArgumentError] if the attribute path format or the user list is
337
+ # wrong.
338
+ # @raise [UnacceptableEncryptedAttributeFormat] if encrypted attribute
339
+ # format is wrong or does not exist.
340
+ # @raise [UnsupportedEncryptedAttributeFormat] if encrypted attribute
341
+ # format is not supported or unknown.
342
+ # @raise [EncryptionFailure] if there are encryption errors.
343
+ # @raise [MessageAuthenticationFailure] if HMAC calculation error.
344
+ # @raise [InvalidPublicKey] if it is not a valid RSA public key.
345
+ # @raise [InvalidKey] if the RSA key format is wrong.
346
+ # @raise [InsufficientPrivileges] if you lack enough privileges to read
347
+ # the keys from the Chef Server.
348
+ # @raise [ClientNotFound] if client does not exist.
349
+ # @raise [Net::HTTPServerException] for Chef Server HTTP errors.
350
+ # @raise [RequirementsFailure] if the specified encrypted attribute
351
+ # version cannot be used.
352
+ # @raise [SearchFailure] if there is a Chef search error.
353
+ # @raise [SearchFatalError] if the Chef search response is wrong.
354
+ # @raise [InvalidSearchKeys] if search keys structure is wrong.
355
+ def create_on_node(name, attr_ary, value, c = {})
356
+ debug(
357
+ "Creating Remote Encrypted Attribute on #{name}: #{attr_ary.inspect}"
358
+ )
359
+ enc_attr = EncryptedAttribute.new(config(c))
360
+ result = enc_attr.create_on_node(name, attr_ary, value)
361
+ debug('Encrypted Remote Attribute created.')
362
+ result
363
+ end
364
+
365
+ # Updates who can read the attribute. This is intended to be used to
366
+ # update to the new nodes returned by `:client_search` and `:node_search`
367
+ # or perhaps global configuration changes.
368
+ #
369
+ # For example, in case new nodes are added or some are removed, and the
370
+ # clients returned by `:client_search` or `:node_search` are different,
371
+ # this `#update` method will decrypt the attribute and encrypt it again
372
+ # for the new nodes (or remove the old ones).
373
+ #
374
+ # If an update is made, the shared secrets are regenerated.
375
+ #
376
+ # Both the local node and the remote node will be able to decrypt the
377
+ # attribute.
378
+ #
379
+ # An exception is thrown if there is any error in the updating process.
380
+ #
381
+ # @param enc_hs [Mash] This must be a node encrypted attribute, this
382
+ # attribute will be updated, so it is mandatory to specify the type
383
+ # (usually `normal`). For example:
384
+ # `node.normal['myapp']['ftp_password']`.
385
+ # @param c [Config, Hash] a configuration hash. Surely you want this
386
+ # `#update` method to use the same `config` that the `#create` call.
387
+ # @return [Boolean] `true` if the encrypted attribute has been updated,
388
+ # `false` if not.
389
+ # @raise [ArgumentError] if user list is wrong.
390
+ # @raise [UnacceptableEncryptedAttributeFormat] if encrypted attribute
391
+ # format is wrong or does not exist.
392
+ # @raise [UnsupportedEncryptedAttributeFormat] if encrypted attribute
393
+ # format is not supported or unknown.
394
+ # @raise [EncryptionFailure] if there are encryption errors.
395
+ # @raise [MessageAuthenticationFailure] if HMAC calculation error.
396
+ # @raise [InvalidPublicKey] if it is not a valid RSA public key.
397
+ # @raise [InvalidKey] if the RSA key format is wrong.
398
+ # @raise [InsufficientPrivileges] if you lack enough privileges to read
399
+ # the keys from the Chef Server.
400
+ # @raise [ClientNotFound] if client does not exist.
401
+ # @raise [Net::HTTPServerException] for Chef Server HTTP errors.
402
+ # @raise [RequirementsFailure] if the specified encrypted attribute
403
+ # version cannot be used.
404
+ # @raise [SearchFailure] if there is a Chef search error.
405
+ # @raise [SearchFatalError] if the Chef search response is wrong.
406
+ # @raise [InvalidSearchKeys] if search keys structure is wrong.
407
+ def update(enc_hs, c = {})
408
+ debug("Updating Encrypted Attribute: #{enc_hs.inspect}")
409
+ enc_attr = EncryptedAttribute.new(config(c))
410
+ result = enc_attr.update(enc_hs)
411
+ if result
412
+ debug('Encrypted Attribute updated.')
413
+ else
414
+ debug('Encrypted Attribute not updated.')
415
+ end
416
+ result
417
+ end
418
+
419
+ # Updates who can decrypt the remote attribute.
420
+ #
421
+ # This method **requires admin privileges**. So in most cases, cannot be
422
+ # used from cookbooks.
423
+ #
424
+ # An exception is thrown if there is any error in the updating process.
425
+ #
426
+ # @param name [String] the node name.
427
+ # @param attr_ary [Array<String>] the attribute path as *array of
428
+ # strings*. For example: `%w(myapp ftp_password)`.
429
+ # @param c [Config, Hash] a configuration hash. Surely you want this
430
+ # `#update_on_node` method to use the same `config` that the `#create`
431
+ # call.
432
+ # @return [Boolean] `true` if the encrypted attribute has been updated,
433
+ # `false` if not.
434
+ # @raise [ArgumentError] if the attribute path format or the user list is
435
+ # wrong.
436
+ # @raise [UnacceptableEncryptedAttributeFormat] if encrypted attribute
437
+ # format is wrong or does not exist.
438
+ # @raise [UnsupportedEncryptedAttributeFormat] if encrypted attribute
439
+ # format is not supported or unknown.
440
+ # @raise [EncryptionFailure] if there are encryption errors.
441
+ # @raise [MessageAuthenticationFailure] if HMAC calculation error.
442
+ # @raise [InvalidPublicKey] if it is not a valid RSA public key.
443
+ # @raise [InvalidKey] if the RSA key format is wrong.
444
+ # @raise [InsufficientPrivileges] if you lack enough privileges to read
445
+ # the keys from the Chef Server.
446
+ # @raise [ClientNotFound] if client does not exist.
447
+ # @raise [Net::HTTPServerException] for Chef Server HTTP errors.
448
+ # @raise [RequirementsFailure] if the specified encrypted attribute
449
+ # version cannot be used.
450
+ # @raise [SearchFailure] if there is a Chef search error.
451
+ # @raise [SearchFatalError] if the Chef search response is wrong.
452
+ # @raise [InvalidSearchKeys] if search keys structure is wrong.
453
+ def update_on_node(name, attr_ary, c = {})
454
+ debug(
455
+ "Updating Remote Encrypted Attribute on #{name}: #{attr_ary.inspect}"
456
+ )
457
+ enc_attr = EncryptedAttribute.new(config(c))
458
+ result = enc_attr.update_on_node(name, attr_ary)
459
+ debug("Encrypted Remote Attribute #{result ? '' : 'not '}updated.")
460
+ result
461
+ end
462
+
463
+ # Checks whether an encrypted attribute exists.
464
+ #
465
+ # @param hs [Mash] an encrypted hash, usually a node attribute. The
466
+ # attribute type can be specified but is not necessary. For example:
467
+ # `node['myapp']['ftp_password']`.
468
+ # @return [Boolean] `true` if an encrypted attribute is found, `false` if
469
+ # not.
470
+ def exist?(hs)
471
+ debug("Checking if Encrypted Attribute exists here: #{hs.inspect}")
472
+ result = EncryptedMash.exist?(hs)
473
+ debug("Encrypted Attribute #{result ? '' : 'not '}found.")
474
+ result
475
+ end
476
+
477
+ # Checks whether an encrypted attribute exists in a remote node.
478
+ #
479
+ # @param [Mixed] args {#exist?} arguments.
480
+ # @return [Boolean] `true` if an encrypted attribute is found, `false` if
481
+ # not.
482
+ # @deprecated Use {#exist?} instead.
483
+ def exists?(*args)
484
+ warn("#{name}.exists? is deprecated in favor of #{name}.exist?.")
485
+ exist?(*args)
486
+ end
487
+
488
+ # Checks whether an encrypted attribute exists in a remote node.
489
+ #
490
+ # @param name [String] the node name.
491
+ # @param attr_ary [Array<String>] the attribute path as *array of
492
+ # strings*. For example: `%w(myapp ftp_password)`.
493
+ # @param c [Config, Hash] a configuration hash. For example:
494
+ # `{ :partial_search => false }`.
495
+ # @return [Boolean] `true` if an encrypted attribute is found, `false` if
496
+ # not.
497
+ # @raise [ArgumentError] if the attribute path format is wrong.
498
+ def exist_on_node?(name, attr_ary, c = {})
499
+ debug("Checking if Remote Encrypted Attribute exists on #{name}")
500
+ remote_node = RemoteNode.new(name)
501
+ node_attr =
502
+ remote_node.load_attribute(attr_ary, config(c).partial_search)
503
+ Chef::EncryptedAttribute.exist?(node_attr)
504
+ end
505
+
506
+ # Checks whether an encrypted attribute exists in a remote node.
507
+ #
508
+ # @param [Mixed] args {#exist_on_node?} arguments.
509
+ # @return [Boolean] `true` if an encrypted attribute is found, `false` if
510
+ # not.
511
+ # @deprecated Use {#exist_on_node?} instead.
512
+ def exists_on_node?(*args)
513
+ warn(
514
+ "#{name}.exists_on_node? is deprecated in favor of "\
515
+ "#{name}.exist_on_node?."
516
+ )
517
+ exist_on_node?(*args)
518
+ end
519
+ end
520
+ end
521
+ end