Using The Update Framework in Sigstore
A Delicious TUF sandwich
We use TUF in the Sigstore project to protect our own keys and infrastructure, but we’re also hoping to make it possible for end users to use TUF on their own, using the Sigstore tools. I call this the TUF sandwich!
The top slice in the sandwich is the Sigstore root of trust. We created this initial root during the key ceremony we performed back in June, and it consists of five individual hardware keys that are held by sigstore key holders. There’s no magic system to bootstrap a trust root, especially in a distributed community, so we did the only real option — a public display of the entire process.
This trust root is checked into a public Git repository where the contents can be distributed, monitored, and fetched from as they evolve over time. The initial ceremony was observed and verified by the community in real time, and that history is preserved in the Git/GitHub logs for anyone to audit later in case something goes wrong.
Because this root uses TUF, it contains the full set of keys used to sign release artifacts and metadata, as well as the rules and policies used to update this root over time. That means users can verify any signed artifact or piece of metadata at a later date as long as they have this initial trusted root, even if the keys and root configuration itself has changed. Here’s roughly what this would look like:
We’ve just started to actually distribute this root inside the Cosign tool, which will contain a pinned version to verify updated metadata against. Users can swap this out for their own trust root, rely on ours, or even use a combination if they like. When we update the root keys, cosign will be able to automatically fetch this new (untrusted) metadata and verify it against the older root before deciding to trust it going forward.
This root currently protects the signing keys used for our Root CA (Fulcio) and our transparency log (Rekor), as well as the keys used to sign release artifacts for these projects. Setting up a root is fun, but it’s also hard. So up next, we’re hoping to share this root with other projects to make the bootstrapping problem a little bit easier!
TUF has a concept called delegations, where a root policy can authorize other sets of keys for a specific role. These roles are flexible and user-defined, although there are a few standard ones built in (snapshot, timestamp, etc.). For other projects that want to piggy-back on a trusted root but still use their own keys and signing infrastructure, we can create a custom role that authorizes their keys to sign their own artifacts through a “delegation”.
This means the Sigstore TUF root could be used to verify and establish other trust roots, operated by their project maintainers. If this sounds similar to web PKI, that’s because it is! This “super root” concept is analogous to a root CA that issues certificates directly, but also signs certificates for other intermediate CAs, which can in turn issue their own certificates. That looks like:
Identities in TUF
Another interesting area we’re currently prototyping is improving the way identities are managed in TUF. Signatures are mathematical operations that map meaningless streams of bytes to other meaningless streams of bytes. Public keys are unwieldy and hard to manage, so this is where “certificates”, or other identity systems come in.
You don’t really care whether the person that holds the private key corresponding to the public key
foobar signed something, you care whether your friend Jim signed it. In typical computer science fashion, we can solve this with another level of indirection, by building a system that maps public keys to identities.
We’ve done this in Sigstore with the Fulcio CA, which allows users to get ephemeral certificates based on Open ID Connect identities (email or SPIFFE-based). What’s up next is merging this system in with TUF, so TUF policies can be expressed in terms of these human-readable identities instead of just plain public keys. A grossly oversimplified comparison between the two might look like:
Since Fulcio is backed by the Sigstore trust root, everything can chain back up to that initial key ceremony, or use an internal corporate PKI that might already exist. Follow along the TUF Augmentation Proposal here if you’re interested!
The Sigstore infrastructure isn’t for everyone, particularly those in sensitive or air gapped systems. Even though this isn’t a core part of the Sigstore mission, we still believe that we should all speak the same protocols and use the same tools where possible. Internal systems using Sigstore tooling will help us reach the ubiquity we eventually need to secure open source, so we’re happy to help organizations get this setup and running!
This means that it will be possible to use the TUF support in Sigstore and cosign without relying on our trust root or infrastructure at all! We’re getting ready to land support for creating new trust roots using the
cosign tool, where all the root metadata is stored in an OCI registry.
OCI registries can be used to store and distribute arbitrary artifacts, meaning this flow can be used to create custom package repositories with full TUF support. These specifications are all widely adopted and supported by dozens of vendors, so we won’t have any excuses left for not securely distributing artifacts.
The delegation support is great for large open source projects, and detached TUF is great for large companies, but small open source communities are still stuck without great options. The overhead of running a full TUF root can be a lot to manage, so we’re also working on making this easier with some new tooling!
This is still under design, but we’re planning on a lightweight policy manifest that can be checked directly into a git repo, which will describe how to authenticate artifacts against that repo and who is authorized to perform releases. These policies can be signed with real keys or verified against an OIDC identity (like a GitHub account!), and can evolve over time like any other TUF policy.
If a full delegation under the sigstore root doesn’t make sense, there are still a few other options! The simplest option is to remember and trust the first they’re fetched (TOFU). This system works great for SSH and other systems, but in ephemeral CI environments where state is hard to persist, trust on first use can easily become trust on every use.
To mitigate this, we can use the Rekor transparency log! The initial policies can be “bound” to this repository with a signed attestation in the transparency log, providing a globally consistent access point. Trust on first use can shift from “trust on my first use” to “trust on anyone’s first use, with a single call to Rekor.
Everything is a TUF problem?
The TUF concepts can be hard to grasp, but they solve important problems that may not be obvious at first. If you take the time to understand TUF, every problem starts to look like a TUF one! We rely on TUF across the Sigstore project, and we’re hoping to make TUF as easy to use as possible for everyone else.
I hope this post gives an overview of the way TUF can be used with the Sigstore project. Some of these ideas are still early, but we have actual working code landing in real systems every week. If you’re interested in helping out or using any of this, please reach out!