Module: Chef::EncryptedAttributesHelpers

Defined in:
libraries/encrypted_attributes_helpers.rb

Overview

Encrypted Attribute Helpers to use from Chef Recipes and Resources.

This library adds some helper methods to try to cover the more common use cases.

Automatically includes the required gems (chef-encrypted-attributes), so you do not have to worry about them.

Also tries to simulate encrypted attributes creation (using unencrypted attributes instead) in some testing environments:

  • With Chef Solo.
  • When node['dev_mode'] is set to true.

You must explicitly include the library before using it from recipes or resources:

include_recipe 'encrypted_attributes'
self.class.send(:include, Chef::EncryptedAttributesHelpers)

Chef::EncryptedAttributesHelpers Example

Here a simple example to save a password encrypted:

include_recipe 'encrypted_attributes'
self.class.send(:include, Chef::EncryptedAttributesHelpers)

# Allow all admin clients and webapp nodes to read the attributes encrypted
# by me
encrypted_attributes_allow_clients('admin:true')
encrypted_attributes_allow_nodes('role:webapp')

ftp_pass = encrypted_attribute_write(%w(myapp ftp_password)) do
  self.class.send(:include, Opscode::OpenSSL::Password)
  secure_password
end

You can then read the attribute as follows:

ftp_pass = encrypted_attribute_read(%w(myapp ftp_password))

Or read it from a remote node:

# Make the Client Public Key public in the node attributes
include_recipe 'encrypted_attributes::expose_key'

# Install the chef-encrypted_attributes gem
include_recipe 'encrypted_attributes'

# Include the helper libraries
self.class.send(:include, Chef::EncryptedAttributesHelpers)

# Read the encrypted attribute using the helpers
ftp_pass = encrypted_attribute_read_from_node(
  'myapp.example.com', %w(myapp ftp_password)
)

Enable Encrypted Attributes From an Attribute

If you want to enable or disable encrypted attributes based on a node attribute value, you can use the #encrypted_attributes_enabled= method:

# Enable encrypted attributes by default
node.default['myapp']['encrypt_attributes'] = true
# [...]

self.encrypted_attributes_enabled = node['myapp']['encrypt_attributes']

Include the encrypted_attributes Cookbook

Don't forget to include the encrypted_attributes cookbook as a dependency in the metadata:

# metadata.rb
[...]

depends 'encrypted_attributes'

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#encrypted_attributes_enabled=(value) ⇒ Object (writeonly)

Sets whether encrypted attributes are enabled underneath. This class attribute allows you to explicitly enable or disable encrypted attributes. This attribute value is calculated by default.

Examples:

# Enable encrypted attributes
self.encrypted_attributes_enabled = true
# Enable or disable encrypted attributes from a node attribute
self.encrypted_attributes_enabled = node['myapp']['encrypt_attributes']

Parameters:

  • value (Boolean)

    whether to enable encrypted attributes.



126
127
128
# File 'libraries/encrypted_attributes_helpers.rb', line 126

def encrypted_attributes_enabled=(value)
  @encrypted_attributes_enabled = value
end

Instance Method Details

#encrypted_attribute_read(attr_ary) ⇒ Mixed

Reads an encrypted attribute.

Examples:

# Read the FTP password
encrypted_attribute_read(%w(ftp password)) #=> 'q73C3LwzRxz9BT8d9rJa'

Parameters:

  • attr_ary (Array<String>)

    node attribute path as array of strings.

Returns:

  • (Mixed)

    the attribute value unencrypted.



411
412
413
414
# File 'libraries/encrypted_attributes_helpers.rb', line 411

def encrypted_attribute_read(attr_ary)
  attr_r = attr_get_from_ary(attr_ary)
  encrypted_attribute_load(attr_r)
end

#encrypted_attribute_read_from_node(node, attr_ary) ⇒ Mixed

Reads an encrypted attribute from a remote node.

Examples:

# Read the FTP password from the FTP server
encrypted_attribute_read_from_node('ftp.example.com', %w(ftp password))
  #=> 'q73C3LwzRxz9BT8d9rJa'

Parameters:

  • node (String)

    node name.

  • attr_ary (Array<String>)

    node attribute path as array of strings.

Returns:

  • (Mixed)

    the attribute value unencrypted.



426
427
428
# File 'libraries/encrypted_attributes_helpers.rb', line 426

def encrypted_attribute_read_from_node(node, attr_ary)
  encrypted_attribute_load_from_node(node, attr_ary)
end

#encrypted_attribute_write(attr_ary) { ... } ⇒ Mixed

Creates and writes an encrypted attribute.

The attribute will be written only on first run and updated on the next runs. Because of this, the attribute value has to be set as a block, and the block will be run only the first time.

Examples:

# Create an encrypted attribute containing the FTP password
unencrypted_pass = encrypted_attribute_write(%w(ftp password)) do
  self.class.send(:include, Opscode::OpenSSL::Password)
  secure_password
end

Parameters:

  • attr_ary (Array<String>)

    node attribute path as array of strings.

Yields:

  • [] the attribute value generator block.

Returns:

  • (Mixed)

    the attribute value unencrypted, that is, the value returned by the block.



447
448
449
450
451
452
453
454
455
456
457
458
# File 'libraries/encrypted_attributes_helpers.rb', line 447

def encrypted_attribute_write(attr_ary, &block)
  attr_r = attr_get_from_ary(attr_ary)
  if encrypted_attribute_exist?(attr_r)
    attr_w = attr_writable_from_ary(attr_ary)
    encrypted_attribute_update(attr_w)
    encrypted_attribute_load(attr_r)
  else
    value = block.call
    attr_set_from_ary(attr_ary, encrypted_attribute_create(value))
    value
  end
end

#encrypted_attributes_allow_clients(search) ⇒ String+

Allows some Chef Clients to read my encrypted attributes.

This method must be called before encrypting the attributes. Attributes encrypted before in the Chef Run will not be readable by these clients.

Examples:

# Allow all admins to decrypt the attribute
encrypted_attributes_allow_clients(%w(admin:true)) #=> %w(admin:true)

Parameters:

  • search (String, Array<String>)

    list of client search queries to perform. Query results will be OR-ed if you provide multiple searches.

Returns:

  • (String, Array<String>)

    the passed search argument.



472
473
474
# File 'libraries/encrypted_attributes_helpers.rb', line 472

def encrypted_attributes_allow_clients(search)
  config_set(:client_search, search)
end

#encrypted_attributes_allow_nodes(search) ⇒ String+

Allows some Chef Nodes to read my encrypted attributes.

This method must be called before encrypting the attributes. Attributes encrypted before in the Chef Run will not be readable by these nodes.

Examples:

# Allow webapp and backup servers to read decrypt the attribute
encrypted_attributes_allow_nodes(%w(role:webapp role:backup))
  #=> %w(role:webapp role:backup)

Parameters:

  • search (String, Array<String>)

    list of node search queries to perform. Query results will be OR-ed if you provide multiple searches.

Returns:

  • (String, Array<String>)

    the passed search argument.



489
490
491
# File 'libraries/encrypted_attributes_helpers.rb', line 489

def encrypted_attributes_allow_nodes(search)
  config_set(:node_search, search)
end

#encrypted_attributes_disableFalseClass

Disables encrypted attributes.

Examples:

self.encrypted_attributes_disable

Returns:

  • (FalseClass)

    always false.



399
400
401
# File 'libraries/encrypted_attributes_helpers.rb', line 399

def encrypted_attributes_disable
  @encrypted_attributes_enabled = false
end

#encrypted_attributes_enabled?Boolean

Whether encrypted attributes are enabled underneath.

Returns @encrypted_attributes_enabled value when set.

When not set, returns false only for Chef Solo or when node['dev_mode'] attribute is true.

Examples:

# With Chef Server
self.encrypted_attributes_enabled = nil
self.encrypted_attributes_enabled? #=> true
# In Chef Solo
self.encrypted_attributes_enabled = nil
self.encrypted_attributes_enabled? #=> false
# When enabled explicitly
self.encrypted_attributes_enabled = true
self.encrypted_attributes_enabled? #=> true
# When disabled explicitly
self.encrypted_attributes_enabled = false
self.encrypted_attributes_enabled? #=> false

Returns:

  • (Boolean)

    true if encrypted attributes are enabled.



385
386
387
388
389
390
391
# File 'libraries/encrypted_attributes_helpers.rb', line 385

def encrypted_attributes_enabled?
  if @encrypted_attributes_enabled.nil?
    !Chef::Config[:solo] && !node['dev_mode']
  else
    @encrypted_attributes_enabled == true
  end
end