Securely Leverage Sensitive Data in your Infrastructure Automation Workflows.
Centralize your secrets sprawl and honor the privilege of least privilege with enterprise secrets management. Leverage secrets stored in HashiCorp Vault in your Puppet automation workflows to both keep your systems secure and configurations up to date.
Are you struggling to centralize sensitive data across your organization? Do you sleep well knowing passwords and private keys aren’t stored and encrypted properly?
If you’re using HashiCorp Vault to store and control access to secrets, you can add an extra layer of security by integrating Vault with Puppet, allowing each Puppet agent to safely retrieve secrets only when they're needed without storing or exposing the information. This can reduce secrets exposure and provide a high level of security across all of your environments.
Secrets can be any type of data that should be kept secret. Often these are used to store authentication credentials--including passwords, API tokens, encryption keys, certificates, etc--but can also be nearly any kind of information you'd like to keep private for any reasons. Managing secrets with automated DevOps tooling is critical for maintaining a scalable and secure infrastructure.
Especially when automating, one must be careful to follow the principle of least privilege, only granting people or automation systems the minimum privileges required to do a job.
In traditional or legacy Puppet infrastructures, the central server had access to all secrets so that it could compile them into catalogs distributed for agents to enforce. Today though, this can be delegated to the agent using a secret management system like HashiCorp Vault which allows the agents to retrieve secrets on demand at runtime. The server doesn't need access to the secret at all--it just instructs the agents on how to look them up.
Look up Vault Secrets in Puppet Code
This leverages the functionality of the puppet-vault_lookup
module from our friends at Vox Pupuli and the deferred function capability of modern Puppet versions. The value returned by the vault_lookup::lookup()
function can be passed directly to a resource parameter, but usually you'll find yourself rendering it to a configuration file via a template. To do this, you'll also need to defer the template rendering, like so:
$variables = { 'token' => Deferred('vault_lookup::lookup', ["myapp/auth_token", 'https://vault.example.com:8200']), } # compile the template source into the catalogfile { '/etc/myapp/auth.conf': ensure => file, content => Deferred('inline_epp', ['TOKEN=<%= $token.unwrap %>', $variables]), }
At this point, classes that do their own template rendering cannot transparently take advantage of deferred secrets lookup. You'll need to generate the templated configuration file on your own by deferring an inline template rendering call as demonstrated above.
Retrieving Vault Secrets Using Bolt
If you'd rather use Bolt tasks and plans for your secrets automation, we'll use the puppetlabs-vault
module. This module provides a plugin allowing secrets to be retrieved from the Vault server at runtime. First you'll need to configure the plugin. Because the token is sensitive data, you'll want to put these settings in your user config file at ~/.puppetlabs/etc/bolt/bolt-defaults.yaml
rather than in the project configuration where it might be committed to source control.
plugins: vault: server_url: https://vault.example.com:8200cacert: /path/to/caauth: method: tokentoken: xxxxx-xxxxx
Once configured, there are a few different ways you can use Vault secrets. For example, if you wanted to store your SSH keys in Vault, you could configure the SSH transport in your inventory file to use those keys whenever you ran Bolt commands.
version: 2targets: - ...config: ssh: user: rootprivate-key: key-data: _plugin: vaultpath: secrets/boltfield: private-keyversion: 2
You can also retrieve secrets to use in your plans with the resolve_reference()
function. Once resolved, you can use secrets just like any other variable.
$references = { "_plugin" => "vault", "path" => "secrets/myapp", "field" => "auth_token" } # returns a string containing the resolved token$token = resolve_references($references)
Further Modules
- See the
puppet-vault_lookup
module and function. - See the
puppetlabs-vault
module and Bolt plugin. - Read about deferred functions.
- See other useful Bolt functions.