gpg.py (salt-3002.1) | : | gpg.py (salt-3002.2) | ||
---|---|---|---|---|
# -*- coding: utf-8 -*- | ||||
r""" | r""" | |||
Renderer that will decrypt GPG ciphers | Renderer that will decrypt GPG ciphers | |||
Any key in the SLS file can be a GPG cipher, and this renderer will decrypt it | 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 | 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 | source control, in such a way that only your Salt master can decrypt them and | |||
distribute them only to the minions that need them. | 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 | 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 | secret key on your master. You can put the public key in source control so that | |||
skipping to change at line 268 | skipping to change at line 267 | |||
ciphertext=`python /path/to/script.py` | ciphertext=`python /path/to/script.py` | |||
With the entire pillar dictionary now encrypted, it can be included in the CLI | With the entire pillar dictionary now encrypted, it can be included in the CLI | |||
pillar data like so: | pillar data like so: | |||
.. code-block:: bash | .. code-block:: bash | |||
salt myminion state.sls secretstuff pillar_enc=gpg pillar="$ciphertext" | salt myminion state.sls secretstuff pillar_enc=gpg pillar="$ciphertext" | |||
""" | """ | |||
# Import python libs | ||||
from __future__ import absolute_import, print_function, unicode_literals | ||||
import logging | import logging | |||
import os | import os | |||
import re | import re | |||
from subprocess import PIPE, Popen | from subprocess import PIPE, Popen | |||
import salt.syspaths | import salt.syspaths | |||
# Import salt libs | ||||
import salt.utils.cache | import salt.utils.cache | |||
import salt.utils.path | import salt.utils.path | |||
import salt.utils.stringio | import salt.utils.stringio | |||
import salt.utils.stringutils | import salt.utils.stringutils | |||
from salt.exceptions import SaltRenderError | from salt.exceptions import SaltRenderError | |||
# Import 3rd-party libs | ||||
from salt.ext import six | ||||
log = logging.getLogger(__name__) | log = logging.getLogger(__name__) | |||
GPG_CIPHERTEXT = re.compile( | GPG_CIPHERTEXT = re.compile( | |||
salt.utils.stringutils.to_bytes( | salt.utils.stringutils.to_bytes( | |||
r"-----BEGIN PGP MESSAGE-----.*?-----END PGP MESSAGE-----" | r"-----BEGIN PGP MESSAGE-----.*?-----END PGP MESSAGE-----" | |||
), | ), | |||
re.DOTALL, | re.DOTALL, | |||
) | ) | |||
GPG_CACHE = None | GPG_CACHE = None | |||
skipping to change at line 400 | skipping to change at line 391 | |||
try: | try: | |||
ret = salt.utils.stringutils.to_unicode(ret, encoding=encoding) | ret = salt.utils.stringutils.to_unicode(ret, encoding=encoding) | |||
except UnicodeDecodeError: | except UnicodeDecodeError: | |||
# decrypted data contains some sort of binary data - not our problem | # decrypted data contains some sort of binary data - not our problem | |||
pass | pass | |||
return ret | return ret | |||
def _decrypt_object(obj, translate_newlines=False, encoding=None): | def _decrypt_object(obj, translate_newlines=False, encoding=None): | |||
""" | """ | |||
Recursively try to decrypt any object. If the object is a six.string_types | Recursively try to decrypt any object. If the object is a string | |||
(string or unicode), and it contains a valid GPG header, decrypt it, | or bytes and it contains a valid GPG header, decrypt it, | |||
otherwise keep going until a string is found. | otherwise keep going until a string is found. | |||
""" | """ | |||
if salt.utils.stringio.is_readable(obj): | if salt.utils.stringio.is_readable(obj): | |||
return _decrypt_object(obj.getvalue(), translate_newlines) | return _decrypt_object(obj.getvalue(), translate_newlines) | |||
if isinstance(obj, six.string_types): | if isinstance(obj, (str, bytes)): | |||
return _decrypt_ciphertexts( | return _decrypt_ciphertexts( | |||
obj, translate_newlines=translate_newlines, encoding=encoding | obj, translate_newlines=translate_newlines, encoding=encoding | |||
) | ) | |||
elif isinstance(obj, dict): | elif isinstance(obj, dict): | |||
for key, value in six.iteritems(obj): | for key, value in obj.items(): | |||
obj[key] = _decrypt_object(value, translate_newlines=translate_newli nes) | obj[key] = _decrypt_object(value, translate_newlines=translate_newli nes) | |||
return obj | return obj | |||
elif isinstance(obj, list): | elif isinstance(obj, list): | |||
for key, value in enumerate(obj): | for key, value in enumerate(obj): | |||
obj[key] = _decrypt_object(value, translate_newlines=translate_newli nes) | obj[key] = _decrypt_object(value, translate_newlines=translate_newli nes) | |||
return obj | return obj | |||
else: | else: | |||
return obj | return obj | |||
def render(gpg_data, saltenv="base", sls="", argline="", **kwargs): | def render(gpg_data, saltenv="base", sls="", argline="", **kwargs): | |||
End of changes. 7 change blocks. | ||||
13 lines changed or deleted | 4 lines changed or added |