Skip to content

Commit

Permalink
adding support for export of private gpg key (spack#22557)
Browse files Browse the repository at this point in the history
This PR allows users to `--export`, `--export-secret`, or both to  export GPG keys
from Spack. The docs are updated that include a warning that this usually does not
need to be done.

This addresses an issue brought up in slack, and also represented in spack#14721.

Signed-off-by: vsoch <vsoch@users.noreply.github.com>

Co-authored-by: vsoch <vsoch@users.noreply.github.com>
  • Loading branch information
vsoch and vsoch authored May 29, 2021
1 parent f6febd2 commit 6f534ac
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 14 deletions.
76 changes: 75 additions & 1 deletion lib/spack/docs/getting_started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1119,6 +1119,33 @@ Secret keys may also be later exported using the
<https://www.digitalocean.com/community/tutorials/how-to-setup-additional-entropy-for-cloud-servers-using-haveged>`_
provides a good overview of sources of randomness.

Here is an example of creating a key. Note that we provide a name for the key first
(which we can use to reference the key later) and an email address:

.. code-block:: console
$ spack gpg create dinosaur dinosaur@thedinosaurthings.com
If you want to export the key as you create it:


.. code-block:: console
$ spack gpg create --export key.pub dinosaur dinosaur@thedinosaurthings.com
Or the private key:


.. code-block:: console
$ spack gpg create --export-secret key.priv dinosaur dinosaur@thedinosaurthings.com
You can include both ``--export`` and ``--export-secret``, each with
an output file of choice, to export both.


^^^^^^^^^^^^
Listing keys
^^^^^^^^^^^^
Expand All @@ -1127,7 +1154,22 @@ In order to list the keys available in the keyring, the
``spack gpg list`` command will list trusted keys with the ``--trusted`` flag
and keys available for signing using ``--signing``. If you would like to
remove keys from your keyring, ``spack gpg untrust <keyid>``. Key IDs can be
email addresses, names, or (best) fingerprints.
email addresses, names, or (best) fingerprints. Here is an example of listing
the key that we just created:

.. code-block:: console
gpgconf: socketdir is '/run/user/1000/gnupg'
/home/spackuser/spack/opt/spack/gpg/pubring.kbx
----------------------------------------------------------
pub rsa4096 2021-03-25 [SC]
60D2685DAB647AD4DB54125961E09BB6F2A0ADCB
uid [ultimate] dinosaur (GPG created for Spack) <dinosaur@thedinosaurthings.com>
Note that the name "dinosaur" can be seen under the uid, which is the unique
id. We might need this reference if we want to export or otherwise reference the key.


^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Signing and Verifying Packages
Expand All @@ -1142,6 +1184,38 @@ may also be used to create a signed file which contains the contents, but it
is not recommended. Signed packages may be verified by using
``spack gpg verify <file>``.


^^^^^^^^^^^^^^
Exporting Keys
^^^^^^^^^^^^^^

You likely might want to export a public key, and that looks like this. Let's
use the previous example and ask spack to export the key with uid "dinosaur."
We will provide an output location (typically a `*.pub` file) and the name of
the key.

.. code-block:: console
$ spack gpg export dinosaur.pub dinosaur
You can then look at the created file, `dinosaur.pub`, to see the exported key.
If you want to include the private key, then just add `--secret`:

.. code-block:: console
$ spack gpg export --secret dinosaur.priv dinosaur
This will write the private key to the file `dinosaur.priv`.

.. warning::

You should be very careful about exporting private keys. You likely would
only want to do this in the context of moving your spack installation to
a different server, and wanting to preserve keys for a buildcache. If you
are unsure about exporting, you can ask your local system administrator
or for help on an issue or the Spack slack.


.. _cray-support:

-------------
Expand Down
4 changes: 3 additions & 1 deletion lib/spack/spack/binary_distribution.py
Original file line number Diff line number Diff line change
Expand Up @@ -1558,7 +1558,9 @@ def push_keys(*mirrors, **kwargs):
filename = fingerprint + '.pub'

export_target = os.path.join(prefix, filename)
spack.util.gpg.export_keys(export_target, fingerprint)

# Export public keys (private is set to False)
spack.util.gpg.export_keys(export_target, [fingerprint])

# If mirror is local, the above export writes directly to the
# mirror (export_target points directly to the mirror).
Expand Down
23 changes: 17 additions & 6 deletions lib/spack/spack/cmd/gpg.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ def setup_parser(subparser):
default='0', help='when the key should expire')
create.add_argument('--export', metavar='DEST', type=str,
help='export the public key to a file')
create.add_argument('--export-secret', metavar="DEST", type=str,
dest="secret",
help='export the private key to a file.')
create.set_defaults(func=gpg_create)

list = subparsers.add_parser('list', help=gpg_list.__doc__)
Expand All @@ -79,7 +82,9 @@ def setup_parser(subparser):
help='where to export keys')
export.add_argument('keys', nargs='*',
help='the keys to export; '
'all secret keys if unspecified')
'all public keys if unspecified')
export.add_argument('--secret', action='store_true',
help='export secret keys')
export.set_defaults(func=gpg_export)

publish = subparsers.add_parser('publish', help=gpg_publish.__doc__)
Expand Down Expand Up @@ -112,22 +117,28 @@ def setup_parser(subparser):

def gpg_create(args):
"""create a new key"""
if args.export:
if args.export or args.secret:
old_sec_keys = spack.util.gpg.signing_keys()

# Create the new key
spack.util.gpg.create(name=args.name, email=args.email,
comment=args.comment, expires=args.expires)
if args.export:
if args.export or args.secret:
new_sec_keys = set(spack.util.gpg.signing_keys())
new_keys = new_sec_keys.difference(old_sec_keys)
spack.util.gpg.export_keys(args.export, *new_keys)

if args.export:
spack.util.gpg.export_keys(args.export, new_keys)
if args.secret:
spack.util.gpg.export_keys(args.secret, new_keys, secret=True)


def gpg_export(args):
"""export a secret key"""
"""export a gpg key, optionally including secret key."""
keys = args.keys
if not keys:
keys = spack.util.gpg.signing_keys()
spack.util.gpg.export_keys(args.location, *keys)
spack.util.gpg.export_keys(args.location, keys, args.secret)


def gpg_list(args):
Expand Down
14 changes: 14 additions & 0 deletions lib/spack/spack/test/cmd/gpg.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,20 @@ def test_gpg(tmpdir, mock_gnupghome):
export_path = tmpdir.join('export.testing.key')
gpg('export', str(export_path))

# Test exporting the private key
private_export_path = tmpdir.join('export-secret.testing.key')
gpg('export', '--secret', str(private_export_path))

# Ensure we exported the right content!
with open(str(private_export_path), 'r') as fd:
content = fd.read()
assert "BEGIN PGP PRIVATE KEY BLOCK" in content

# and for the public key
with open(str(export_path), 'r') as fd:
content = fd.read()
assert "BEGIN PGP PUBLIC KEY BLOCK" in content

# Create a second key for use in the tests.
gpg('create',
'--comment', 'Spack testing key',
Expand Down
10 changes: 6 additions & 4 deletions lib/spack/spack/util/gpg.py
Original file line number Diff line number Diff line change
Expand Up @@ -336,10 +336,12 @@ def public_keys(self, *args):
*args, output=str)
return parse_public_keys_output(output)

def export_keys(self, location, *keys):
self('--batch', '--yes',
'--armor', '--export',
'--output', location, *keys)
def export_keys(self, location, keys, secret=False):
if secret:
self("--export-secret-keys", "--armor", "--output", location, *keys)
else:
self('--batch', '--yes', '--armor', '--export', '--output',
location, *keys)

def trust(self, keyfile):
self('--import', keyfile)
Expand Down
4 changes: 2 additions & 2 deletions share/spack/spack-completion.bash
Original file line number Diff line number Diff line change
Expand Up @@ -1010,7 +1010,7 @@ _spack_gpg_sign() {
_spack_gpg_create() {
if $list_options
then
SPACK_COMPREPLY="-h --help --comment --expires --export"
SPACK_COMPREPLY="-h --help --comment --expires --export --export-secret"
else
SPACK_COMPREPLY=""
fi
Expand All @@ -1027,7 +1027,7 @@ _spack_gpg_init() {
_spack_gpg_export() {
if $list_options
then
SPACK_COMPREPLY="-h --help"
SPACK_COMPREPLY="-h --help --secret"
else
_keys
fi
Expand Down

0 comments on commit 6f534ac

Please sign in to comment.