rubygems / rfcs

RubyGems + Bundler RFCs
45 stars 40 forks source link

RFC: Proposal for new signing mechanism #37

Open rochlefebvre opened 2 years ago

rochlefebvre commented 2 years ago

Rendered RFC.

We'd like to propose a new gem signing mechanism. We believe the new mechanism will be easier to use and more secure. Our goal is that eventually, almost all gems are signed as a matter of course. The proposed design builds on sigstore, an OpenSSF-backed project for software signatures.

As part of our work, we have developed a proof of concept system that works as a gem plugin.

We have drafted the RFC for an audience who are familiar with RubyGems, but who may not be familiar with sigstore or with the security primitives it utilizes. We note that the reference-level guide section is very detailed, and most of it can be safely skipped on a first reading.

We will be available on the Bundler Slack if you wish to discuss there.

Contributors: @bettymakes, @aellispierce, @jchestershopify, @jenshenny, @tomstuart, @doodzik and @rochlefebvre.

Special thanks to: @dlorenc, @lukehinds and @bobcallaway for help on sigstore questions.

dlorenc commented 2 years ago

On behalf of the Sigstore community, we'd like to voice our support here! Let us know how we can help make this a success.

https://blog.sigstore.dev/sigstore-ruby-ce3591838fe8

joshuagl commented 2 years ago

This is a really nicely written RFC, brilliant work Shopify team!

The detailed breakdown of OIDC and OAuth2 flows in particular is really nice documentation I would love to see included in the sigstore documentation.

I'm not a RubyGems contributor, just an interested observer, but there are a couple of points I was hoping the RFC would include:

dlorenc commented 2 years ago
  • The rekor public instance currently carries a warning that the log may be reset at any time. Does that warning affect the roll-out plans for this implementation?

We'll have some news to share on this soon! But we're hoping to get rid of that disclaimer very soon.

jchestershopify commented 2 years ago

with regards depending on sigstore public infrastructure, have you considered whether RubyGems should run an auditor to detect malicious/compromised log operators?

I think yes, though we didn't cover it in this RFC (we left a lot on the cutting room floor). One critical function would be to email authors when their signature is published, to help them notice if something unexpected has happened. This is already done for gem pushes.

The rekor public instance currently carries a warning that the log may be reset at any time. Does that warning affect the roll-out plans for this implementation?

Yes, but we would gate Phase 1 on sigstore's reaching an official ™️ operational status.

elfotografo007 commented 2 years ago

Great work!

joshuagl commented 2 years ago

with regards depending on sigstore public infrastructure, have you considered whether RubyGems should run an auditor to detect malicious/compromised log operators?

I think yes, though we didn't cover it in this RFC (we left a lot on the cutting room floor). One critical function would be to email authors when their signature is published, to help them notice if something unexpected has happened. This is already done for gem pushes.

The rekor public instance currently carries a warning that the log may be reset at any time. Does that warning affect the roll-out plans for this implementation?

Yes, but we would gate Phase 1 on sigstore's reaching an official ™️ operational status.

The answers I hoped for/expected, thanks @jchestershopify

woodruffw commented 2 years ago

Ditto all the praise above: this is a very exciting improvement to the Gem ecosystem!

I'm currently working with Google and the PyPA (the team than runs PyPI) to implement a nearly identical (and sigstore-based) signing and verification mechanism for the Python packaging ecosystem. My hope is that our parallel work will serve as a good cross-reference (and vice versa) as it proceeds.

This is outside of the scope of the scope of the RFC as-is, but something for the RubyGems ecosystem to consider: PyPI is also gaining support for credential-free authentication via trusted OIDC providers like GitHub (and eventually others) -- we plan to allow PyPI users to mark a particular repository and CI workflow as "trusted," allowing us to derive a temporary API key from the action's OIDC token. A user can then GitHub Actions to publish their package without having to configure an API key, add it as a secret, etc. Something to consider for a future capability within RubyGems as well!

simi commented 2 years ago

Thanks for this RFC :muscle: :pray:.

Looking at the sigstore login picture, does it mean you need GitHub, Google or Microsoft account to be able to sign gem?

rochlefebvre commented 2 years ago

I'm currently working with Google and the PyPA (the team than runs PyPI) to implement a nearly identical (and sigstore-based) signing and verification mechanism for the Python packaging ecosystem. My hope is that our parallel work will serve as a good cross-reference (and vice versa) as it proceeds.

Excellent. My colleague @jchestershopify is suggesting we organize a cross-ecosystem working group on sigstore Slack. Stay tuned!

This is outside of the scope of the scope of the RFC as-is, but something for the RubyGems ecosystem to consider: PyPI is also gaining support for credential-free authentication via trusted OIDC providers like GitHub (and eventually others) -- we plan to allow PyPI users to mark a particular repository and CI workflow as "trusted," allowing us to derive a temporary API key from the action's OIDC token. A user can then GitHub Actions to publish their package without having to configure an API key, add it as a secret, etc. Something to consider for a future capability within RubyGems as well!

We expect to support CI OIDC tokens assigned to jobs/actions as an alternative to performing a web sign in. Fulcio already has support for GitHub action tokens. I don't have the best grasp on this scenario, but I hope others can propose solutions.

In the meantime, sigstore auth already supports single use refresh tokens, which is an attractive way to decouple web authentication from gem signing. Here's what we're thinking:

  1. While you have access to a browser, acquire a "signing token" to use in your next gem build.
    $ gem signatures --token
    <same browser-based sign in as shown in RFC>
    Signing token: ChlqaWVxc2RobjVkNTczankzY3Y0bjdoYTd1EhlyMzUzeWtjM3NnNHBrcHd2bmt0Mmxyd2k0

    Later on, in some job or as part of a script, this token can be used instead of having to interact with a browser:

    $ gem build --sign --signing-token ChlqaWVxc2RobjVkNTczankzY3Y0bjdoYTd1EhlyMzUzeWtjM3NnNHBrcHd2bmt0Mmxyd2k0 foo
    Gem `foo` signed as person@example.com

    Refresh token are much longer-lived than the ID tokens we get from the regular flow (which expires after one minute).

jchestershopify commented 2 years ago

Looking at the sigstore login picture, does it mean you need GitHub, Google or Microsoft account to be able to sign gem?

For right now, yes. As sigstore adds more supported identity providers the list will grow.

simi commented 2 years ago

As part of our work, we have developed a proof of concept system that works as a gem plugin.

:thinking: Looking at the current (reference) implementation, I see a huge list of big dependencies (like activesupport). If we plan to make this part of RubyGems by default, we will need to find way how to incorporate this feature with minimal dependencies, since RubyGems itself (by design) can't have any dependencies on gems.

There are few gem exceptions being vendored under RubyGems namespace.

https://github.com/rubygems/rubygems/blob/975f9dcbef882bf457dab200d31bc87044e9a2b0/Rakefile#L88-L125

But vendoring whole activesupport would not be pribably accepted. I'm using activesupport as an example only here. Same can be applied to any dependency.

:thinking: On the other side (as also mentioned in RFC) OAuth2 is super complex and implementing it again just for this purpose doesn't make any sense.

My initial idea is to keep this as a gem plugin, support --sign parameter by default (without having gem installed) and install this gem if this parameter is used and the gem plugin is missing (similar what we do currently for missing bundler version). That way it can still use the dependencies and make it usable in default RubyGems installation. As a side-benefit we can ensure latest supported version is installed.

simi commented 2 years ago

Looking at the sigstore login picture, does it mean you need GitHub, Google or Microsoft account to be able to sign gem?

For right now, yes. As sigstore adds more supported identity providers the list will grow.

Are there any plans to support kind of "custom" account using just an email? That way no "vendoring" is going to happen.

jchestershopify commented 2 years ago

Are there any plans to support kind of "custom" account using just an email? That way no "vendoring" is going to happen.

Not as such, given the way the flow works. Part of the security guarantee comes from having a third party vouch that the signer legitimately controls the given email address.

The list isn't fixed; if someone sets up a non-vendor identity provider that's trustworthy and reputable enough, it could be added to the list.

simi commented 2 years ago

Are there any plans to support kind of "custom" account using just an email? That way no "vendoring" is going to happen.

Not as such, given the way the flow works. Part of the security guarantee comes from having a third party vouch that the signer legitimately controls the given email address.

The list isn't fixed; if someone sets up a non-vendor identity provider that's trustworthy and reputable enough, it could be added to the list.

And is there any reason to not be able just to provide your email on your own instead of relying on (for example) GitHub handing over your email to the service? If I understand it well, it is all about getting the email.

jchestershopify commented 2 years ago

And is there any reason to not be able just to provide your email on your own instead of relying on (for example) GitHub handing over your email to the service?

The difficulty is that this puts us back where we are: you have to manually decide to trust a claim, rather than falling back on independent roots of trust. Right now I can upload a gem with email set to Rails maintainers. If I could supply an arbitrary email address to signing, I could sign as Rafael França and there'd be no independent verification that I am who I say I am. Then you can have shenanigans like this "commit from Linus".

The approach we outline forces you to prove, with a third party attestation, that you really do control the email address.

simi commented 2 years ago

And is there any reason to not be able just to provide your email on your own instead of relying on (for example) GitHub handing over your email to the service?

The difficulty is that this puts us back where we are: you have to manually decide to trust a claim, rather than falling back on independent roots of trust. Right now I can upload a gem with email set to Rails maintainers. If I could supply an arbitrary email address to signing, I could sign as Rafael França and there'd be no independent verification that I am who I say I am. Then you can have shenanigans like this "commit from Linus".

The approach we outline forces you to prove, with a third party attestation, that you really do control the email address.

I'm not sure I do follow, but what would be different when I provide email and just confirm in an received email I have access to it? I can understand if sigstore is in beta and early stage,and this is not implemented since going OAuth to get email could be easier. But I don't see any blocker to add this "manual" option as well. I can check (open discussion) somewhere on sigstore side.

jchestershopify commented 2 years ago

I'm not sure I do follow, but what would be different when I provide email and just confirm in an received email I have access to it?

I think I see your point now. What you're proposing would be to provide a rubygems-operated OIDC identity provider. Which would be possible, but there are two serious drawbacks.

  1. Running an identity provider is hard. OAuth2 and OIDC protocols are complex. The servers are likewise complex. It's one of those leave-it-to-an-expert things.
  2. It means that account takeovers of a rubygems.org account == ability to sign as that user. The proposal above separates the email verification to a different authority, which creates a significant hurdle to attackers: they have to compromise both the rubygems.org account and an account at an identity provider.
simi commented 2 years ago

I'm not sure I do follow, but what would be different when I provide email and just confirm in an received email I have access to it?

I think I see your point now. What you're proposing would be to provide a rubygems-operated OIDC identity provider. Which would be possible, but there are two serious drawbacks.

  1. Running an identity provider is hard. OAuth2 and OIDC protocols are complex. The servers are likewise complex. It's one of those leave-it-to-an-expert things.
  2. It means that account takeovers of a rubygems.org account == ability to sign as that user. The proposal above separates the email verification to a different authority, which creates a significant hurdle to attackers: they have to compromise both the rubygems.org account and an account at an identity provider.

I understand OAuth2 and OIDC is complex, but I don't understand why we need this complexity just to get an email address. Being able to login using RubyGems credentials would be nice, but I still think just providing email (with verification email link) would be the simplest way in here.


If we stick with current options, we will "vendorize" whole feature since it will require Google, Microsoft, or GitHub account to use. It actually adds security to open source software traded for requirement of having 3rd party account on proprietary service. That doesn't make any sense IMHO. Me, personally, would not use such feature. So I'm looking for alternatives to make it useful without any 3rd party service being involved as well. :pray:

jchestershopify commented 2 years ago

I understand your concern and it's valid. We think this problem will be faced by everybody who is currently working on sigstore-based systems (we are aware of efforts by NPM, Gradle and PyPI).

Can we have a little time to huddle on this question? We'll try to work out what can be done.

mensfeld commented 2 years ago

@simi has a point. During my work with and in RubyGems, I've encountered several gems developers/maintainers including core Ruby members that do not have their code in Github and use private domain-based emails. While I have a Github account and I would be ok using it, I spent 3 years moving away from gmail and I can imagine people that do not have any of the ones mentioned above.

That said, I am in favour of improving the current signing capabilities of RubyGems as I do not see a lot of usage of it.

simi commented 2 years ago

I understand your concern and it's valid. We think this problem will be faced by everybody who is currently working on sigstore-based systems (we are aware of efforts by NPM, Gradle and PyPI).

Can we have a little time to huddle on this question? We'll try to work out what can be done.

Sure, no rush. I'm looking for possibilities to contribute as well. I have joined sigstore Slack. I will continue on this topic in there. For now it is clear, plan is to use what sigstore provides. :pray: we can get sigstore to state this will not be limiting users not using any of those 3rd party services.

rochlefebvre commented 2 years ago

I just want to say: I am very excited by everyone's questions and ideas! Please keep them coming.

We don't have all the answers, which is where the rest of you come in. No one should be discouraged by the amount of work we're proposing. I have no doubt that we'll find the fingers and the keyboards.

dlorenc commented 2 years ago

I understand OAuth2 and OIDC is complex, but I don't understand why we need this complexity just to get an email address. Being able to login using RubyGems credentials would be nice, but I still think just providing email (with verification email link) would be the simplest way in here.

Sigstore maintainer here!

We caught up in the Sigstore slack briefly. Email-based verification is something we should definitely consider adding to Sigstore. At a high level I imagine it could work with something like a link sent to the email address that a user could click on to complete the challenge. I'd prefer we don't run our own login/password system on our own at Sigstore if possible, but something like that should be doable statelessly!

jchestershopify commented 2 years ago

I'll update the "Unanswered questions" to mention:

  1. Email->link based verification flows (h/t @simi & @dlorenc)
  2. Key rotation / key trust (h/t @haydentherapper)
trishankatdatadog commented 2 years ago

Nice. Have not read the full RFC yet, but I see no reason why RubyGems and PyPI (via PEP 458 and PEP 480, perhaps with an update as @axelsimon is working on) cannot agree on the ultimate security model here: SigStore + TUF + in-toto. Then, both RubyGems and PyPI would be compromise-resilient against MitM attacks anywhere between projects/developers and end-users. Happy to discuss further with stakeholders here, especially on threat modelling (critical for measuring security guarantees), and working out all the gory details. The more we collaborate, the stronger the entire ecosystem.

Cc @mnm678 @SantiagoTorres @JustinCappos @joshuagl

P.S. Square once wrote about integrating TUF with RubyGems ;)

varunsh-coder commented 2 years ago

Gem signing as it exists today is unwieldy and little-used, even though signatures form a vital part of ensuring the security of software supply chains... An important risk to the ecosystem is that gems are unsigned, leaving them without valuable guarantees of authenticity

Thanks a lot for the RFC! While reviewing it, I can clearly understand the proposed end-to-end flow for signing and verification.

What I was looking for was also a threat model, like the threat model RFC for OAuth. Is there such an RFC for the ruby program or other package manager programs?

In this RFC, as an example, I cannot understand what specific threats/ attack vectors will be mitigated.

  1. As an example, typosquatting is a threat in the software supply chain, and I am not sure if this proposal addresses that.
  2. Similarly, a malicious maintainer is a threat, which is hard for signing to address.

So, may be listing common threats with examples of past incidents, and how the proposal mitigates those threats will help. Also specifying the limitations, and what threats will not be mitigated will be helpful. Apologies if this is listed somewhere and I did not notice it.

jchestershopify commented 2 years ago

@varunsh-coder

What I was looking for was also a threat model, like the threat model RFC for OAuth. Is there such an RFC for the ruby program or other package manager programs?

Not that I'm aware of. The RFC was written to follow the template. Security isn't a standalone category for RFCs per se. The two RFCs we're championing -- this one and one for a required-MFA policy on top gems -- are based on our reading of available study data (from eg. Backstabber's Knife Collection). We saw (roughly) that typo/combosquatting attacks are the most common attack, account takeover is second, and repository compromise is third. This RFC addresses repository compromise and to a lesser extent account takeover, MFA addresses account takeover. We note that previous attempts at controlling typosquatting weren't wholly successful. We didn't aim to address typo/combosquatting in rubygems.org at this time.

A full threat model for rubygems would probably have large overlap with a model for most source package managers (so for PyPI, Maven, NPM etc) since they have a great deal of mutual inspiration and convergent evolution. We would gladly use one as a reference if available, but given the RFC mechanism it wasn't in scope to develop one. We focused on what the available data told us.

varunsh-coder commented 2 years ago

@varunsh-coder

What I was looking for was also a threat model, like the threat model RFC for OAuth. Is there such an RFC for the ruby program or other package manager programs?

Not that I'm aware of. The RFC was written to follow the template. Security isn't a standalone category for RFCs per se. The two RFCs we're championing -- this one and one for a required-MFA policy on top gems -- are based on our reading of available study data (from eg. Backstabber's Knife Collection). We saw (roughly) that typo/combosquatting attacks are the most common attack, account takeover is second, and repository compromise is third. This RFC addresses repository compromise and to a lesser extent account takeover, MFA addresses account takeover. We note that previous attempts at controlling typosquatting weren't wholly successful. We didn't aim to address typo/combosquatting in rubygems.org at this time.

Thanks a lot @jchestershopify for the clarification. If the primary goal is to address repository compromise (which I am assuming is rubygems.org in this case), isn't something like Trillian a better way (Minimise the impact of a hacked download server)? I am not sure if each owner should have to sign each gem to address repository compromise.

W.r.t account takeover, looks like signing will not offer prevention, right? It will cause attacker to add another email address to the gem spec. Such an addition could have been a valid action by a gem owner, so it would be hard to tell whether it was because of an account takeover or some other reason... Moreover gem owners will anyways need to enable MFA as part of the other RFC to counter account takeover...

So overall, my recommendation would be to investigate if something like Trillian can be used to solve for repository compromise, so gem owners do not have to pay the tax of signing each gem. Unless there is other value to this, that I am missing...

jchestershopify commented 2 years ago

If the primary goal is to address repository compromise (which I am assuming is rubygems.org in this case), isn't something like Trillian a better way

What we're describing is similar to what the Trillian article describes. That's not coincidental: sigstore's transparency log, Rekor, uses Trillian as its substrate.

More generally, my goal in using a transparency log is to force attackers to move in the open. As @rochlefebvre noted in this reply, we see gem signing as contributing to detection and recovery. I think it's a mistake to assume that prevention is the only acceptable way to improve security. Increasing the chances of detecting an attacker, and providing a reliable log of all attacker actions for remedial work, means that the net value of an attack is greatly reduced.

varunsh-coder commented 2 years ago

If the primary goal is to address repository compromise (which I am assuming is rubygems.org in this case), isn't something like Trillian a better way

What we're describing is similar to what the Trillian article describes. That's not coincidental: sigstore's transparency log, Rekor, uses Trillian as its substrate.

I think there is a big difference between the Trillian article and this RFC. This RFC requires each gem owner to sign each gem, whereas the Trillian article does not. This is a huge difference from a cost/benefit perspective. When one can get the same benefit, without the extra cost of each gem owner signing each gem, why require signing?

More generally, my goal in using a transparency log is to force attackers to move in the open. As @rochlefebvre noted in this reply, we see gem signing as contributing to detection and recovery. I think it's a mistake to assume that prevention is the only acceptable way to improve security.

I think the community would be happy to see any improvement, whether it is with prevention, detection, or recovery. I just cannot understand how this RFC addresses detection or recovery. Moreover, the RFC does not clarify these points. It is my humble request to please clarify in the RFC what specific value it adds.

@rochlefebvre request you to please clarify how this RFC helps with detection of account takeover? If a new email address is added in the gemspec, how does one know that it is an account takeover, or that the maintainer simply decided to add a new email address?

simi commented 2 years ago

@rochlefebvre request you to please clarify how this RFC helps with detection of account takeover? If a new email address is added in the gemspec, how does one know that it is an account takeover, or that the maintainer simply decided to add a new email address?

I would like to mention currently adding email to gemspec doesn't allow that email account to push the gem and gemspec email should not be used to determine any permission.

jchestershopify commented 2 years ago

gemspec email should not be used to determine any permission.

To be clear, we are not proposing such a change.

SantiagoTorres commented 2 years ago

Hello, sorry I've been lurking on this conversation. I wanted to help clarify a minor misconception.

I think there is a big difference between the Trillian article and this RFC. This RFC requires each gem owner to sign each gem, whereas the Trillian article does not. This is a huge difference from a cost/benefit perspective. When one can get the same benefit, without the extra cost of each gem owner signing each gem, why require signing?

Because they serve two different purposes. One is to avoid a malicious server from lying, the other is to avoid a server from re-writing history. You don't get the same benefit from using a vanilla tlog. Overall, there are ways to combine these two in which the tlog provides baseline security for all packages while mission-critical packages are signed by conscious developers.

jchestershopify commented 2 years ago

Overall, there are ways to combine these two in which the tlog provides baseline security for all packages while mission-critical packages are signed by conscious developers.

Indeed, we foreshadowed this in the discussion of adding other types of events as log entries, particularly gem push operations.

simi commented 2 years ago

Overall, there are ways to combine these two in which the tlog provides baseline security for all packages while mission-critical packages are signed by conscious developers.

Indeed, we foreshadowed this in the discussion of adding other types of events as log entries, particularly gem push operations.

Indeed^2. Let's focus on gem signing here. For the other security improvements anyone is welcomed to open RFC addressing those.

SantiagoTorres commented 2 years ago

Indeed, we foreshadowed this in the discussion of adding other types of events as log entries, particularly gem push operations.

Most definitely. I believe it would be possible to have the server submit push operations (i.e., so as to provide tamper-evident repository state), and have developers push signatures. I'm not sure what'd this entail for the scope of this RFC, but a design like this is definitely not at odds with this best-of-both-worlds long-term goal.

jrochkind commented 2 years ago

gemspec email should not be used to determine any permission.

To be clear, we are not proposing such a change. [— @jchestershopify]

I thought that this proposal would make gemspec email authorize someone with that verified email address to sign the gem release? But am I misunderstanding?

simi commented 2 years ago

gemspec email should not be used to determine any permission.

To be clear, we are not proposing such a change.

I thought that this proposal would make gemspec email authorize someone with that verified email address to sign the gem release? But am I misunderstanding?

It is part of the current RFC, but I think that is wrong and it should be changed.

jchestershopify commented 2 years ago

I thought that this proposal would make gemspec email authorize someone with that verified email address to sign the gem release? But am I misunderstanding?

I don't think of it as "authorizing" per se. This design has no effect on rubygems.org's permissions scheme.

varunsh-coder commented 2 years ago

gemspec email should not be used to determine any permission.

To be clear, we are not proposing such a change.

I thought that this proposal would make gemspec email authorize someone with that verified email address to sign the gem release? But am I misunderstanding?

It is part of the current RFC, but I think that is wrong and it should be changed.

IMHO, it is the code repository URL, and not the email address that should be identity for the signing. As a consumer, if I decide to use a gem, I am implicitly deciding to use the source code in that location. As a producer, if I own that source code location, and can somehow prove that as part of signing, a compromised repo will not be able to spoof it. Just my 2 cents...

s.metadata    = { "source_code_uri" => "https://github.com/example/example" }
varunsh-coder commented 2 years ago

I thought that this proposal would make gemspec email authorize someone with that verified email address to sign the gem release? But am I misunderstanding?

I don't think of it as "authorizing" per se. This design has no effect on rubygems.org's permissions scheme.

It has no effect on the rubygems.org permissions scheme @jchestershopify, but RFC uses it as the identity for signing. Whereas a consumer has no way to know if developer1@gmail.com is really the email address of the developer who wrote the gem...This is why a compromised repository can spoof it, and it reduces the value of signing, and it doesn't help with detection...

jchestershopify commented 2 years ago

@varunsh-coder could you elaborate with an example or walkthrough? I'd like to make sure I understand your point before replying.

varunsh-coder commented 2 years ago

@varunsh-coder could you elaborate with an example or walkthrough? I'd like to make sure I understand your point before replying.

Sure. Let us say there is a gem gemA which is popular. The owner of the gem signs it with their email address developer1@gmail.com. Consumers install it and the signature is validated.

Now, let us assume the repository rubygems.org is compromised. The attacker decides to release a new version. The attacker creates a gemspec file on disk, changes the email address to developer2@gmail.com (which the attacker owns). The attacker then signs this gem and makes the new version available on rubygems.org.

Consumers get the latest version, and everything looks fine. Sure, a new email address is used for signing, but as a consumer how am I to know if developer2@gmail.com is not the right email address for whoever is developing gemA. After all, their earlier email address was developer1@gmail.com...

If you want, I will be happy to get on a call and discuss this...Also see my recommendation to somehow use source code location as identify for signing. Not sure how to do it, but as a consumer, the identity for a package is really the source code location, not the developer email address...

jchestershopify commented 2 years ago

I think I understand better now.

Consumers get the latest version, and everything looks fine. Sure, a new email address is used for signing, but as a consumer how am I to know if developer2@gmail.com is not the right email address for whoever is developing gemA. After all, their earlier email address was developer1@gmail.com...

This goes back to prevent - detect - recover. It is not claimed that gem signing prevents account takeovers. But it does make detection at all possible, which is a step change from the current state of being.

In terms of direct repository compromise in itself, I think the best tool to apply would be TUF. We see it as complementary but outside the scope of this RFC. In the meantime, signatures will require attackers who compromise a repository to use a different email address (increasing the odds of detection) and will not enable them to tamper with already-signed gems.

varunsh-coder commented 2 years ago

I think I understand better now.

Consumers get the latest version, and everything looks fine. Sure, a new email address is used for signing, but as a consumer how am I to know if developer2@gmail.com is not the right email address for whoever is developing gemA. After all, their earlier email address was developer1@gmail.com...

This goes back to prevent - detect - recover. It is not claimed that gem signing prevents account takeovers. But it does make detection at all possible, which is a step change from the current state of being.

In terms of direct repository compromise in itself, I think the best tool to apply would be TUF. We see it as complementary but outside the scope of this RFC. In the meantime, signatures will require attackers who compromise a repository to use a different email address (increasing the odds of detection) and will not enable them to tamper with already-signed gems.

@jchestershopify can you please help me understand how use of different email address for signing increases odds of detection? We can continue with the same scenario and walkthrough. So let us say attacker has released a hijacked version signed with developer2@gmail.com. Now everyone knows a new email address is used for signing. In this scenario, how do we go from this step to confirming that latest version of gemA is compromised? The reason I am trying to understand this is, because you might have ideas around this, that might help build other countermeasures. I am unable to connect the dots between the event of new email address is used for signing and therefore confirmed that latest version of gemA is compromised.

flavorjones commented 2 years ago

IMHO, it is the code repository URL, and not the email address that should be identity for the signing

Worth noting that a gem may contain non-source artifacts, such as the precompiled native libraries present in gems like grpc, nokogiri, and others.

In these cases, it is the source plus the packaging process (either manual or automated) that need attestation, and in the absence of reproducible builds (which, notably, are being investigated at https://github.com/rubygems/rubygems/issues/3118) we can use the identity of the person packaging the gem file as a proxy.

rochlefebvre commented 2 years ago

Gem signing is an effective way of creating a direct link of authenticity between gem build and gem install, which are the start and end points of an assembled gem's journey across the software supply chain. Our proposed scheme says "I control this email address, and I assembled the following gem". It is not a statement of provenance nor of its bill of materials.

Many questions focus on the rubygems.org link in the chain, which is of course the most prominent one. Some doubt the effectiveness of a signature when the gem repository or the gem owner account have been compromised. No doubt, in the face of either compromise, a gem signature is not the only/best measure. But let's not forget about mirrors, CI/CD providers, build caches, etc. Any one link invites tampering with the gem file, and a missing/mismatched signature would be demonstrably suspect.

jchestershopify commented 2 years ago

An update: we’ve been listening to feedback in this thread, in an adjacent issue on the sigstore/fulcio repo, and to a reddit discussion. Feedback we saw centered on (1) the use of 3rd-party identity providers (IdPs) such as Github, Google et al, (2) whether to provide an alternative “email option” and (3) the use of email addresses in a gemspec as the basis of a signing certificate’s subject alternative name.

Speaking for myself, I’m much more ambivalent about relying on 3rd party IdPs than I was last week. But in the interests of reaching the best decision, we wanted to lay out two main options and gather feedback from folks in this thread.

The two basic options are:

  1. Do everything with 3rd party IdPs, potentially with an open “email option”. In this option the present prototype represents what the final outcome is likely to be. To account for folks who do not want to use Google accounts etc, we would provide a kind of escape hatch for folks to prove their control of an email address through a secondary process. Identity is based on an email account. Signing certificates use email addresses as their subject alternative name.
  2. Rubygems.org becomes the 2nd party IdP. In this option rubygems.org provides an OIDC endpoint and sigstore is configured to trust it. The prototype represents some of the final outcome, but users would no longer have to choose an identity provider; our reference-level explanation would be mostly unchanged. Identity is based on the rubygems.org account. Signing certificates use the rubygems.org user profile URI as their subject alternative name.

There are quite a few differences between these two options. In the interests of brevity we’ve laid out the pros and cons in dot point form.

Do everything with 3rd-party IdPs + provide an open “email option”

Pros

Cons

Do everything with Rubygems IdP

Pros

Cons

Unknowns

di commented 2 years ago

Thanks @jchestershopify, that does a really good job of laying out the pros & cons.

Taking a stab at the unknowns:

What happens to the browser flow? Can we cut out the grant step?

I think it would be desirable to keep this flow as it's probably easier & more familiar for manual signing. Since OIDC is a layer on top of OAuth, it shouldn't be a lot of extra work to support.

How do we get the gem owner’s profile URI into the signing certificate’s subject alternative name? What claim or scope do we use? How do we standardize with other package managers?

I think this would be set by the rubygems IdP in the identity token used to sign the artifact, and Fulcio would infer it from there. For example, if you use the GitHub Actions identity token to sign an artifact via cosign sign-blob --identity-token, the identity token has claims like:

  "job_workflow_ref": "di/<repo_name>/.github/workflows/<workflow_name>.yml@refs/heads/main",

And the resulting signature has something like:

Subject Alternative Name:
                URI:https://github.com/di/<repo_name>/.github/workflows/ci.yml@refs/heads/main

Which Fulcio created based on the identity token.

jrochkind commented 2 years ago

As someone who is a committer/releaser for a couple dozen gems with small distributed teams, rubygems as an IDP is appealing to me, and seems like it will require me incorporating fewer additional moving parts/services/concepts into my workflow.

Have any of the rubygems maintainer team been on this discussion yet? Are you having any offline conversations with them? Including them and their perspective and concerns and interests in this discussion up front seems important.