class Chef::EncryptedAttribute
Main EncryptedAttribute
class.
This class contains both static and instance level public methods. Internally, all work with {EncryptedMash} object instances.
# Class Methods
The *class methods* (or static methods) are normally used **from Chef
cookbooks**.
The attributes create with the class methods are encrypted **only for the local node** by default.
The static `*_on_node` methods can be used, although they have not been designed for this purpose (have not been tested).
They are # documented in the {Chef::EncryptedAttribute::API} class.
# Instance Methods
The *instance methods* are normally used **by other libraries or gems**. For example, the knife extensions included in this gem uses these methods.
The instance methods will grant encrypted attribute access **only to the remote node** by default.
Usually only the `_from_node/_on_node` instance methods will be used.
Constants
- VERSION
`chef-encrypted-attributes` gem version.
Public Class Methods
Chef::EncryptedAttribute
constructor.
@param c [Config, Hash] configuration to use.
# File lib/chef/encrypted_attribute.rb, line 76 def initialize(c = nil) config(c) end
Public Instance Methods
Sets or gets the encrypted attribute configuration.
Reads the default configuration from `Chef::Config`.
When setting using a {Chef::EncryptedAttribute::Config} class, all the configuration options will be replaced.
When setting using a Hash, only the provided keys will be replaced.
@param arg [Config, Hash] the configuration to set. @return [Config] the read or set configuration object.
# File lib/chef/encrypted_attribute.rb, line 92 def config(arg = nil) @config ||= EncryptedAttribute::Config.new( Chef::Config[:encrypted_attributes] ) @config.update!(arg) unless arg.nil? @config end
Creates an encrypted attribute from a Hash.
Only the **keys passed as parameter and the configured keys** will be able to decrypt the attribute, so beware of including your local key if you need to decrypt it in the future.
@param value [Hash, Array, String, Fixnum, …] the value to encrypt in
clear.
@param keys [String, OpenSSL::PKey::RSA] public keys that will be able to
decrypt the attribute.
@raise [ArgumentError] if user list is wrong. @return [EncryptedMash] encrypted attribute value. This is usually what is
saved in the node attributes.
@raise [UnacceptableEncryptedAttributeFormat] if encrypted attribute
format is wrong or does not exist.
@raise [UnsupportedEncryptedAttributeFormat] if encrypted attribute
format is not supported or unknown.
@raise [EncryptionFailure] if there are encryption errors. @raise [MessageAuthenticationFailure] if HMAC calculation error. @raise [InvalidPublicKey] if it is not a valid RSA public key. @raise [InvalidKey] if the RSA key format is wrong. @raise [InsufficientPrivileges] if you lack enough privileges to read
the keys from the Chef Server.
@raise [ClientNotFound] if client does not exist. @raise [Net::HTTPServerException] for Chef
Server HTTP errors. @raise [RequirementsFailure] if the specified encrypted attribute
version cannot be used.
@raise [SearchFailure] if there is a Chef
search error. @raise [SearchFatalError] if the Chef
search response is wrong. @raise [InvalidSearchKeys] if search keys structure is wrong.
# File lib/chef/encrypted_attribute.rb, line 170 def create(value, keys = nil) decrypted = { 'content' => value } enc_attr = EncryptedMash.create(config.version) enc_attr.encrypt(decrypted, target_keys(keys)) end
Creates an encrypted attribute on a remote node.
The remote node will always be able to decrypt it. The local node will not be able to decrypt it by default, you must remember to include the key in the configuration.
@param name [String] node name. @param attr_ary [Array<String>] node attribute path as Array. @param value [Hash, Array, String, Fixnum, …] the value to encrypt. @return [EncryptedMash] encrypted attribute value. @raise [ArgumentError] if the attribute path format or the user list is
wrong.
@raise [UnacceptableEncryptedAttributeFormat] if encrypted attribute
format is wrong or does not exist.
@raise [UnsupportedEncryptedAttributeFormat] if encrypted attribute
format is not supported or unknown.
@raise [EncryptionFailure] if there are encryption errors. @raise [MessageAuthenticationFailure] if HMAC calculation error. @raise [InvalidPublicKey] if it is not a valid RSA public key. @raise [InvalidKey] if the RSA key format is wrong. @raise [InsufficientPrivileges] if you lack enough privileges to read
the keys from the Chef Server.
@raise [ClientNotFound] if client does not exist. @raise [Net::HTTPServerException] for Chef
Server HTTP errors. @raise [RequirementsFailure] if the specified encrypted attribute
version cannot be used.
@raise [SearchFailure] if there is a Chef
search error. @raise [SearchFatalError] if the Chef
search response is wrong. @raise [InvalidSearchKeys] if search keys structure is wrong.
# File lib/chef/encrypted_attribute.rb, line 206 def create_on_node(name, attr_ary, value) # read the client public key node_public_key = RemoteClients.get_public_key(name) # create the encrypted attribute enc_attr = create(value, [node_public_key]) # save encrypted attribute remote_node = RemoteNode.new(name) remote_node.save_attribute(attr_ary, enc_attr) end
Decrypts an encrypted attribute from a local node attribute.
@param enc_hs [Mash] the encrypted hash as read from the node attributes. @param key [String, OpenSSL::PKey::RSA] private key to use in the
decryption process, uses the local node key by default.
@return [Hash, Array, String, …] decrypted attribute value. @raise [UnacceptableEncryptedAttributeFormat] if encrypted attribute
format is wrong.
@raise [UnsupportedEncryptedAttributeFormat] if encrypted attribute
format is not supported or unknown.
# File lib/chef/encrypted_attribute.rb, line 110 def load(enc_hs, key = nil) enc_attr = EncryptedMash.json_create(enc_hs) decrypted = enc_attr.decrypt(key || local_key) decrypted['content'] # TODO: check this Hash end
Decrypts a encrypted attribute from a remote node.
@param name [String] node name. @param attr_ary [Array<String>] node attribute path as Array. @param key [String, OpenSSL::PKey::RSA] private key to use in the
decryption process, uses the local key by default.
@return [Hash, Array, String, …] decrypted attribute value. @raise [ArgumentError] if the attribute path format is wrong. @raise [UnacceptableEncryptedAttributeFormat] if encrypted attribute
format is wrong.
@raise [UnsupportedEncryptedAttributeFormat] if encrypted attribute
format is not supported or unknown.
@raise [SearchFailure] if there is a Chef
search error. @raise [SearchFatalError] if the Chef
search response is wrong. @raise [InvalidSearchKeys] if search keys structure is wrong.
# File lib/chef/encrypted_attribute.rb, line 131 def load_from_node(name, attr_ary, key = nil) remote_node = RemoteNode.new(name) enc_hs = remote_node.load_attribute( attr_ary, config.search_max_rows, config.partial_search ) load(enc_hs, key) end
Updates the keys for which a local attribute is encrypted.
In case new keys are added or some keys are removed, the attribute will be re-created again.
Only the **keys passed as parameter and the configured keys** will be able to decrypt the attribute, so beware of including your local key if you need to decrypt it in the future.
Uses the local key to decrypt the attribute, so the local key should be able to read the attribute. At least before updating.
@param enc_hs [Mash] encrypted attribute. This parameter value will be
modified on updates.
@param keys [Array<String, OpenSSL::PKey::RSA> public keys that should be
able to read the attribute.
@return [Boolean] Returns `true` if the encrypted attribute (the Mash
parameter) has been updated.
@raise [ArgumentError] if user list is wrong. @raise [UnacceptableEncryptedAttributeFormat] if encrypted attribute
format is wrong or does not exist.
@raise [UnsupportedEncryptedAttributeFormat] if encrypted attribute
format is not supported or unknown.
@raise [EncryptionFailure] if there are encryption errors. @raise [MessageAuthenticationFailure] if HMAC calculation error. @raise [InvalidPublicKey] if it is not a valid RSA public key. @raise [InvalidKey] if the RSA key format is wrong. @raise [InsufficientPrivileges] if you lack enough privileges to read
the keys from the Chef Server.
@raise [ClientNotFound] if client does not exist. @raise [Net::HTTPServerException] for Chef
Server HTTP errors. @raise [RequirementsFailure] if the specified encrypted attribute
version cannot be used.
@raise [SearchFailure] if there is a Chef
search error. @raise [SearchFatalError] if the Chef
search response is wrong. @raise [InvalidSearchKeys] if search keys structure is wrong. @see config
# File lib/chef/encrypted_attribute.rb, line 255 def update(enc_hs, keys = nil) old_enc_attr = EncryptedMash.json_create(enc_hs) if old_enc_attr.needs_update?(target_keys(keys)) hs = old_enc_attr.decrypt(local_key) new_enc_attr = create(hs['content'], keys) # TODO: check this Hash enc_hs.replace(new_enc_attr) true else false end end
Updates the keys for which a remote attribute is encrypted.
In case new keys are added or some keys are removed, the attribute will be re-created again.
Only the **remote node and the configured keys** will be able to decrypt the attribute, so beware of including your local key if you need to decrypt it in the future.
Uses the local key to decrypt the attribute, so the local key should be able to read the attribute. At least before updating.
@param name [String] node name. @param attr_ary [Array<String>] node attribute path as Array. @return [Boolean] Returns `true` if the remote encrypted attribute has
been updated.
@raise [ArgumentError] if the attribute path format or the user list is
wrong.
@raise [UnacceptableEncryptedAttributeFormat] if encrypted attribute
format is wrong or does not exist.
@raise [UnsupportedEncryptedAttributeFormat] if encrypted attribute
format is not supported or unknown.
@raise [EncryptionFailure] if there are encryption errors. @raise [MessageAuthenticationFailure] if HMAC calculation error. @raise [InvalidPublicKey] if it is not a valid RSA public key. @raise [InvalidKey] if the RSA key format is wrong. @raise [InsufficientPrivileges] if you lack enough privileges to read
the keys from the Chef Server.
@raise [ClientNotFound] if client does not exist. @raise [Net::HTTPServerException] for Chef
Server HTTP errors. @raise [RequirementsFailure] if the specified encrypted attribute
version cannot be used.
@raise [SearchFailure] if there is a Chef
search error. @raise [SearchFatalError] if the Chef
search response is wrong. @raise [InvalidSearchKeys] if search keys structure is wrong. @see config
# File lib/chef/encrypted_attribute.rb, line 303 def update_on_node(name, attr_ary) # read the client public key node_public_key = RemoteClients.get_public_key(name) # update the encrypted attribute remote_node = RemoteNode.new(name) enc_hs = remote_node.load_attribute( attr_ary, config.search_max_rows, config.partial_search ) updated = update(enc_hs, [node_public_key]) # save encrypted attribute if updated # TODO: Node is accessed twice (RemoteNode#load_attribute above) remote_node.save_attribute(attr_ary, enc_hs) end updated end
Protected Instance Methods
Gets the local private key.
@return [OpenSSL::PKey::RSA.new] local private (and public) key object.
# File lib/chef/encrypted_attribute.rb, line 399 def local_key LocalNode.new.key end
Gets remote client public keys using the *client search* query included in the configuration.
@return [Array<String>] list of client public keys. @raise [ClientNotFound] if client does not exist. @raise [Net::HTTPServerException] for Chef
Server HTTP errors. @raise [SearchFailure] if there is a Chef
search error. @raise [SearchFatalError] if the Chef
search response is wrong. @raise [InvalidSearchKeys] if search keys structure is wrong. @see config
# File lib/chef/encrypted_attribute.rb, line 335 def remote_client_keys RemoteClients.search_public_keys( config.client_search, config.search_max_rows, config.partial_search ) end
Gets remote node public keys using the *node search* query included in the configuration.
@return [Array<String>] list of node public keys. @raise [InsufficientPrivileges] if you lack enough privileges to read
the keys from the Chef Server.
@raise [ClientNotFound] if client does not exist. @raise [Net::HTTPServerException] for Chef
Server HTTP errors. @raise [SearchFailure] if there is a Chef
search error. @raise [SearchFatalError] if the Chef
search response is wrong. @raise [InvalidSearchKeys] if search keys structure is wrong. @see config
# File lib/chef/encrypted_attribute.rb, line 353 def remote_node_keys RemoteNodes.search_public_keys( config.node_search, config.search_max_rows, config.partial_search ) end
Gets remote user keys using the configured user list.
@return [Array<String>] list of user public keys. @raise [ArgumentError] if user list is wrong. @see config
# File lib/chef/encrypted_attribute.rb, line 364 def remote_user_keys RemoteUsers.get_public_keys(config.users) end
Gets the public keys that should be able to read the attribute based on the configuration.
This includes keys passed as parameter, configured keys, remote_client_keys
, remote_node_keys
and remote_user_keys.
@param keys [Array<String>] list of public keys to include in addition to
the configured.
@return [Array<String>] list of user public keys. @raise [ArgumentError] if user list is wrong. @raise [InsufficientPrivileges] if you lack enough privileges to read
the keys from the Chef Server.
@raise [ClientNotFound] if client does not exist. @raise [Net::HTTPServerException] for Chef
Server HTTP errors. @raise [SearchFailure] if there is a Chef
search error. @raise [SearchFatalError] if the Chef
search response is wrong. @raise [InvalidSearchKeys] if search keys structure is wrong. @see config
@see remote_client_keys
@see remote_node_keys
@see remote_user_keys
# File lib/chef/encrypted_attribute.rb, line 389 def target_keys(keys = nil) target_keys = config.keys + remote_client_keys + remote_node_keys + remote_user_keys target_keys += keys if keys.is_a?(Array) target_keys end