Using Hiera with Puppet

Editing encrypted values in place is one of the coolest features of the hiera-eyaml back end. eyaml edit opens a copy of the eyaml file in your editor of choice and automatically decrypts all of the values in the file. Here you can modify the values just as though they were plain text. When you exit the editor by saving the file, it automatically encrypts all of the modified values and saves the new file in place. You can see that the unencrypted plain text is marked to allow the eyaml tool to identify each encrypted block, along with the encryption method that originally was used. This is used to make sure that the block is encrypted again only if the clear text value has changed and is encrypted using the original encryption mechanism:


nginx::credentials::user: user1
nginx::credentials::basic_auth : DEC(1)::PKCS7[very secret password]! 

Blocks and strings of encrypted text can get rather onerous once you have more than a hundred entries or so. Because these yaml files are meant to be modified by humans directly, you want them to be easy to navigate. In my experience, it makes sense to keep your encrypted values in a separate file, such as a secure.yaml, with a hierarchy path of:


:hierarchy:
  - "node/%{::fqdn}"
 - "environment/%{::env}/secure"
  - "environment/%{::env}/main"
  - "environment/%{::env}/%{calling_module}"

This isn't necessary, as each value is encrypted individually and can be distributed safely to other teams. It may work well for your environment, however, because you can store the encrypted files in a separate repository, perhaps in a different Git repository. Only the private keys need to be protected on the Puppet master. I also recommend having separate keys for each environment, as this can give more granular control over who can decrypt different datafiles in Hiera, as well as even greater security separation. One way to do this is to name the keys with the possible values for the @env fact, and include that in the path of the hierarchy. You'll need to encrypt values with the correct key, and this naming convention makes it easy to tell which one is correct:


:pkcs7_private_key: /path/to/private_key.pkcs7.pem-%{::env}
:pkcs7_public_key: /path/to/public_key.pkcs7.pem-%{::env}

When using Hiera values within Puppet templates, either encrypted or not, you must be careful to pull them into the class that contains the templates instead of calling the values from within the template across classes—for example, in the template mytest.erb in a module called mymodule:


mytest.erb:
...
username: user1
passwd: <%= scope.lookupvar('nginx::credentials::basic_auth') %> 
 ↪#don't do this
...

Puppet may not have loaded a value into nginx::credentials::basic_auth yet because of the order of operations. Also, if you are using the %calling_module Hiera variable, the calling module in this case would be mymodule, and not nginx, so it would not find the value in the nginx.yaml file, as one might expect.

To avoid these and other issues, it's best to import the values into the mymodule class and assign local values:


mymodule.pp:
class mymodule {
  include nginx::credentials
  $basic_auth = "${nginx::credentials::basic_auth}"
  file { '/etc/credentials/boto_cloudwatch.cfg':
     content =>  template ("mymodule/mytest.erb"),
  }

And then reference the local value from the template:


mytest.erb:
...
username: user1
passwd: <%= @basic_auth %>

You're now ready to start introducing encrypted Hiera values gradually into your Puppet environment. Maybe after you separate data from your Puppet code, you can contribute some of your modules to the PuppetForge for others to use!

Resources

Docs—Hiera 1 Overview: https://docs.puppetlabs.com/hiera/1

"First Look: Installing and Using Hiera": http://puppetlabs.com/blog/first-look-installing-and-using-hiera

TomPoulton/hiera-eyaml: https://github.com/TomPoulton/hiera-eyaml

dalen/hiera-psql: https://github.com/dalen/hiera-psql

"Encrypting sensitive data in Puppet": http://www.theguardian.com/info/developer-blog/2014/feb/14/encrypting-sensitive-data-in-puppet

______________________