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:
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.
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 🔗︎
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 |
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:
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.
Comments
comments powered by Disqus