Simple Secret Storage for Puppet

I manage my VPS systems using Puppet, which is a brilliant way to keep track of everything I want them to do, and allows me to destroy them and create a new copy in minutes. I keep the source files for this on GitHub, so I have an easily managed central storage space.

This works pretty well, but means I can't keep any passwords or sensitive data inside the Puppet code, or it would be publicly browsable on GitHub. As I want to use my GMail account for outgoing mail ... There are various solutions for proper distributed secret management with Puppet, like Blackbox or Summon, or Vault but they require running external services or GPG encryption which is overkill for a barebones VPS and my small manifest files.

To get around this I use a simple way of keeping secrets local to the server.

Storage

Default values are kept in a YAML file called secrets.yaml alongside the site.pp main manifest. This should contain default values for all the secrets, and you can commit this to Git.

#This is a secret container for secrets. All secrets named in here will be tracked by git, so put default values only!
#Put the real values in a file called "secrets.local.yaml". Puppet will overwrite any values from here with those, and that
#file is ignored by git.

gmail:
  username: default
  password: default
  admin_email: default_admin_email@domain.com
newrelic:
  license_key: none
some_service:
  username: default
  password: default

Than at the top of your site.pp manifest put the following code:

#Load up our secrets for use in the modules below - refer to them using the $::secrets name
$default_secrets = loadyaml('secrets.yaml')
$local_secrets = loadyaml('secrets.local.yaml')

if $local_secrets == undef {
  fail('Can\'t load "secrets.local.yaml" - File does not exist')
}

$secrets = merge($default_secrets, $local_secrets)

And on your server create a local file next to secrets.yaml called secrets.local.yaml. Don't commit this to git!

gmail:
  username: my_gmail_username
  password: my_gmail_password
  admin_email: emailme@domain.com
newrelic:
  license_key: 123abc456def789abc123def456
some_service:
  username: me
  password: s00pers33cret

When you run Puppet this will give you a global variable called $::secrets that you can use in your manifests:

##Set up SSMTP with GMail to handle system outgoing mail
  class { 'ssmtp':
    mail_hub           => 'smtp.gmail.com:587',
    rewritedomain      => 'mydomain.org.uk',
    root_email         => $::secrets["gmail"]["admin_email"],
    authuser           => $::secrets["gmail"]["username"],
    authpass           => $::secrets["gmail"]["password"],
    from_line_override => 'YES',
    usetls             => 'YES',
    usestarttls        => 'YES',
  }