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

Support Private Sigstore with ENV config only. #320

Open
ChevronTango opened this issue May 23, 2023 · 16 comments
Open

Support Private Sigstore with ENV config only. #320

ChevronTango opened this issue May 23, 2023 · 16 comments
Labels
bug Something isn't working

Comments

@ChevronTango
Copy link

Description

I am currently running a Private Sigstore stack using the Scaffold Helm chart. I cureently have gitsign installed using the following:

git config --global gitsign.fulcio https://<my-fulcio-url>
git config --global gitsign.rekor https://<my-rekor-url>
git config --global gitsign.issuer https://<my-dex-url>

using this I am able to get gitsign to properly sign the commits, however I am unable to get gitsign to verify any commits I make.

failed to verify detached signature: x509: certificate signed by unknown authority

I understand this is something to do with TUF, and the documentation here is almost non-existant so I did some digging. I have tuf enabled and hosted via the scaffold helm chart, though I don't quite understand how this works or how to interact with it to properly manage my roots.

I have read that if you are using a private sigstore instance you must run cosign initialize first however this breaks my setup as I don't have cosign installed and I want to be able to configure everything using environment variables so I can easily point my machine at any private sigstore instance I wish.

Is there a way to use only environment variables to configure gitsign to securely connect to, trust, and verify a private sigstore instance? I am happy to encode json into such a variable, or have a root.json file downloaded if it will help.

Is the scaffold helm chart complete and does its tuf config require any more additional manual steps? the helm chart has been deployed successfully and is running smoothly, but I am certain I've missed something.

@ChevronTango ChevronTango added the bug Something isn't working label May 23, 2023
@wlynch
Copy link
Member

wlynch commented May 23, 2023

I've been thinking for a bit that we should just port cosign initialize to gitsign. Would this be okay for your use case?

cc @znewman01 who knows more than I do about the TUF + Sigstore. 🙂

@wlynch
Copy link
Member

wlynch commented May 23, 2023

Alternatively, you should be able to set the Fulcio / Rekor certs manually via the following environment variables:

  • SIGSTORE_FULCIO_ROOT
  • SIGSTORE_REKOR_PUBLIC_KEY
  • SIGSTORE_CT_LOG_PUBLIC_KEY_FILE

But you won't get all the TUF magic for root key management.

See https://docs.sigstore.dev/cosign/custom_components/ for some documentation for how this works - this was written for cosign but it should be the same for gitsign as well

@wlynch
Copy link
Member

wlynch commented May 23, 2023

Added gitsign initialize in #321

@ChevronTango
Copy link
Author

Added gitsign initialize in #321

Oh wow! That's super quick. Thanks @wlynch. Massively impressed with the support you all provide for this project!

With that, will there be anything that needs to exist on disk still to use a private sigstore stack? Any certificates or files that should be present or will initialize pull everything it needs from config and env variables?

@ChevronTango
Copy link
Author

I realized some context for my objective might help with understanding my request.

Gitpod are making moves to add gitsign into all of there workspaces so that all commits from all users are automatically signed. I have some clients working on sensitive workloads that wish to host a private sigstore for their work. Gitpod provides a way for users or teams to define a set of environment variables that are loaded in to a gitpod workspace at startup.

My objective is define a set of environment variables so that gitpods gitsign client automatically switches to the private sigstore instance, without the user having to run any additional scripts. I would ideally like it to silently switch over to the private sigstore for signing

@wlynch
Copy link
Member

wlynch commented May 24, 2023

gitsign initialize should pull in everything it needs and save it to $HOME/.sigstore based on the TUF mirror args you give it. It should be a one time setup (unless you need to swap between trust roots).
If you don't need TUF for your private instance, then the env variables I listed above should work.

cc @priyawadhwa who's been looking into getting gitsign working with Chainguard's private sigstore service and might know some more tricks.

@saisatishkarra
Copy link

Does this also handle populating the Timestamping service Authority trust roots using the specified TSA URL in env variables using the initialize command? If not, is there a recommended way to rotate the trust roots and verify old artifacts signed using TSA?

@ChevronTango
Copy link
Author

ChevronTango commented May 24, 2023

gitsign initialize should pull in everything it needs and save it to $HOME/.sigstore based on the TUF mirror args you give it. It should be a one time setup (unless you need to swap between trust roots). If you don't need TUF for your private instance, then the env variables I listed above should work.

cc @priyawadhwa who's been looking into getting gitsign working with Chainguard's private sigstore service and might know some more tricks.

My worry is that this still requires a local file (the root.json) and a command gitsign initizialize to be run in order for a workspace to use our private store. If I want my engineers to be using our sigstore instance, I need to instruct them to run a command or configure all our workspaces with additional commands, rather than configuring a set of global environment variables that switch gitsign over seamlessly.

Our workspaces are ephemeral and varied, and setting env vars is the only real universal way I have of configuring them all simultaneously

@ChevronTango
Copy link
Author

@wlynch is there any appetite for this feature? We are keen to use a private sigstore stack, but the gitsign initialize call being required is actually quite awkward for us with how our environments work. If there's any way to have gitsign automatically switch to our private instance using Environment Variables alone it would massively jumpstart our whole orgs adoption of this stack.

@wlynch
Copy link
Member

wlynch commented Jun 14, 2023

I'm open to it!

If you have control over the user environment, you could consider a workaround like running gitsign initialize on login via .profile or something similar.

If you're interested in adding this as a new feature, there's some subtleties we'd have to work through -

  • What information would the user need to provide? The root + mirror that is usually passed into gitsign initialize?
  • What happens if there's already existing TUF root present and the environment variable is set? Do we need to add support for handling multiple roots?

/cc @znewman01 who probably has opinions about this. 🙂

@ChevronTango
Copy link
Author

ChevronTango commented Jun 14, 2023

If you have control over the user environment, you could consider a workaround like running gitsign initialize on login via .profile or something similar.

So most of our environments are virtualised, so limit access to the underlying image and OS, but environment variables are easy for us to configure, which is why I'm keen on this approach. We also have potentially a few different sigstores so being able to say which one a container is using just in those env variables, and being able to switch them around, would be massive.

  • What information would the user need to provide? The root + mirror that is usually passed into gitsign initialize?

I think so, though specifically I think we need to avoid the need to have a file on disk. That can certainly be another option, but if the JSON could instead be in the env variable's content that would be ideal for this kind of free flowing control.

  • What happens if there's already existing TUF root present and the environment variable is set? Do we need to add support for handling multiple roots?

Good question. I think if the env is present then it should be used. if no env is present then the default should be used, and if the user calls gitsign initialize with any params then they should be used. Does that seem like a good order of priority?

@znewman01
Copy link

Taking a step back: Sigstore recommends using TUF as a single root of trust to distribute the root key material for Rekor/Fulcio. There are two actions that you would do:

  1. Initialize: from a TUF root, set up a local TUF repo on disk.
  2. Update: from the current local TUF state, update the TUF repo.

This suggests to me that there are two knobs to configure: a TUF root to initialize from, and where the TUF repo state lives. Right now, we don't make it very easy to change either. Note that the "TUF root to initialize from" is only going to get used the first time.

We also have potentially a few different sigstores so being able to say which one a container is using just in those env variables, and being able to switch them around, would be massive.

Great, let's figure out what changes we need to make to support that use case, which seems reasonable.

Are these environments ephemeral? So you're mostly just initializing the TUF configuration once? If that's the case, I'd actually consider skipping TUF and just supplying the root keys for Fulcio/Rekor directly in the config for these environments, as you're not really getting the benefits of TUF.

If they're longer-lived, then you'll want configure both the initial TUF root and the location of the TUF repo in tandem.

What happens if there's already existing TUF root present and the environment variable is set? Do we need to add support for handling multiple roots?
Good question. I think if the env is present then it should be used. if no env is present then the default should be used, and if the user calls gitsign initialize with any params then they should be used. Does that seem like a good order of priority?

I'd actually argue the opposite: if the local repo is configured, that should override the root to initialize from. The reason being that the local TUF repo will update the root of trust.

but if the JSON could instead be in the env variable's content that would be ideal for this kind of free flowing control.

Despite my aesthetic objections to putting a file's worth of JSON in an environment variable, this should work 😛


So spitballing, I think I'd actually recommend the following (feel free to change the names):

  • $SIGSTORE_DIR: the Sigstore root configuration directory (default: ~/.sigstore).
  • $SIGSTORE_TUF_REPO_NAME: where the TUF repo lives, relative to the Sigstore config directory (the default right now is ~/.sigstore/root).
  • $SIGSTORE_TUF_ROOT_FILE and $SIGSTORE_TUF_ROOT_DATA: used for initialization only. I think I'd prefer not to have this, and copying the roots into $SIGSTORE_DIR/$SIGSTORE_TUF_REPO_NAME manually. Then, your environment could copy in a complete $SIGSTORE_DIR with a bunch of roots in it. But I can live with these if needed.

A cleaner approach might be to introduce some notion of "profiles"—basically, a config file with a bunch of options. Then each profile could have its own TUF repo and all you'd have to do to switch between them is set SIGSTORE_PROFILE. But that requires a bit more thought, and I think we'd prefer to unblock you sooner.

@ChevronTango
Copy link
Author

Thanks @znewman01 , all that sounds very sensible and I defer to your expertise on the matter.

Yes, our environments are meant to be ephemeral, so the initialize is the only part I think we need for us to focus on. As mentioned, we have limited ability to configure files into them, but env we can set easily. I agree, JSON in a env feels inelegant (maybe Base64 it?) But requiring the file is not something we can do at scale.

An additional thought, would this also mean you could provide the json direct to gitsign initialize as a parameter instead of pointing to a file? That's not something that we need ourselves, but worth considering that option for others.

I think the profile idea makes sense. I know that initialize is called automatically on first run of gitsign, and my worry was that this change might confuse some users. Having a profile which would mean users could explicitly choose to use a different setup if they want to would be great for testing and user freedom.

All of this looks sensible though. Is there anything we can do to help delivery?

@wlynch
Copy link
Member

wlynch commented Jun 15, 2023

Despite my aesthetic objections to putting a file's worth of JSON in an environment variable, this should work 😛

There's some limits we'd need to worry about, though this will probably be okay in most cases?

As an alternative, I was talking with @mnm678 yesterday and she recommended using the root mirror URL + checksum and the snapshot URL + checksum. e.g.

SIGSTORE_TUF_ROOT_INIT="https://tuf-repo-cdn.sigstore.dev/1.root.json"
SIGSTORE_TUF_ROOT_INIT_SHA="cd7549b15e7b4e660a89c950bca1bce262a524a5cf909952b66951b5c8667bc6"

An additional thought, would this also mean you could provide the json direct to gitsign initialize as a parameter instead of pointing to a file? That's not something that we need ourselves, but worth considering that option for others.

This would be easy to add - gitsign initialize supports reading from a local file, so we'd just need to add support for reading from stdin.


I think the profile idea makes sense. I know that initialize is called automatically on first run of gitsign, and my worry was that this change might confuse some users. Having a profile which would mean users could explicitly choose to use a different setup if they want to would be great for testing and user freedom.

👍 I'm also worried that it might be unexpected if we blow away the existing client cache because an environment variable is set, though as long as we have the profile / SIGSTORE_TUF_REPO_NAME envvar this should be fine.


Is there anything we can do to help delivery?

If you're interested in contributing, https://github.com/sigstore/sigstore/blob/585296cf6ea94a9a808f82547727edbe1497362e/pkg/tuf/client.go#L351 is where you'd want to look!

@znewman01
Copy link

I like the checksum trick too, that feels less awkward than sticking the whole JSON in the env var.

CC @haydentherapper—we've talked in the past about "grown-up" configuration management for Cosign and other Sigstore clients, like config files, "profiles", etc.

@haydentherapper
Copy link
Contributor

haydentherapper commented Jun 20, 2023

I'd love to have a mapping between CLI flag, env var name, and profile configuration. We've got a mapping between the first two in Cosign currently, there might be a library we can pull in to take care of the latter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

5 participants