Add option to have gpg decrypt failures treated as errors.

This is defaulted `false` for compatibility, and is controlled via
a `gpg_decrypt_must_succeed` option.

If this is true- and the ciphertext couldn't be decrypted- then it's
treated as an error rather than just passing the raw ciphertext through.

Sending the ciphertext through basically is *never* desired- the point
of the gpg renderer is to decrypt the secret, not send the cipher text
through.
This commit is contained in:
Brian Harring 2021-12-08 17:24:37 +00:00 committed by Megan Wilhite
parent 6c47ee5057
commit ef56aa0547
6 changed files with 92 additions and 0 deletions

View file

@ -873,6 +873,10 @@
#decrypt_pillar_renderers:
# - gpg
# If this is `True` and the ciphertext could not be decrypted, then an error is
# raised.
#gpg_decrypt_must_succeed: False
# The ext_pillar_first option allows for external pillar sources to populate
# before file system pillar. This allows for targeting file system pillar from
# ext_pillar.

View file

@ -656,6 +656,10 @@
# base:
# - /srv/pillar
# If this is `True` and the ciphertext could not be decrypted, then an error is
# raised.
#gpg_decrypt_must_succeed: False
# Set a hard-limit on the size of the files that can be pushed to the master.
# It will be interpreted as megabytes. Default: 100
#file_recv_max_size: 100

View file

@ -4124,6 +4124,32 @@ List of renderers which are permitted to be used for pillar decryption.
- gpg
- my_custom_renderer
.. conf_master:: gpg_decrypt_must_succeed
``gpg_decrypt_must_succeed``
----------------------------
.. versionadded:: 3005
Default: ``False``
If this is ``True`` and the ciphertext could not be decrypted, then an error is
raised.
Sending the ciphertext through basically is *never* desired, for example if a
state is setting a database password from pillar and gpg rendering fails, then
the state will update the password to the ciphertext, which by definition is
not encrypted.
.. warning::
The value defaults to ``False`` for backwards compatibility. In the
``Chlorine`` release, this option will default to ``True``.
.. code-block:: yaml
gpg_decrypt_must_succeed: False
.. conf_master:: pillar_opts
``pillar_opts``

View file

@ -2660,6 +2660,32 @@ List of renderers which are permitted to be used for pillar decryption.
- gpg
- my_custom_renderer
.. conf_minion:: gpg_decrypt_must_succeed
``gpg_decrypt_must_succeed``
----------------------------
.. versionadded:: 3005
Default: ``False``
If this is ``True`` and the ciphertext could not be decrypted, then an error is
raised.
Sending the ciphertext through basically is *never* desired, for example if a
state is setting a database password from pillar and gpg rendering fails, then
the state will update the password to the ciphertext, which by definition is
not encrypted.
.. warning::
The value defaults to ``False`` for backwards compatibility. In the
``Chlorine`` release, this option will default to ``True``.
.. code-block:: yaml
gpg_decrypt_must_succeed: False
.. conf_minion:: pillarenv
``pillarenv``

View file

@ -255,6 +255,8 @@ VALID_OPTS = immutabletypes.freeze(
"decrypt_pillar_default": str,
# List of renderers available for decrypt_pillar
"decrypt_pillar_renderers": list,
# Treat GPG decryption errors as renderer errors
"gpg_decrypt_must_succeed": bool,
# The type of hashing algorithm to use when doing file comparisons
"hash_type": str,
# Order of preference for optimized .pyc files (PY3 only)
@ -1057,6 +1059,7 @@ DEFAULT_MINION_OPTS = immutabletypes.freeze(
"decrypt_pillar_delimiter": ":",
"decrypt_pillar_default": "gpg",
"decrypt_pillar_renderers": ["gpg"],
"gpg_decrypt_must_succeed": False,
# Update intervals
"roots_update_interval": DEFAULT_INTERVAL,
"azurefs_update_interval": DEFAULT_INTERVAL,
@ -1294,6 +1297,7 @@ DEFAULT_MASTER_OPTS = immutabletypes.freeze(
"decrypt_pillar_delimiter": ":",
"decrypt_pillar_default": "gpg",
"decrypt_pillar_renderers": ["gpg"],
"gpg_decrypt_must_succeed": False,
"thoriumenv": None,
"thorium_top": "top.sls",
"thorium_interval": 0.5,

View file

@ -267,6 +267,21 @@ pillar data like so:
.. code-block:: bash
salt myminion state.sls secretstuff pillar_enc=gpg pillar="$ciphertext"
Configuration
*************
The default behaviour of this renderer is to log a warning if a block could not
be decrypted; in other words, it just returns the ciphertext rather than the
encrypted secret.
This behaviour can be changed via the `gpg_decrypt_must_succeed` configuration
option. If set to `True`, any gpg block that cannot be decrypted raises a
`SaltRenderError` exception, which registers an error in ``_errors`` during
rendering.
In the Chlorine release, the default behavior will be reversed and an error
message will be added to ``_errors`` by default.
"""
@ -280,6 +295,7 @@ import salt.utils.cache
import salt.utils.path
import salt.utils.stringio
import salt.utils.stringutils
import salt.utils.versions
from salt.exceptions import SaltRenderError
log = logging.getLogger(__name__)
@ -365,6 +381,18 @@ def _decrypt_ciphertext(cipher):
decrypted_data, decrypt_error = proc.communicate(input=cipher)
if not decrypted_data:
log.warning("Could not decrypt cipher %r, received: %r", cipher, decrypt_error)
if __opts__["gpg_decrypt_must_succeed"]:
raise SaltRenderError(
"Could not decrypt cipher {!r}, received: {!r}".format(
cipher,
decrypt_error,
)
)
else:
salt.utils.versions.warn_until(
"Chlorine",
"After the Chlorine release of Salt, gpg_decrypt_must_succeed will default to True.",
)
return cipher
else:
if __opts__.get("gpg_cache"):