Renderer that will decrypt GPG ciphers
Any key in the SLS file can be a GPG cipher, and this renderer will decrypt it before passing it off to Salt. This allows you to safely store secrets in source control, in such a way that only your Salt master can decrypt them and distribute them only to the minions that need them.
The typical use-case would be to use ciphers in your pillar data, and keep a secret key on your master. You can put the public key in source control so that developers can add new secrets quickly and easily.
This renderer requires the python-gnupg package. Be careful to install the
python-gnupg
package, not the gnupg
package, or you will get errors.
To set things up, you will first need to generate a keypair. On your master, run:
# gpg --gen-key --homedir /etc/salt/gpgkeys
Do not supply a password for your keypair, and use a name that makes sense for your application. Be sure to back up your gpg directory someplace safe!
To retrieve the public key:
# gpg --armor --homedir /etc/salt/gpgkeys --armor --export <KEY-NAME> > exported_pubkey.gpg
Now, to encrypt secrets, copy the public key to your local machine and run:
$ gpg --import exported_pubkey.gpg
To generate a cipher from a secret:
$ echo -n "supersecret" | gpg --homedir ~/.gnupg --armor --encrypt -r <KEY-name>
There are two ways to configure salt for the usage of this renderer:
config:
renderer: jinja | yaml | gpg
This will apply the renderers to all pillars and states while requiring
python-gnupg
to be installed on all minions since the decryption
will happen on the minions.
To apply the renderer on a file-by-file basis add the following line to the top of any pillar with gpg data in it:
#!yaml|gpg
Now with your renderers configured, you can include your ciphers in your pillar data like so:
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-----
salt.renderers.gpg.
decrypt_ciphertext
(cypher, gpg, safe=False)¶Given a block of ciphertext as a string, and a gpg object, try to decrypt the cipher and return the decrypted string. If the cipher cannot be decrypted, log the error, and return the ciphertext back out.
Parameters: | safe -- Raise an exception on failure instead of returning the ciphertext |
---|
salt.renderers.gpg.
decrypt_object
(obj, gpg)¶Recursively try to decrypt any object. If the object is a string, and it contains a valid GPG header, decrypt it, otherwise keep going until a string is found.
salt.renderers.gpg.
render
(gpg_data, saltenv='base', sls='', argline='', **kwargs)¶Create a gpg object given a gpg_keydir, and then use it to try to decrypt the data to be rendered.