jaraco / keyring

MIT License
1.23k stars 150 forks source link

Provide signned tags #427

Closed FFY00 closed 3 years ago

FFY00 commented 4 years ago

Hey, would it be possible for you to start signing the tags?

jaraco commented 4 years ago

Wow. In 12 words, you opened up a huge can of worms.

I'd love to provide signed tags, but the implications of this request are many. If I were to implement this request just on keyring, it would mean that the workflow for keyring starts to deviate from the other 140 projects I maintain, or conversely, I'd need to apply this request to those projects as well. And while that might be a good idea, I'd need to make sure that signed tags are available in all of the environments in which I cut releases, including multiple workstations and GitHub and GitLab (I do cut releases through the web on my phone). I'd also need to ensure that signed tags are supported by tools that create tags (such as with setuptools via bump2version).

It doesn't look like either GitHub nor GitLab support creating signed tags. Furthermore, it's not obvious to me what PKI (if any) I should use for creating a key pair for signing or if the tooling is robust enough to support storing the private key in multiple places.

I suspect there are other pitfalls in the workflow, such as required interactivity. All of the examples show typing a passphrase on each invocation, but I'd like commands to be non-interactive, and I suspect git and other tools don't support secure storage of the keys without requiring a password.

So I'm struggling with envisioning a workflow that's not complicated and adds constraints to the workflows.

I'd be interested (enthusiastic even) if there were a definitive guide on how to address these concerns, but as it appears now, there's just a bunch of loosely-coupled tools without a complete workflow.

FFY00 commented 4 years ago

Agh, sorry for the delay! I got lost on a few other things.

Okay, there are a few things to unpack here.

1) Git tags

First, we should have a little discussion about git tags. Git actually provides two types of tags, annotated tags and lightweight tags. Annotated tags store an object containing the author, date and description in the git database, where lightweight tags are just a pointer to a git object, they don't hold any information.

Other thing to take into account is that git describe ignores lightweight tags. If you want it to take them into account, you need to provide the --tags option.

For project releases, in my opinion, annotated tags should be used. Having access to the tag author and date at a later date is something I consider very desirable for releases. You also have the opportunity to attach a changelog and/or comments to the releases.\

Git also recommends the use of annotated tags:

It’s generally recommended that you create annotated tags so you can have all this information; but if you want a temporary tag or for some reason don’t want to keep the other information, lightweight tags are available too.

2) Github/Gitlab tag/release support

So, Github and Gitlab support is very similar. They both provide an incomplete interface to the tags and a custom separate release system. The main difference between the two is that Github only allows you to create a tag by creating a release, while Gitlab lets you create only a tag.

The problem here is tag both websites will create lightweight tags instead of annotated tags. They expect you to rely on their release system to keep this metadata. This is obviously bad, if you ever want to migrate, or if the website goes down, you lose the metadata.

Taking this into account, if you choose to use lightweight tags, you may use the web interface to create new releases, if you choose to use annotated tags, you must use the command line to create releases as there is no support on the web interface yet.

Because lightweight tags are not git objects, they can't be signed. So, if you want to provide signed tags, you need to create releases via the terminal.

3) Which PKI & release workflow

Okay, the PKI to use seems pretty straight forward to me, GPG. Git has great integration with GPG and it's really easy sign and verify git objects.

The only requirement for this is to have a valid GPG setup and a private key.

Creating signed tags is trivial, just pass -s:

git tag -s v1.0

And then to verify the signature we use the -v option:

git tag -v v1.0

3) Mobile workflow

If you choose to go with lightweight tags this is trivial, just use the web interface provided by Github or Gitlab. If you want annotated tags (which allow you to sign them), you need a git client that spports them. For eg. on Android I think the easiest way to achieve this is just running git from the terminal, which should also allow you to have a valid GPG setup. Other option is to ssh to a remote server, but this is not as secure.

4) Interactivity

You can have your gpg/keyring setup caching the passphrase on a timeout, this is what I do. The passphrase caching does not happen at the git level, git asks gpg to sign something and then gpg asks you to unlock the key.

Note: If you want you can get a hardware security key, such as a Yubikey or a Nitrokey, I believe they should make your gpg setup a bit more secure and even easier to use in some cases. This also has some benefits and drawbacks so it's not a clear decision :)

Well, I think I managed to explain the requirements for such setup and the differences between the various approaches. Let me know if you have any questions!

jaraco commented 4 years ago

Thanks for the considerate response.

You can have your gpg/keyring setup caching the passphrase on a timeout.

This behavior is insufficient for my goals. I'd really like to avoid adding an interactive step at any stage. I've already authenticated to my workstation - that should be sufficient to unlock/decrypt any credentials (and ideally without storing it in plaintext on the filesystem). I'm able to do that with my one-time-password generator, x509 certs, cryptocurrency wallet keys, and passwords for my most sensitive assets. It should be possible for something like a signing key. Requiring a passphrase that I have to enter is a no-go. If the tooling can grab the passphrase from the output of a command, I can work with that.

I'm considering adopting the proposed approach with the following tweak:

Part of my workflow has been to configure the following in my .gitconfig:

keyring master $ git config --get alias.atag
tag -a -m 

And I use git atag n.n.n; git push to create a release. But this approach is ugly. It requires that I run a non-standard command (atag) and that the alias is configured on every workstation I use (not too bad as I sync my .gitconfig).

I also have some projects that rely on bump2version, a fork of bumpversion but with one tweak to enable annotated tags.

Can you imagine a way in which I could run some command, and if I'm on my primary workstation where the GPG credentials are present, it will produce a signed tag, but if I run the same command on another workstation where the GPG credentials (or tooling) is not present, it will create an unsigned (still annotated) tag?

I could imagine writing this software and making sure that I install this software on whatever machine I'm developing on, but I'm not sure I want to invest that kind of effort just for my own workflow.

I look forward to your thoughts and recommendations.

jaraco commented 3 years ago

It sounds like the workflow I desire may not be possible yet. I'll implement signed tags when signing can be integrated into a lightweight maintenance workflow.