This module helps include encrypted passwords in pillars, grains and salt state files.


This is often useful if you wish to store your pillars in source control or share your pillar data with others that you trust. I don't advise making your pillars public regardless if they are encrypted or not.

When generating keys and encrypting passwords use --local when using salt-call for extra security. Also consider using just the salt runner nacl when encrypting pillar passwords.

The nacl lib uses 32byte keys, these keys are base64 encoded to make your life more simple. To generate your key or keyfile you can use:

salt-call --local nacl.keygen keyfile=/root/.nacl

Now with your key, you can encrypt some data:

salt-call --local nacl.enc mypass keyfile=/root/.nacl

To decrypt the data:

salt-call --local nacl.dec data='DRB7Q6/X5gGSRCTpZyxS6hXO5LnlJIIJ4ivbmUlbWj0llUA+uaVyvou3vJ4=' keyfile=/root/.nacl

The following optional configurations can be defined in the minion or master config. Avoid storing the config in pillars!

cat /etc/salt/master.d/nacl.conf
    key: 'cKEzd4kXsbeCE7/nLTIqXwnUiD1ulg4NoeeYcCFpd9k='
    keyfile: /root/.nacl

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

salt-run nacl.enc 'myotherpass'

Now you can create a pillar with protected data like:

    user: root
    password: {{ salt.nacl.dec('DRB7Q6/X5gGSRCTpZyxS6hXO5LnlJIIJ4ivbmUlbWj0llUA+uaVyvou3vJ4=') }}

Or do something interesting with grains like:

salt-call nacl.enc minionname:dbrole

salt minionname grains.setval role 'AL24Z2C5OlkReer3DuQTFdrNLchLuz3NGIhGjZkLtKRYry/b/CksWM8O9yskLwH2AGVLoEXI5jAa'

{%- set r = grains.get('role') %}
{%- set role = None %}
{%- if r and 'nacl.dec' in salt %}
    {%- set r = salt['nacl.dec'](r,keyfile='/root/.nacl').split(':') %}
    {%- if opts['id'] == r[0] %}
        {%- set role = r[1] %}
    {%- endif %}
{%- endif %}
    {%- if role %}
    '{{ opts['id'] }}':
        - {{ role }}
    {%- endif %}

Multi-line text items like certificates require a bit of extra work. You have to strip the new lines and replace them with '/n' characters. Certificates specifically require some leading white space when calling nacl.enc so that the '--' in the first line (commonly -----BEGIN CERTIFICATE-----) doesn't get interpreted as an argument to nacl.enc. For instance if you have a certificate file that lives in cert.crt:

cert=$(cat cert.crt |awk '{printf "%s\n",$0} END {print ""}'); salt-run nacl.enc "  $cert"

Pillar data should look the same, even though the secret will be quite long. However, when calling multiline encrypted secrets from pillar in a state, use the following format to avoid issues with /n creating extra whitespace at the beginning of each line in the cert file:

        - template: jinja
        - user: user
        - group: group
        - mode: 700
        - contents: "{{- salt['pillar.get']('secret') }}"

The '{{-' will tell jinja to strip the whitespace from the beginning of each of the new lines.

salt.modules.nacl.dec(data, **kwargs)

Takes a key generated from nacl.keygen and decrypt some data.

CLI Examples:

salt-call --local nacl.dec pEXHQM6cuaF7A=
salt-call --local nacl.dec data='pEXHQM6cuaF7A=' keyfile=/root/.nacl
salt-call --local nacl.dec data='pEXHQM6cuaF7A=' key='cKEzd4kXsbeCE7/nLTIqXwnUiD1ulg4NoeeYcCFpd9k='
salt.modules.nacl.enc(data, **kwargs)

Takes a key generated from nacl.keygen and encrypt some data.

CLI Examples:

salt-call --local nacl.enc datatoenc
salt-call --local nacl.enc datatoenc keyfile=/root/.nacl
salt-call --local nacl.enc datatoenc key='cKEzd4kXsbeCE7/nLTIqXwnUiD1ulg4NoeeYcCFpd9k='

Use libnacl to generate a private key

CLI Examples:

salt-call --local nacl.keygen
salt-call --local nacl.keygen keyfile=/root/.nacl
salt-call --local --out=newline_values_only nacl.keygen > /root/.nacl