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

Allow restricting API token to publish a subset of crates #849

Closed
Nemo157 opened this issue Jul 2, 2017 · 14 comments
Closed

Allow restricting API token to publish a subset of crates #849

Nemo157 opened this issue Jul 2, 2017 · 14 comments
Labels
A-accounts C-enhancement ✨ Category: Adding new behavior or a change to the way an existing feature works

Comments

@Nemo157
Copy link
Member

Nemo157 commented Jul 2, 2017

Now that #688 is available, it would be great to be able to generate a token that is only able to publish a single/limited subset of crates. (A subset to account for things like proc-macro crates commonly being published as a pair of relatively tightly coupled crates).

I'm not sure exactly where the UI for creating these tokens should go, one idea I have had so far:

  • In the "New Token" row on the "Account Settings" page add a little expander with text like "Limit Token Access", expanding that can show a list of all crates with checkboxes for selecting which to be able to publish to.

I feel that would not be great for a user that has access to many many crates though.

Alternative idea I had was to somehow do it via the crate page instead. I don't see any nice to allow adding additional crates to the token that doesn't basically end up with a massive list like above.


Probably worth doing a survey of if any other package repositories support something similar. Closest parallel I can think of is GitHub repository scoped API tokens, but as far as I'm aware they don't allow for accessing a selection of repositories; you either have a token that can access all repositories you have access to, or a token that can access a single repository. I'll try and take a look soon and update here.

@sfackler
Copy link
Member

sfackler commented Jul 7, 2017

This would be fantastic for things like publishing automatically in CI builds.

@est31
Copy link
Member

est31 commented Jan 7, 2020

There is a workaround for this issue which we applied in RustAudio/cpal#337 :

  1. you create a new github user, e.g. reponame-publish-bot
  2. you create a new github team that both you as well as reponame-publish-bot are members of.
  3. that team is given access to the crates.io crate(s) you want the scope to apply to

The crates.io token of the reponame-publish-bot account is now scoped to the set of crates you gave access to. Due to step 2, an attacker gaining access to the token can't remove anyone as owners or add any new owners.

@smarnach
Copy link
Contributor

smarnach commented Jan 7, 2020

@est31 While this approach works, the GitHub terms don't allow more than one free account per individual person, so we can't really make this an official recommendation. Eventually we will need a better permissions model.

@est31
Copy link
Member

est31 commented Jan 7, 2020

GitHub terms don't allow more than one free account per individual person

I didn't know about that rule but looking it up, it exempts machine accounts:

https://help.github.com/en/github/site-policy/github-terms-of-service#3-account-requirements

One person or legal entity may maintain no more than one free Account (if you choose to control a machine account as well, that's fine, but it can only be used for running a machine)

Anyways, I do agree with you that this issue shouldn't be closed or ignored because the workaround exists. There should be a proper feature for it right in crates.io.

@est31
Copy link
Member

est31 commented Apr 14, 2020

Also note that you may only have up to one free machine account (same sections of Github terms as linked above):

A machine account is used exclusively for performing automated tasks. Multiple users may direct the actions of a machine account, but the owner of the Account is ultimately responsible for the machine's actions. You may maintain no more than one free machine account in addition to your free User Account.

So this limits the number of gratis crates.io tokens per person to 2.

@pietroalbini
Copy link
Member

pietroalbini commented May 29, 2020

I'm willing to do the backend work to implement this, and @locks should be available to then hook the changes in the frontend. What I'd like to implement here is two things: endpoint scopes to limit which things a crate can do, and crate scopes to limit which crates the token is allowed to act on.

A mockup of the UI I'd love to see is:

2020-05-29--17-43-10

2020-05-29--17-42-01

Endpoint scopes

During token creation the user will be allowed to choose whether to allow the token access to all the API endpoints (the current behavior) or to select which permissions the token has.

The initial set of scopes will cover all endpoints accessible through cargo:

  • publish: allow publishing new crates and new versions of crates you own
  • yank: allow yanking and unyanking crates
  • owners: allow inviting new owners to the crate, removing existing owners and allow accepting invitations

New scopes might be added in the future to cover more API endpoints. All existing tokens will default to allowing access to all the API endpoints, to maintain backward compatibility.

Note that once we define the set of endpoints a token is allowed to create adding more endpoints to them might be considered a breaking change for existing tokens, as we would allow the token to do things the owner might not want.

The set of endpoints covered by the initial set of scopes is:

Endpoint Required scope
PUT /crates/new publish
DELETE /crates/:crate_id/:version/yank yank
PUT /crates/:crate_id/:version/unyank yank
PUT /crates/:crate_id/owners owners
DELETE /crates/:crate_id/owners owners
GET /me/crate_owner_invitations owners
PUT /me/crate_owner_invitations/:crate_id owners
PUT /me/crate_owner_invitations/accept/:token owners

Crate scopes

During token creation the user will be allowed to choose whether to allow the token access to all the crates they own or just a subset of them. This setting will only apply to endpoints handling crates: other endpoints will continue to work even with crate-scoped tokens.

To select which crates the token is allowed to operate on the user will have to insert a pattern we will match on every request. The pattern will be a simplified regex, only allowing | to include multiple patterns and * to include any character. Example of such patterns include:

  • lazy_static|regex: allow acting on both the lazy_static and regex crates
  • serde|serde-*: allow acting on serde and any crate starting with serde-
  • rustc-ap-*: allow acting on all the crates starting with rustc-ap-

I think this approach is better that letting the user tick checkboxes for each crate they want to allow. Checkboxes benefit accounts with a small amount of crates, while the pattern benefits large projects with tons of crates, and I believe big projects are the ones more likely to scope down which crates a token is allowed to access.

All existing tokens will allow access to any crate, to maintain backward compatibility.

@pietroalbini
Copy link
Member

Note that with the implementation I have in mind adding more scopes should be trivial impl wise, so if anyone watching this issue has other needs let's discuss them!

@est31
Copy link
Member

est31 commented May 29, 2020

owners: allow inviting new owners to the crate, and allow accepting invitations

Important to keep in mind that full owners privilege includes also ability to remove owners of a crate.

@pietroalbini
Copy link
Member

Thanks @est31! Updated the comment to reflect that.

@smarnach
Copy link
Contributor

Thanks a lot for taking this work on! I've got a few comments.

High-level comments

In the long run, I would like to have some kind of permissions model for crate owners as well. Currently we have two access levels: Individual owners have all permissions, and team owners can do everything except managing owners. This model is rather inflexible. I would like to have the ability to add individual owners with only a limited set of permissions.

One idea that comes to mind would be to introduce the concept of a "role" which can have certain permissions. Both tokens and owners could be assigned a role that defines what they are allowed to do. I haven't thought this through, and I only mention it to clarify my point above.

I appreciate that we don't need to solve all problems at once. It is worthwhile to think about future directions anyway since this may make our life easier once we get there.

Specific comments

I would de-emphasize the "access to all API endpoints" somehow. Tokens should by default only have access to the endpoints used by cargo, and it should be very rare for someone to need more than that.

New scopes might be added in the future to cover more API endpoints. All existing tokens will default to allowing access to all the API endpoints, to maintain backward compatibility.

It's not quite clear what you are saying here. Does "existing tokens" refer to tokens existing right now, or to existing tokens when we add further scopes? Because in the former case I agree with you, while in the latter case I think we don't want to add new permissions to tokens with limited permissions.

Note that once we define the set of endpoints a token is allowed to create adding more endpoints to them might be considered a breaking change for existing tokens, as we would allow the token to do things the owner might not want.

That's exactly the reason why I think we shouldn't do that.

The pattern will be a simplified regex, only allowing | to include multiple patterns and * to include any character.

Hmm, that doesn't really sound like a simplified regex, but more like a hybrid using the the | operator from regexes and the * from glob patterns. I'd prefer to simply us a comma-separated list of glob patterns, which is both easier to explain and to implement.

When is the star pattern resolved? The desciption makes it sound like it's just to avoid having to check lots of crate names. However, if the pattern is not immediately resolved, but stored as is and checked everytime an operation is performed, it will apply to all new crates matching the pattern – something that would never be possible with just checkboxes.

@pietroalbini
Copy link
Member

Turns out I also have questions about my proposal now 😅.

I'll turn this into a proper RFC soon.

@pietroalbini
Copy link
Member

Posted an RFC: rust-lang/rfcs#2947

@rbtcollins
Copy link

I'd love to see this - I have write access to some N crates, but some of them are published to by repositories with shared admin access : while the admins should be able to publish to that repositories crates, not my other ones. Creating a service account rather than delegating access through a scoped token is a bit tedious.

@Turbo87
Copy link
Member

Turbo87 commented Nov 13, 2022

closing this now in favor of #5443 :)

@Turbo87 Turbo87 closed this as completed Nov 13, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-accounts C-enhancement ✨ Category: Adding new behavior or a change to the way an existing feature works
Projects
None yet
Development

No branches or pull requests

8 participants