Puppet manifests can hold a lot of sensitive information. Sensitive information like passwords or certificates are used in the configuration of many applications. Exposing them in a puppet manifest is not ideal and may conflict with an organization's compliance policies. That is why data separation is very important aspect of secure puppet code.
Hiera is a pluggable Hierarchical Database. Hiera can help by keeping data out of puppet manifests. Puppet classes can look for data in hiera and hiera would search hierarchically and provide the first instance of value. Although Hiera is able to provide data separation, it cannot ensure security of sensitive information. Anyone with access to the Hiera data store will be able to see the data.
Enter Hiera-eyaml. Hiera-eyaml is a backend for Hiera that provides per-value encryption of sensitive data within yaml files to be used by Puppet. The following puppet module can be used to manage hiera with eyaml support: https://forge.puppetlabs.com/hunner/hiera.
The module class can be used like below:
modules/profile/manifests/hieraconf.pp
class profile::hieraconf { # hiera configuration class { 'hiera': hierarchy => [ '%{environment}/%{calling_class}', '%{environment}', '%{fqdn}', 'common', 'accounts', 'dev' ], } }
The /etc/hiera.conf would look like following after the puppet run:
/etc/puppet/hiera.yaml
# managed by puppet --- :backends: - yaml :logger: console :hierarchy: - "%{environment}/%{calling_class}" - "%{environment}" - "%{fqdn}" - common - accounts - dev :yaml: :datadir: /etc/puppet/hieradata
In following example, diamond collector for Mongodb does have data like, hosts, user and password. The collector is only enabled for grafana.pythian.com host.
modules/profile/manifests/diamond_coll.pp
diamond::collector { 'MongoDBCollector': options => { enabled => $fqdn ? { /grafana.pythian.com/ => True, default => false }, hosts => 'abc.pythian.com,xyz.pythian.com', user => 'grafana', passwd => 'xxxx', } }
To move the data to hiera, create_resources function can be used in the manifest.
modules/profile/manifests/diamond_coll.pp
class profile::diamond_coll{ $mycollectors = hiera('diamond::collectors', {}) create_resources('diamond::collector', $mycollectors) }
Then a new yaml file can be created and diamond::collectors code for MongoDBCollector can be abstracted like below:
hieradata/grafana.pythian.com.yaml
--- diamond::collectors: MongoDBCollector: options: enabled: True hosts: abc.pythian.com,xyz.pythian.com user: grafana passwd: xxxx
Hiera puppet code can be changed to following to enable eyaml
class profile::hieraconf { # hiera configuration class { 'hiera': hierarchy => [ '%{environment}/%{calling_class}', '%{environment}', '%{fqdn}', 'common', 'accounts', 'dev' ], eyaml => true, eyaml_datadir => '/etc/puppet/hieradata', eyaml_extension => 'eyaml', } }
This will add the eyaml backend to puppet after a puppet run on the puppet server. The process involves:
eyaml createkeys (Private: /etc/puppet/keys/private_key.pkcs7.pem, Public: /etc/puppet/keys/public_key.pkcs7.pem)./etc/hiera.conf to include the eyaml backend and key paths.Note that the Puppetmaster needs to be restarted after these changes to apply the new configuration.
Eyaml commands should be executed in a directory containing the keys directory (e.g., /etc/puppet).
The following command can be used to encrypt a password. It provides both string and block options
# eyaml encrypt -p Enter password: **** string: ENC[PKCS7,MIIBeQYJKoZIhvcN[..]Fg3jAmdlCLbQ] OR block: > ENC[PKCS7,MIIBeQYJKoZIhvcNAQcDoIIBajCCAWYCAQAxggEhMIIBHQIBADAFMAACAQEw...]
To decrypt, use the following: # eyaml decrypt -s 'ENC[PKCS7,MIIBeQYJKoZIhvcN[..]Fg3jAmdlCLbQ]'
While using our previous example, the hiera file would look like following. We also have to rename the file to .eyaml from .yaml.
hieradata/grafana.pythian.com.eyam
--- diamond::collectors: MongoDBCollector: options: enabled: True hosts: abc.pythian.com,xyz.pythian.com user: grafana passwd: ENC[PKCS7,MIIBeQYJKoZIhvcN[..]Fg3jAmdlCLbQ]
Here is a standard file resource used to copy an SSL certificate
file { '/etc/logstash/certs/logstash-forwarder.crt': ensure => present, mode => '0644', owner => 'root', group => 'root', source => 'puppet:///modules/logstash/logstash-forwarder.crt', }
The file resource can be moved to hiera using hiera_hash and then encrypted using the following command: # eyaml encrypt -f modules/logstash/files/logstash-forwarder.crt
The returned string value can then be added using the content parameter of the file resource in your .eyaml file:
hieradata/common.eyam
files: '/etc/logstash-forwarder/certs/logstash-forwarder.crt': ensure: present mode: '0644' owner: 'root' group: 'root' content: 'ENC[PKCS7,MIIB+wYJKoZI[..]C609Oc2QUvxARaw==]'
Incorporating hiera-eyaml into your Puppet workflow ensures compliance and security for sensitive data, covering everything from simple strings to complex certificate files.
Are you ready to save up to 60% in operational costs?