« Back to home

Salt NACL encryption for external pillars

This article is about encrypting Satl external pillars with NACL.

TL;DR

Salt NACL is based on another SaltStack project libnacl, an wrapper for libsodium and Salt nacl resources (module, runner, renderer and ext_pillar).

Overview of merged features to develop branch:

  • NACL module, runner (around 2015.x)

  • NACL update with secretbox, sealedbox (around 2017/Aug)

  • NACL render with boxed syntax support NACL[Cr7ptHere=] (around 2017/Aug)

  • NACL ext_pillar (around 2017/Aug)

Open bugs:

Overview

To securely deal with credentials, keys and any other private data in Salt pillars you have couple of options to choose today.

  • SDB in general allows to store data in external database backend and access them with ACLs.

    • Vault SDB module

    • Immutalbe Secrets Manager SDB Module

    • Confidant

    • Etcd

    • Consul

    • …​

  • GPG module and pillar encryption

  • NACL module

However if you employ one of the ext_pillar extensions these features are not available, as we expect ext_pillar will already provide rendered pillar data. No extra template rendering/parsing is being performed.

We could easily write a support for that into the Salt but there are also a down sides: As for example for SDB Vault, on each request to render SDB links it will spawn huge number of queries to Vault backed. Even for simple scenario that would be an overhead without a caching.

Gpg pillar encryption is in today stable version and even has support for gpg render on ext_pillar. as short string will always end-up as multi line entry for each. The obvious downside of using GPG is that any pillar item "value" of any length will look like this:

gpg-encrypted-pillar.yml
  a-secret:
    -----BEGIN PGP MESSAGE-----
    Version: GnuPG v1
    hQEMAweRHKaPCfNeAQf9GLTN16hCfXAbPwU6BbBK0unOc7i9/etGuVc5CyU9Q6um
    QuetdvQVLFO/HkrC4lgeNQdM6D9E8PKonMlgJPyUvC8ggxhj0/IPFEKmrsnv2k6+
    cnEfmVexS7o/U1VOVjoyUeliMCJlAz/30RXaME49Cpi6No2+vKD8a4q4nZN1UZcG
    RhkhC0S22zNxOXQ38TBkmtJcqxnqT6YWKTUsjVubW3bVC+u2HGqJHu79wmwuN8tz
    m4wBkfCAd8Eyo2jEnWQcM4TcXiF01XPL4z4g1/9AAxh+Q4d8RIRP4fbw7ct4nCJv
    Gr9v2DTF7HNigIMl4ivMIn9fp+EZurJNiQskLgNbktJGAeEKYkqX5iCuB1b693hJ
    FKlwHiJt5yA8X2dDtfk8/Ph1Jx2TwGS+lGjlZaNqp3R1xuAZzXzZMLyZDe5+i3RJ
    skqmFTbOiA==
    =Eqsm
    -----END PGP MESSAGE-----

That is obviously quite hard to maintain if you manipulate your pillar yamls with text editor.

With NACL it’s another story. First it’s based on [libsodium].

Sodium is a new, easy-to-use software library for encryption, decryption, signatures, password hashing and more. It is a portable, cross-compilable, installable, packageable fork of NaCl, with a compatible API, and an extended API to improve usability even further. Its goal is to provide all of the core operations needed to build higher-level cryptographic tools.
— libsodium.org

With NACL with default setup the cipher is much shorter. And for short input it have also have padding to output within minimal block size mask (as far as I understand).

Use-Case with ext_pillar

While NACL in Salt can end-to-end encryption, the usage with ext_pillar is way of simplified. It don’t replace sophisticated, enterprise level, solutions as Vault.

External pillars in salt is a list of engines that can process the pillar data in a pipeline. So you may use one external pillar backend to provide the data with encrypted values and the other one later to decrypt these.

Salt Master then operates with already unencrypted pillar data. The benefit is processing speed and of course the ability to hide sensitive information on your repository.

My Salt external pillars are distributed as git repository that holds the reclass.[1] model of the deployment.

(an shared piece of our model as an example)

Sealed and Secret box

When it comes to NACL implementation you have two options. sealedbox or secretbox.

SecretBox is data encrypted using private key sk. Sealedbox is encrypted using public key pk.

Recommend using Sealedbox because the one way encryption permits developers to encrypt data for source control but not decrypt.

What is not in the article

This tutorial don’t cover workflow for nacl key distribution, lifecycle and secure storage.

For enterprise or large scale production environments you still want to combide it with additional SDB options like Vault (there is a possibility to mix native pillars and external pillars).

Setup

In order to get NACL configured you have to do couple of steps described below. Full documentation is available on SaltStack doc page.

Install prerequisite libraries

$ pip install --upgrade libnacl===1.5.2
Caution
Ensure you have version at least 1.5.2

Optionally:

$ apt install nacl-tools

Generate your secret and public key

$ salt-call --local nacl.keygen /etc/salt/pki/master/nacl

  local:
    saved sk_file:/etc/salt/pki/master/nacl  pk_file: /etc/salt/pki/master/nacl.pub

Configure salt master ext_pillars

/etc/salt/master.d/master.conf
nacl.config:
    box_type: sealedbox
    sk_file: /etc/salt/pki/master/nacl
    pk_file: /etc/salt/pki/master/nacl.pub

reclass: &reclass
  storage_type: yaml_fs
  inventory_base_uri: /srv/salt/reclass

master_tops:
  reclass: *reclass

ext_pillar:
  - reclass: *reclass
  - nacl: {}

Encrypt your secrets

We will use sealed box thus we keep our sk_file out of the model and distributed independently. Our secrets will be encrypted with the pk_file (public key). This one can be distributed with model on pillar.

$ salt-call --local nacl.enc 'my_secret_value' pk_file=/etc/salt/pki/master/nacl.pub

  hXTkJpC1hcKMS7yZVGESutWrkvzusXfETXkacSklIxYjfWDlMJmR37MlmthdIgjXpg4f2AlBKb8tc9Woma7q

When the key is defined in the master config you can use it from the nacl runner:

$ salt-run nacl.enc 'myotherpass'

  ADDFD0Rav6p6+63sojl7Htfrncp5rrDVyeE4BSPO7ipq8fZuLDIVAzQLf4PCbDqi+Fau5KD3/J/E+Pw=

NACL on ext_pillar

Encrypted values on pillar

Update reclass class holding pillar data, it’s as easy a enclose the crypted data within the NACL[crypted data] envelope:

Tip
The syntax is for sure the same for non-ext_pillars
/srv/salt/reclass/classes/cluster/region01/infra/test_nacl.yml
parameters:
  my_pillar:
    my_nacl:
        key0: unencrypted_value
        key1: NACL[hXTkJpC1hcKMS7yZVGESutWrkvzusXfETXkacSklIxYjfWDlMJmR37MlmthdIgjXpg4f2AlBKb8tc9Woma7q]

Check pillar:

$ salt cfg\* pillar.data |egrep 'my_nacl:' -A6
    my_nacl:
        ----------
        key0:
            unencrypted_value
        key1:
            my_secret_value
Note
for native pillars you should mark first line of your pillar .yml with corresponding shebang header #!yaml|nacl.

TODO: Use CLI,sed to update your pillar’s on the fly.

large files

$ salt-call nacl.enc_file /tmp/cert.crt out=/srv/salt/env/dev/cert.nacl

# or more advanced
$ cert=$(cat /tmp/cert.crt)
$ salt-call --out=newline_values_only nacl.enc_pub data="$cert" > /srv/salt/env/dev/cert.nacl
Note
/srv/salt/env/dev is my salt:// path.

TODO: Add advanced example from our formulas

Usage of nacl module on native pillars

Besides that you may want to use NACL module on native pillars:

mypillar.yml
pillarexample:
    user: root
    password1: {{salt.nacl.dec('DRB7Q6/X5gGSRCTpZyxS6hlbWj0llUA+uaVyvou3vJ4=')|json}}
    cert_key: {{salt.nacl.dec_file('/srv/salt/env/dev/certs/example.com/cert.nacl')|json}}
    cert_key2: {{salt.nacl.dec_file('salt:///certs/example.com/cert2.nacl')|json}}

Summary

Finally a simple but robust solution for encrypted pillar values. (being said, well you can’t encrypt keys or whole pillars yml’s this way). For a serious enterprise level you still might have a need for external credential store to employ common security policies as key/password rotation, end-to-end, which these tools offer. Wort to mention that external pillars are quite familiar in Salt community so we should push hard to have features like SDB’s available for external pillars as well.


1. Reclass - Recursive external node classifier for automation tools like Ansible, Puppet, and Salt.

Comments

comments powered by Disqus