Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] gpg.decrypt not working when use_passphrase=True #62806

Closed
leifliddy opened this issue Oct 4, 2022 · 5 comments · Fixed by #62977
Closed

[BUG] gpg.decrypt not working when use_passphrase=True #62806

leifliddy opened this issue Oct 4, 2022 · 5 comments · Fixed by #62977
Assignees
Labels
Bug broken, incorrect, or confusing behavior Execution-Module needs-triage

Comments

@leifliddy
Copy link
Contributor

leifliddy commented Oct 4, 2022

Description
The gpg.decrypt function is not working when the use_passphrase=True argument is present.

Setup
I'm simply following the examples listed here.
https://docs.saltproject.io/en/latest/ref/modules/all/salt.modules.gpg.html

Steps to Reproduce the behavior

  1. create a gpg_passphrase (encrypted or non-encrypted it doesn't matter)
[root@cloud ~]# cat /srv/pillar/gpg.sls 
#!yaml|gpg
gpg_passphrase: |
    -----BEGIN PGP MESSAGE-----

    hQIMAzfugaDuscO2AQ//dTbgKY+fpBy0bbWm5HLLX4h78UQoH4NU3UPVvPiW3JBj
    btA26j/4soHu+Ht7P02OBf0p9H+dHuvMffyx7z/y19KhUjsc7r5AIniRFYsD8ze7
    RbObLAKpwg4KCmiXvNhF0/bKqyGk/vxCWOIE2pNUiclvozAzSV1vX75f8JEQOH4N
    wsxMqwyhpNIsuF6FdFjKPkGkHYbuw/5MYT3+KQ95GTFMvbuV5Q/IMyJ1rH39z0uH
    LTsIHXM2I2thGI+mWeQnyBuGkXqRWG0uo/MXTzR4xf+tDhRA2vGAYSyeey4IpGAe
    M862W7EXCD2+eN2IiEDjcbsuOnLIN8QSAoVBPPwU75FtRdI5qqTL5873iugTsGkF
    moMf7Q3/z7tbdCt2b8uCSJ/ZfPu5RoVS24d458Q564e2MHQVoxYUzHB60Jedy28j
    X9Hi3FD8XI1L5pSNtdrS7Moc9cFGf3vBdgmG/X1Oa8jKaEbTrt367SHtaNXSxXFw
    STqygIuw68bIpiAag78TIeEUMzIpUDboVapRYXoqx6EY7AEAEhK6rC0mGdxdIEsG
    y2SCQqAnI+ivuiqt5PIKwN9YURTsBeRN18SV+6vZXNvuezgyEhPSSmCX8TYT90Ix
    UOpLNL6FZ6stODMI3tP+po2Qku6n2HCGa5Kb4X1XRnlzLmqRPM7XoOJDTPBHsXbS
    bQEZdvS6c4josfmitfk6t73NVomf2DFDNAVot15XwMNhIYjkjHrDJlA8HPvwSPzZ
    T34WXl9xKXsxXs0WVJiXACZ5Ww1ocfiwimWhFH7KCatX9lL2IRCHDKbP+2z8izDu
    Phcj64T8xXSRjXgfm8U=
    =mxOK
    -----END PGP MESSAGE-----
  1. create a gpg key
    salt-call gpg.create_key key_type='rsa' key_length=3072 name_real=logrotate name_email=logrotate@localhost expire_date=0 use_passphrase=True

  2. encrypt file

[root@cloud ~]# salt-call gpg.encrypt filename='/root/script.py' output='/root/script.py.asc' recipients=logrotate
local:
    ----------
    comment:
        Encrypted data has been written to /root/script.py.asc
    res:
        True
  1. now try and decrypt that file
    salt-call gpg.decrypt filename='/root/script.py.asc' use_passphrase=True
    This is the resulting error:
Traceback (most recent call last):
  File "/usr/lib/python3.10/site-packages/salt/cli/caller.py", line 202, in call
    ret["return"] = self.minion.executors[fname](
  File "/usr/lib/python3.10/site-packages/salt/loader/lazy.py", line 149, in __call__
    return self.loader.run(run_func, *args, **kwargs)
  File "/usr/lib/python3.10/site-packages/salt/loader/lazy.py", line 1228, in run
    return self._last_context.run(self._run_as, _func_or_method, *args, **kwargs)
  File "/usr/lib/python3.10/site-packages/salt/loader/lazy.py", line 1243, in _run_as
    return _func_or_method(*args, **kwargs)
  File "/usr/lib/python3.10/site-packages/salt/executors/direct_call.py", line 10, in execute
    return func(*args, **kwargs)
  File "/usr/lib/python3.10/site-packages/salt/loader/lazy.py", line 149, in __call__
    return self.loader.run(run_func, *args, **kwargs)
  File "/usr/lib/python3.10/site-packages/salt/loader/lazy.py", line 1228, in run
    return self._last_context.run(self._run_as, _func_or_method, *args, **kwargs)
  File "/usr/lib/python3.10/site-packages/salt/loader/lazy.py", line 1243, in _run_as
    return _func_or_method(*args, **kwargs)
  File "/usr/lib/python3.10/site-packages/salt/modules/gpg.py", line 1250, in encrypt
    gpg_passphrase = gpg_passphrase["gpg_passphrase"]
TypeError: string indices must be integers

Expected behavior
It should decrypt the file

Versions Report

salt --versions-report Salt Version: Salt: 3005

Dependency Versions:
cffi: 1.15.0
cherrypy: Not Installed
dateutil: 2.8.1
docker-py: Not Installed
gitdb: Not Installed
gitpython: Not Installed
Jinja2: 3.0.3
libgit2: Not Installed
M2Crypto: Not Installed
Mako: Not Installed
msgpack: 1.0.3
msgpack-pure: Not Installed
mysql-python: Not Installed
pycparser: 2.20
pycrypto: Not Installed
pycryptodome: 3.15.0
pygit2: Not Installed
Python: 3.10.7 (main, Sep 7 2022, 00:00:00) [GCC 12.2.1 20220819 (Red Hat 12.2.1-1)]
python-gnupg: 0.5.0
PyYAML: 6.0
PyZMQ: 22.3.0
smmap: Not Installed
timelib: Not Installed
Tornado: 4.5.3
ZMQ: 4.3.4

System Versions:
dist: fedora 36
locale: utf-8
machine: x86_64
release: 5.19.11-200.fc36.x86_64
system: Linux
version: Fedora Linux 36

PASTE HERE

Additional context
Add any other context about the problem here.

This issue is caused by this:
/usr/lib/python3.10/site-packages/salt/modules/gpg.py

    ret = {"res": True, "comment": ""}
    gpg = _create_gpg(user, gnupghome)
    if use_passphrase:
        gpg_passphrase = __salt__["pillar.get"]("gpg_passphrase")
        if not gpg_passphrase:
            raise SaltInvocationError("gpg_passphrase not available in pillar.")
        #gpg_passphrase = gpg_passphrase["gpg_passphrase"] # problem line
    else:
        gpg_passphrase = None

If I comment out that gpg_passphrase = gpg_passphrase["gpg_passphrase"] line, it works fine.
Not sure what the purpose of that line is anyway.
The gpg_passphrase has already been set with
gpg_passphrase = __salt__["pillar.get"]("gpg_passphrase")

Note: gpg.encrypt also fails when use_passphrase=True is provided
and commenting out/removing that gpg_passphrase = gpg_passphrase["gpg_passphrase"] line in the encrypt function resolves the issue.

@leifliddy leifliddy added Bug broken, incorrect, or confusing behavior needs-triage labels Oct 4, 2022
@leifliddy
Copy link
Contributor Author

@OrangeDog You still around? If you have time, could you please verify this issue?

@OrangeDog
Copy link
Contributor

That line does indeed look wrong, and other functions in the module don't have it.

It was added by @garethgreenaway in 641b719. It is unclear why.

@leifliddy
Copy link
Contributor Author

leifliddy commented Oct 4, 2022

I'm guessing that when the original author wrote this, he probably had gpg_passphrase stored as a dictionary in pillar.

Something along the lines of:

gpg_passphrase: 
  gpg_passphrase: ">0aX+:@>apw_mW3v>--hw5gxJ?msekrDtyG=tsBikNd.rG:ebP"

Unfortunately, it's only treated as a dictionary for the encrypt and decrypt functions.
Which brings up a good point. It doesn't show anywhere in the documentation how gpg_passphrase should be set in pillar.
Actually, there's no mention of gpg_passphrase anywhere (that I can find). I initially discovered that from the error messages.
I suppose that is a limiting factor with the gpg module -- that you can only have a single gpg passphrase stored in pillar for your entire environment. I guess that makes sense though, otherwise things would get pretty messy trying to decrypt/encrypt things in a large computing environment. For more complex use cases, it'd be better to write your own module.

As a side note -- one feature that would be really nice to have would be key_usage and subkey_usage arguments for the create_key function.
I wrote about that topic here:
vsajip/python-gnupg#194

I might try to develop this feature when I have some time....

@leifliddy
Copy link
Contributor Author

leifliddy commented Oct 4, 2022

Just to be clear, the only modification that needs to happen is:

--- /usr/lib/python3.10/site-packages/salt/modules/gpg.py.orig	2022-10-04 07:08:31.244654831 +0200
+++ /usr/lib/python3.10/site-packages/salt/modules/gpg.py	2022-10-04 22:45:59.934524234 +0200
@@ -1247,7 +1247,6 @@ def encrypt(
         gpg_passphrase = __salt__["pillar.get"]("gpg_passphrase")
         if not gpg_passphrase:
             raise SaltInvocationError("gpg_passphrase not available in pillar.")
-        gpg_passphrase = gpg_passphrase["gpg_passphrase"]
     else:
         gpg_passphrase = None
 
@@ -1352,7 +1351,6 @@ def decrypt(
         gpg_passphrase = __salt__["pillar.get"]("gpg_passphrase")
         if not gpg_passphrase:
             raise SaltInvocationError("gpg_passphrase not available in pillar.")
-        gpg_passphrase = gpg_passphrase["gpg_passphrase"]
     else:
         gpg_passphrase = None

@leifliddy
Copy link
Contributor Author

I finally learned the basics of mock unit testing. Ok I have the fix for this current issue along with the associated unit test. I'll push a PR out within the next few days.

As a side note, I really want to rework that entire gpg.trust_key function. Should not be needing to run cmd.run_all for that.
But I need wait until this PR to get approved first so that we don't lose any functionality.
https://github.com/vsajip/python-gnupg/pull/205/files

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug broken, incorrect, or confusing behavior Execution-Module needs-triage
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants