From 39b738a0bd4e41f33539df4ba7f00e9ec0f87394 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 24 Jun 2020 11:31:54 +0200 Subject: [PATCH 01/19] add initial draft of the crates.io token scopes RFC --- text/0000-crates-io-token-scopes.md | 223 ++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 text/0000-crates-io-token-scopes.md diff --git a/text/0000-crates-io-token-scopes.md b/text/0000-crates-io-token-scopes.md new file mode 100644 index 00000000000..18ecb4b7f98 --- /dev/null +++ b/text/0000-crates-io-token-scopes.md @@ -0,0 +1,223 @@ +# crates.io token scopes RFC + +- Feature Name: `crates_io_token_scopes` +- Start Date: (fill me in with today's date, YYYY-MM-DD) +- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) +- crates.io issue: [rust-lang/crates.io#0000](https://github.com/rust-lang/crates.io/issues/0000) + +# Summary +[summary]: #summary + +This RFC proposes implementing scopes for crates.io tokens, allowing users to +choose which endpoints the token is allowed to call and which crates it's +allowed to affect. + +# Motivation +[motivation]: #motivation + +While the current implementation of API tokens for crates.io works fine for +developers using the `cargo` CLI on their workstations, it's not acceptable for +CI scenarios, such as publishing crates automatically once a git tag is pushed. + +The implementation of scoped tokens would allow users to restrict the actions a +token can do, decreasing the blast radius in case of automation bugs or token +compromise. + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +During token creation, the user will be prompted to select the permissions the +token will have. Two sets of independent scopes will be available: the +endpoints the token is authorized to call, and the crates the token is allowed +to act on. + +## Endpoint scopes + +The user will be able to choose one or more endpoint scopes. This RFC proposes +adding the following endpoint scopes: + +* **publish**: allows uploading new crates or new versions of existing crates + the user owns +* **yank**: allows yanking and unyanking existing versions of the user's crates +* **change-owners**: allows inviting new owners or removing existing owners + +More endpoint scopes might be added in the future without the need of a +dedicated RFC. + +There will also be an option to opt out of endpoint scopes and retain the +permission model implemented before this RFC (called "legacy"), which allows +access to all (documented and undocumented) crates.io API endpoints except for +adding new tokens. + +The crates.io UI will pre-select the scopes needed by the `cargo` CLI, which at +the time of writing this RFC are `publish`, `yank` and `change-owners`. The +user will have to explicitly opt into extra scopes or the legacy permission +model. + +Tokens created before the implementation of this RFC will use the legacy +permission model. + +## Crates scope + +The user will be able to opt into limiting which crates the token can act on by +defining a crates scope. It will be possible to set a crates scope even with +the legacy endpoint scope. + +The crates scope can be left empty to allow the token to act on all the crates +owned by the user, or it can contain the comma-separated list of crate names +the token can interact with. Crate names can contain `*` to match one or more +characters. + +For example, a crates scope of `serde,serde-*` allows the token to act on the +`serde` crate or any crate starting with `serde-`, if the user is an owner of +those crates. + +The crates scope will allow access to all present and future crates matching +it. When an endpoint that doesn't interact with crates is called by a token +with a crates scope, the crates scope will be ignored and the call will be +authorized. + +Tokens created before the implementation of this RFC won't have a crates scope, +and it will be possible to use a crates scope in a token with the legacy +endpoint scope. + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +Endpoint scopes and crates scope are two completly separate systems, and can be +used independently from one another. Token scopes will be implemented entirely +on the crates.io side, and there will be no change to `cargo` or alternate +registries. + +## Endpoint scopes + +The scopes proposed by this RFC allow access to the following endpoints: + +| 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` | **change-owners** | +| `DELETE /crates/:crate_id/owners` | **change-owners** | + +Removing an endpoint from a scope or adding an existing endpoint to an existing +scope will be considered a breaking change. Adding newly created endpoints to +an existing scope will be allowed only at the moment of their creation, if the +crates.io team believes the new endpoint won't grant more privileges than the +existing set of endpoints in that scope. + +## Crates scope + +The pattern for the crate scope is desugared into a regular expression, +following these rules: + +* **`^`** is added at the start of the pattern, and **`|`** is added at the end of it. +* **`,`** is desugared into `|`, separating multiple patterns. +* **`*`** is desugared into `.+`, matching one or more characters greedily. +* All other characters are quoted to prevent them from having a special meaning. + +As an example, the following pattern: + +``` +foo,foo-* +``` + +... is desugared into the following regex: + +``` +^foo|foo\-.+$ +``` + +Any combination of those characters is allowed, but crates.io might define a +complexity limit for the generated regular expressions. + +Every time an endpoint acting on a crate is called the regex is desugared, +compiled and used to match the crate name. If no match is found the request is +denied. + +The check for the crates scope is separate from crate ownership: having a scope +that technically permits to interact with a crate the user doesn't own will be +accepted by the backend, but a warning will be displayed if the pattern doesn't +match any crate owned by the user. + +# Drawbacks +[drawbacks]: #drawbacks + +No drawbacks are known at the time of writing the RFC. + +# Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +An alternative implementation for endpoint scopes could be to allow users to +directly choose every endpoint they want to allow for their token, without +having to choose whole groups at a time. This would result in more granularity +and possibly better security, but it would make the UX to create new tokens way +more complex (requiring more choices and a knowledge of the crates.io API). + +An alternative implementation for crate scopes could be to have the user select +the crates they want to allow in the UI instead of having to write a pattern. +That would make creating a token harder for people with lots of crates (which, +in the RFC author's opinion, are more likely to need crate scopes than a person +with just a few crates), and it wouldn't allow new crates matching the pattern +but uploaded after the token's creation from being accessed. + +Finally an alternative could be to do nothing, and encourage users to create +"machine accounts" for each set of crates they own. A drawback of this is that +GitHub's terms of service limit how many accounts a single person could have. + +# Prior art +[prior-art]: #prior-art + +The endpoint scopes system is heavily inspired by GitHub, while the rest of the +proposal is similar to nuget. Here is how popular package registries implements +scoping: + +* [nuget] (package registry for the .NET ecosystem) implements three endpoint + scopes (publish new packages, publish new versions, unlist packages), has a + mandatory expiration and supports specifying which packages the token applies + to, either by checking boxes or defining a single glob pattern. + [(documentation)][nuget-docs] +* [npm] (package registry for JavaScript) implements a binary + "read-only"/"read-write" permission model, also allowing to restrict the IP + ranges allowed to access the token, but does not allow restricting the + packages a token is allowed to change. [(documentation)][npm-docs] +* [pypi] (package registry for Python) only implements the "upload packages" + permission, and allows to scope each token to a *single* package. + [(documentation)][pypi-docs] +* [rubygems] (package registry for Ruby) and [packagist] (package registry for + PHP) don't implement any kind of scoping for the API tokens. + +[nuget]: https://www.nuget.org/ +[nuget-docs]: https://docs.microsoft.com/en-us/nuget/nuget-org/scoped-api-keys +[npm]: https://www.npmjs.com +[npm-docs]: https://docs.npmjs.com/creating-and-viewing-authentication-tokens +[pypi]: https://pypi.org +[pypi-docs]: https://pypi.org/help/#apitoken +[rubygems]: https://rubygems.org/ +[packagist]: https://packagist.org/ + +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +* Should there be separate scopes for publishing a new crate and a version of + an existing crate, instead of the single `publish` scope? +* Are there more scopes that would be useful to implement from the start? +* Should crate scopes be allowed on tokens with the legacy endpoint scope? +* Is the current behavior of crate scopes on endpoints that don't interact with + crates the best, or should a token with crate scopes prevent access to + endpoints that don't act on crates? + +# Future possibilities +[future-possibilities]: #future-possibilities + +A future extension to the crates.io authorization model could be adding an +optional expiration to tokens, to limit the damage over time if a token ends up +being leaked. + +Another extension could be an API endpoint that programmatically creates +short-lived tokens (similar to what AWS STS does for AWS Access Keys), allowing +to develop services that provide tokens with a short expiration time to CI +builds. Such tokens would need to have the same set or a subset of the parent +token's scopes: this RFC should consider that use case and avoid the +implementation of solutions that would make the check hard. From d0ee1db5282125ea2c95257d4e4839b9ed3b6da0 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 24 Jun 2020 11:45:13 +0200 Subject: [PATCH 02/19] fix typo --- text/0000-crates-io-token-scopes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-crates-io-token-scopes.md b/text/0000-crates-io-token-scopes.md index 18ecb4b7f98..da768ef9dda 100644 --- a/text/0000-crates-io-token-scopes.md +++ b/text/0000-crates-io-token-scopes.md @@ -112,7 +112,7 @@ existing set of endpoints in that scope. The pattern for the crate scope is desugared into a regular expression, following these rules: -* **`^`** is added at the start of the pattern, and **`|`** is added at the end of it. +* **`^`** is added at the start of the pattern, and **`$`** is added at the end of it. * **`,`** is desugared into `|`, separating multiple patterns. * **`*`** is desugared into `.+`, matching one or more characters greedily. * All other characters are quoted to prevent them from having a special meaning. From d4cad47de42b932447dfc95db89465ea5f472326 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 24 Jun 2020 13:01:54 +0200 Subject: [PATCH 03/19] clarify that token scopes allow interacting with future matches --- text/0000-crates-io-token-scopes.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/text/0000-crates-io-token-scopes.md b/text/0000-crates-io-token-scopes.md index da768ef9dda..a068f11fbe8 100644 --- a/text/0000-crates-io-token-scopes.md +++ b/text/0000-crates-io-token-scopes.md @@ -69,8 +69,8 @@ the token can interact with. Crate names can contain `*` to match one or more characters. For example, a crates scope of `serde,serde-*` allows the token to act on the -`serde` crate or any crate starting with `serde-`, if the user is an owner of -those crates. +`serde` crate or any present or future crates starting with `serde-`, if the +user is an owner of those crates. The crates scope will allow access to all present and future crates matching it. When an endpoint that doesn't interact with crates is called by a token @@ -132,9 +132,9 @@ foo,foo-* Any combination of those characters is allowed, but crates.io might define a complexity limit for the generated regular expressions. -Every time an endpoint acting on a crate is called the regex is desugared, -compiled and used to match the crate name. If no match is found the request is -denied. +The pattern will be evaluated during each API call, and if no match is found +the request will be denied. Because it's evaluated every time, a crates scope +will allow interacting with matching crates published after token creation. The check for the crates scope is separate from crate ownership: having a scope that technically permits to interact with a crate the user doesn't own will be From 4caaba694fe44fb7b82555e58535d8239effa3e6 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 24 Jun 2020 13:14:56 +0200 Subject: [PATCH 04/19] improve wording of the motivation section Co-authored-by: XAMPPRocky <4464295+XAMPPRocky@users.noreply.github.com> --- text/0000-crates-io-token-scopes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-crates-io-token-scopes.md b/text/0000-crates-io-token-scopes.md index a068f11fbe8..81f4cc63c04 100644 --- a/text/0000-crates-io-token-scopes.md +++ b/text/0000-crates-io-token-scopes.md @@ -20,7 +20,7 @@ developers using the `cargo` CLI on their workstations, it's not acceptable for CI scenarios, such as publishing crates automatically once a git tag is pushed. The implementation of scoped tokens would allow users to restrict the actions a -token can do, decreasing the blast radius in case of automation bugs or token +token can do, decreasing the risk in case of automation bugs or token compromise. # Guide-level explanation From 905a789234bfb6cab11cff748c579e1e337da9f8 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 25 Jun 2020 10:23:49 +0200 Subject: [PATCH 05/19] split the publish scope in publish-new and publish-update --- text/0000-crates-io-token-scopes.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/text/0000-crates-io-token-scopes.md b/text/0000-crates-io-token-scopes.md index 81f4cc63c04..b9074a420c7 100644 --- a/text/0000-crates-io-token-scopes.md +++ b/text/0000-crates-io-token-scopes.md @@ -36,8 +36,9 @@ to act on. The user will be able to choose one or more endpoint scopes. This RFC proposes adding the following endpoint scopes: -* **publish**: allows uploading new crates or new versions of existing crates - the user owns +* **publish-new**: allows publishing new crates +* **publish-update**: allows publishing a new version for existing crates the + user owns * **yank**: allows yanking and unyanking existing versions of the user's crates * **change-owners**: allows inviting new owners or removing existing owners @@ -50,9 +51,9 @@ access to all (documented and undocumented) crates.io API endpoints except for adding new tokens. The crates.io UI will pre-select the scopes needed by the `cargo` CLI, which at -the time of writing this RFC are `publish`, `yank` and `change-owners`. The -user will have to explicitly opt into extra scopes or the legacy permission -model. +the time of writing this RFC are `publish-new`, `publish-update`, `yank` and +`change-owners`. The user will have to explicitly opt into extra scopes or the +legacy permission model. Tokens created before the implementation of this RFC will use the legacy permission model. @@ -95,7 +96,8 @@ The scopes proposed by this RFC allow access to the following endpoints: | Endpoint | Required scope | | --- | --- | -| `PUT /crates/new` | **publish** | +| `PUT /crates/new` (new crates) | **publish-new** | +| `PUT /crates/new` (existing crates) | **publish-update** | | `DELETE /crates/:crate_id/:version/yank` | **yank** | | `PUT /crates/:crate_id/:version/unyank` | **yank** | | `PUT /crates/:crate_id/owners` | **change-owners** | @@ -200,8 +202,6 @@ scoping: # Unresolved questions [unresolved-questions]: #unresolved-questions -* Should there be separate scopes for publishing a new crate and a version of - an existing crate, instead of the single `publish` scope? * Are there more scopes that would be useful to implement from the start? * Should crate scopes be allowed on tokens with the legacy endpoint scope? * Is the current behavior of crate scopes on endpoints that don't interact with From 8e5a9adf248218cb2c9e375b2cceb5124dc9dbc9 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Mon, 29 Jun 2020 18:22:49 +0200 Subject: [PATCH 06/19] change the meaning of * from .+ to .* --- text/0000-crates-io-token-scopes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/0000-crates-io-token-scopes.md b/text/0000-crates-io-token-scopes.md index b9074a420c7..ee5aff8d047 100644 --- a/text/0000-crates-io-token-scopes.md +++ b/text/0000-crates-io-token-scopes.md @@ -66,7 +66,7 @@ the legacy endpoint scope. The crates scope can be left empty to allow the token to act on all the crates owned by the user, or it can contain the comma-separated list of crate names -the token can interact with. Crate names can contain `*` to match one or more +the token can interact with. Crate names can contain `*` to match zero or more characters. For example, a crates scope of `serde,serde-*` allows the token to act on the @@ -116,7 +116,7 @@ following these rules: * **`^`** is added at the start of the pattern, and **`$`** is added at the end of it. * **`,`** is desugared into `|`, separating multiple patterns. -* **`*`** is desugared into `.+`, matching one or more characters greedily. +* **`*`** is desugared into `.*`, matching zero or more characters greedily. * All other characters are quoted to prevent them from having a special meaning. As an example, the following pattern: From 804b6ee1be8917a29a2e89d76a84d63643b4eedc Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Mon, 29 Jun 2020 18:28:14 +0200 Subject: [PATCH 07/19] update examples using * --- text/0000-crates-io-token-scopes.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/text/0000-crates-io-token-scopes.md b/text/0000-crates-io-token-scopes.md index ee5aff8d047..ff4108a2945 100644 --- a/text/0000-crates-io-token-scopes.md +++ b/text/0000-crates-io-token-scopes.md @@ -69,9 +69,9 @@ owned by the user, or it can contain the comma-separated list of crate names the token can interact with. Crate names can contain `*` to match zero or more characters. -For example, a crates scope of `serde,serde-*` allows the token to act on the -`serde` crate or any present or future crates starting with `serde-`, if the -user is an owner of those crates. +For example, a crates scope of `lazy_static,serde*` allows the token to act on +the `lazy_static` crate or any present or future crates starting with `serde` +(including `serde` itself), if the user is an owner of those crates. The crates scope will allow access to all present and future crates matching it. When an endpoint that doesn't interact with crates is called by a token @@ -122,13 +122,13 @@ following these rules: As an example, the following pattern: ``` -foo,foo-* +foo,bar-* ``` ... is desugared into the following regex: ``` -^foo|foo\-.+$ +^foo|bar\-.*$ ``` Any combination of those characters is allowed, but crates.io might define a From 5c43b7dd51761b2761604547ef78ec9502a6bebc Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Mon, 29 Jun 2020 18:38:53 +0200 Subject: [PATCH 08/19] mentionn separate confirmation of token actions as a future possibility --- text/0000-crates-io-token-scopes.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/text/0000-crates-io-token-scopes.md b/text/0000-crates-io-token-scopes.md index ff4108a2945..e9187e8be89 100644 --- a/text/0000-crates-io-token-scopes.md +++ b/text/0000-crates-io-token-scopes.md @@ -221,3 +221,9 @@ to develop services that provide tokens with a short expiration time to CI builds. Such tokens would need to have the same set or a subset of the parent token's scopes: this RFC should consider that use case and avoid the implementation of solutions that would make the check hard. + +To increase the security of CI environments even more, we could implement an +option to require a separate confirmation for the actions executed by tokens. +For example, we could send a confirmation email with a link the owners have to +click to actually publish the crate uploaded by CI, preventing any mailicious +action with stolen tokens. From cffcaf83182942566f32cf57a1bba1ecd53be8ac Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 3 Sep 2020 11:20:23 +0200 Subject: [PATCH 09/19] fix regex --- text/0000-crates-io-token-scopes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/0000-crates-io-token-scopes.md b/text/0000-crates-io-token-scopes.md index e9187e8be89..d71f9789a8f 100644 --- a/text/0000-crates-io-token-scopes.md +++ b/text/0000-crates-io-token-scopes.md @@ -114,7 +114,7 @@ existing set of endpoints in that scope. The pattern for the crate scope is desugared into a regular expression, following these rules: -* **`^`** is added at the start of the pattern, and **`$`** is added at the end of it. +* **`^(`** is added at the start of the pattern, and **`)$`** is added at the end of it. * **`,`** is desugared into `|`, separating multiple patterns. * **`*`** is desugared into `.*`, matching zero or more characters greedily. * All other characters are quoted to prevent them from having a special meaning. @@ -128,7 +128,7 @@ foo,bar-* ... is desugared into the following regex: ``` -^foo|bar\-.*$ +^(foo|bar\-.*)$ ``` Any combination of those characters is allowed, but crates.io might define a From 0db28dffe7900c1ff3131bdee0cce5462c65c2c9 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 3 Sep 2020 11:27:16 +0200 Subject: [PATCH 10/19] add the legacy scope, replacing legacy tokens --- text/0000-crates-io-token-scopes.md | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/text/0000-crates-io-token-scopes.md b/text/0000-crates-io-token-scopes.md index d71f9789a8f..ffc936aed4e 100644 --- a/text/0000-crates-io-token-scopes.md +++ b/text/0000-crates-io-token-scopes.md @@ -41,28 +41,25 @@ adding the following endpoint scopes: user owns * **yank**: allows yanking and unyanking existing versions of the user's crates * **change-owners**: allows inviting new owners or removing existing owners +* **legacy**: allows accessing all the endpoints on crates.io except for + creating new tokens, like tokens created befores the implementation of this + RFC. More endpoint scopes might be added in the future without the need of a dedicated RFC. -There will also be an option to opt out of endpoint scopes and retain the -permission model implemented before this RFC (called "legacy"), which allows -access to all (documented and undocumented) crates.io API endpoints except for -adding new tokens. - The crates.io UI will pre-select the scopes needed by the `cargo` CLI, which at the time of writing this RFC are `publish-new`, `publish-update`, `yank` and `change-owners`. The user will have to explicitly opt into extra scopes or the legacy permission model. -Tokens created before the implementation of this RFC will use the legacy -permission model. +Tokens created before the implementation of this RFC will default to the legacy +scope. ## Crates scope The user will be able to opt into limiting which crates the token can act on by -defining a crates scope. It will be possible to set a crates scope even with -the legacy endpoint scope. +defining a crates scope. The crates scope can be left empty to allow the token to act on all the crates owned by the user, or it can contain the comma-separated list of crate names @@ -78,9 +75,8 @@ it. When an endpoint that doesn't interact with crates is called by a token with a crates scope, the crates scope will be ignored and the call will be authorized. -Tokens created before the implementation of this RFC won't have a crates scope, -and it will be possible to use a crates scope in a token with the legacy -endpoint scope. +Tokens created before the implementation of this RFC will default to an empty +crate scope filter (equivalent to no restrictions). # Reference-level explanation [reference-level-explanation]: #reference-level-explanation @@ -102,6 +98,7 @@ The scopes proposed by this RFC allow access to the following endpoints: | `PUT /crates/:crate_id/:version/unyank` | **yank** | | `PUT /crates/:crate_id/owners` | **change-owners** | | `DELETE /crates/:crate_id/owners` | **change-owners** | +| everything except `PUT /me/tokens` | **legacy** | Removing an endpoint from a scope or adding an existing endpoint to an existing scope will be considered a breaking change. Adding newly created endpoints to @@ -203,7 +200,6 @@ scoping: [unresolved-questions]: #unresolved-questions * Are there more scopes that would be useful to implement from the start? -* Should crate scopes be allowed on tokens with the legacy endpoint scope? * Is the current behavior of crate scopes on endpoints that don't interact with crates the best, or should a token with crate scopes prevent access to endpoints that don't act on crates? From 04b48cbb5ac69de4552ca495953f4635065f980d Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 3 Sep 2020 11:28:42 +0200 Subject: [PATCH 11/19] clarify only non-alpha are quoted --- text/0000-crates-io-token-scopes.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/text/0000-crates-io-token-scopes.md b/text/0000-crates-io-token-scopes.md index ffc936aed4e..05e0180bc6d 100644 --- a/text/0000-crates-io-token-scopes.md +++ b/text/0000-crates-io-token-scopes.md @@ -114,7 +114,8 @@ following these rules: * **`^(`** is added at the start of the pattern, and **`)$`** is added at the end of it. * **`,`** is desugared into `|`, separating multiple patterns. * **`*`** is desugared into `.*`, matching zero or more characters greedily. -* All other characters are quoted to prevent them from having a special meaning. +* All other non-alphanumeric characters are quoted to prevent them from having + a special meaning. As an example, the following pattern: From f5f12a74eac37a17ac0df9057ddd6621f09fc953 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 3 Sep 2020 11:33:04 +0200 Subject: [PATCH 12/19] add future possibility for tokens owned by a team --- text/0000-crates-io-token-scopes.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/text/0000-crates-io-token-scopes.md b/text/0000-crates-io-token-scopes.md index 05e0180bc6d..1d6f5c04ecb 100644 --- a/text/0000-crates-io-token-scopes.md +++ b/text/0000-crates-io-token-scopes.md @@ -224,3 +224,7 @@ option to require a separate confirmation for the actions executed by tokens. For example, we could send a confirmation email with a link the owners have to click to actually publish the crate uploaded by CI, preventing any mailicious action with stolen tokens. + +To remove the need for machine accounts, a future RFC could propose adding API +tokens owned by teams, granting access to all resources owned by that team and +allowing any team member to revoke them. From 7cede63ab7cc1d7148ab7768a63bfeaf0f9132af Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 19 Oct 2022 10:44:58 +0200 Subject: [PATCH 13/19] token-scopes: Align endpoint table --- text/0000-crates-io-token-scopes.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/text/0000-crates-io-token-scopes.md b/text/0000-crates-io-token-scopes.md index 1d6f5c04ecb..faae984e2ff 100644 --- a/text/0000-crates-io-token-scopes.md +++ b/text/0000-crates-io-token-scopes.md @@ -90,15 +90,15 @@ registries. The scopes proposed by this RFC allow access to the following endpoints: -| Endpoint | Required scope | -| --- | --- | -| `PUT /crates/new` (new crates) | **publish-new** | -| `PUT /crates/new` (existing crates) | **publish-update** | -| `DELETE /crates/:crate_id/:version/yank` | **yank** | -| `PUT /crates/:crate_id/:version/unyank` | **yank** | -| `PUT /crates/:crate_id/owners` | **change-owners** | -| `DELETE /crates/:crate_id/owners` | **change-owners** | -| everything except `PUT /me/tokens` | **legacy** | +| Endpoint | Required scope | +|------------------------------------------|--------------------| +| `PUT /crates/new` (new crates) | **publish-new** | +| `PUT /crates/new` (existing crates) | **publish-update** | +| `DELETE /crates/:crate_id/:version/yank` | **yank** | +| `PUT /crates/:crate_id/:version/unyank` | **yank** | +| `PUT /crates/:crate_id/owners` | **change-owners** | +| `DELETE /crates/:crate_id/owners` | **change-owners** | +| everything except `PUT /me/tokens` | **legacy** | Removing an endpoint from a scope or adding an existing endpoint to an existing scope will be considered a breaking change. Adding newly created endpoints to From 826ebc0373e48c7117ae38a8c3c246a9a2ebd303 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 19 Oct 2022 10:46:57 +0200 Subject: [PATCH 14/19] token-scopes: Fix typos --- text/0000-crates-io-token-scopes.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/text/0000-crates-io-token-scopes.md b/text/0000-crates-io-token-scopes.md index faae984e2ff..11f58e0c1e5 100644 --- a/text/0000-crates-io-token-scopes.md +++ b/text/0000-crates-io-token-scopes.md @@ -42,7 +42,7 @@ adding the following endpoint scopes: * **yank**: allows yanking and unyanking existing versions of the user's crates * **change-owners**: allows inviting new owners or removing existing owners * **legacy**: allows accessing all the endpoints on crates.io except for - creating new tokens, like tokens created befores the implementation of this + creating new tokens, like tokens created before the implementation of this RFC. More endpoint scopes might be added in the future without the need of a @@ -81,8 +81,8 @@ crate scope filter (equivalent to no restrictions). # Reference-level explanation [reference-level-explanation]: #reference-level-explanation -Endpoint scopes and crates scope are two completly separate systems, and can be -used independently from one another. Token scopes will be implemented entirely +Endpoint scopes and crates scope are two completely separate systems, and can be +used independently of one another. Token scopes will be implemented entirely on the crates.io side, and there will be no change to `cargo` or alternate registries. @@ -162,7 +162,7 @@ in the RFC author's opinion, are more likely to need crate scopes than a person with just a few crates), and it wouldn't allow new crates matching the pattern but uploaded after the token's creation from being accessed. -Finally an alternative could be to do nothing, and encourage users to create +Finally, an alternative could be to do nothing, and encourage users to create "machine accounts" for each set of crates they own. A drawback of this is that GitHub's terms of service limit how many accounts a single person could have. @@ -222,7 +222,7 @@ implementation of solutions that would make the check hard. To increase the security of CI environments even more, we could implement an option to require a separate confirmation for the actions executed by tokens. For example, we could send a confirmation email with a link the owners have to -click to actually publish the crate uploaded by CI, preventing any mailicious +click to actually publish the crate uploaded by CI, preventing any malicious action with stolen tokens. To remove the need for machine accounts, a future RFC could propose adding API From 67d07c6535059d65c5d8d88d39553f8ea8d4ec62 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 19 Oct 2022 12:56:27 +0200 Subject: [PATCH 15/19] token-scopes: Remove endpoint scope preselection paragraph We might want to discuss the default endpoint scope separately. It could be beneficial to not select anything by default, or just `publish-update` as a default for CI systems. --- text/0000-crates-io-token-scopes.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/text/0000-crates-io-token-scopes.md b/text/0000-crates-io-token-scopes.md index 11f58e0c1e5..8cb1a779711 100644 --- a/text/0000-crates-io-token-scopes.md +++ b/text/0000-crates-io-token-scopes.md @@ -48,11 +48,6 @@ adding the following endpoint scopes: More endpoint scopes might be added in the future without the need of a dedicated RFC. -The crates.io UI will pre-select the scopes needed by the `cargo` CLI, which at -the time of writing this RFC are `publish-new`, `publish-update`, `yank` and -`change-owners`. The user will have to explicitly opt into extra scopes or the -legacy permission model. - Tokens created before the implementation of this RFC will default to the legacy scope. From 48d8cf4f723a92f4bd6f7d961ea432a984c12eca Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 19 Oct 2022 13:04:55 +0200 Subject: [PATCH 16/19] token-scopes: Rephrase "crates scope" guide to only allow wildcards at the end --- text/0000-crates-io-token-scopes.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/text/0000-crates-io-token-scopes.md b/text/0000-crates-io-token-scopes.md index 8cb1a779711..4d32d276a26 100644 --- a/text/0000-crates-io-token-scopes.md +++ b/text/0000-crates-io-token-scopes.md @@ -56,19 +56,19 @@ scope. The user will be able to opt into limiting which crates the token can act on by defining a crates scope. -The crates scope can be left empty to allow the token to act on all the crates -owned by the user, or it can contain the comma-separated list of crate names -the token can interact with. Crate names can contain `*` to match zero or more -characters. +The crates scope can contain a list of crate name patterns the token can +interact with. Crate name patterns can either be regular crate names or they +can end with a `*` character to match zero or more characters. -For example, a crates scope of `lazy_static,serde*` allows the token to act on -the `lazy_static` crate or any present or future crates starting with `serde` -(including `serde` itself), if the user is an owner of those crates. +For example, a crate name pattern of `lazy_static` will only make the token +apply to the corresponding crate, while `serde*` allows the token to act on +any present or future crates starting with `serde` (including `serde` itself), +but only if the user is an owner of those crates. The crates scope will allow access to all present and future crates matching it. When an endpoint that doesn't interact with crates is called by a token with a crates scope, the crates scope will be ignored and the call will be -authorized. +authorized, unless limited by an endpoint scope (see above). Tokens created before the implementation of this RFC will default to an empty crate scope filter (equivalent to no restrictions). From fb5579799cf621ed7344c29f30e02a10b8283983 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 19 Oct 2022 13:05:48 +0200 Subject: [PATCH 17/19] token-scopes: Split "no change to cargo" part into dedicated paragraph This is somewhat unrelated to the previous sentence and deserves its own paragraph --- text/0000-crates-io-token-scopes.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/text/0000-crates-io-token-scopes.md b/text/0000-crates-io-token-scopes.md index 4d32d276a26..b67ec496927 100644 --- a/text/0000-crates-io-token-scopes.md +++ b/text/0000-crates-io-token-scopes.md @@ -77,9 +77,10 @@ crate scope filter (equivalent to no restrictions). [reference-level-explanation]: #reference-level-explanation Endpoint scopes and crates scope are two completely separate systems, and can be -used independently of one another. Token scopes will be implemented entirely -on the crates.io side, and there will be no change to `cargo` or alternate -registries. +used independently of one another. + +Token scopes will be implemented entirely on the crates.io side, and there will +be no change necessary to `cargo` or alternate registries. ## Endpoint scopes From 1d9527ec45fb590566394055fab2e465df04a820 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 19 Oct 2022 13:07:10 +0200 Subject: [PATCH 18/19] token-scopes: Remove regular expression implementation details --- text/0000-crates-io-token-scopes.md | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/text/0000-crates-io-token-scopes.md b/text/0000-crates-io-token-scopes.md index b67ec496927..04dacb44133 100644 --- a/text/0000-crates-io-token-scopes.md +++ b/text/0000-crates-io-token-scopes.md @@ -104,31 +104,7 @@ existing set of endpoints in that scope. ## Crates scope -The pattern for the crate scope is desugared into a regular expression, -following these rules: - -* **`^(`** is added at the start of the pattern, and **`)$`** is added at the end of it. -* **`,`** is desugared into `|`, separating multiple patterns. -* **`*`** is desugared into `.*`, matching zero or more characters greedily. -* All other non-alphanumeric characters are quoted to prevent them from having - a special meaning. - -As an example, the following pattern: - -``` -foo,bar-* -``` - -... is desugared into the following regex: - -``` -^(foo|bar\-.*)$ -``` - -Any combination of those characters is allowed, but crates.io might define a -complexity limit for the generated regular expressions. - -The pattern will be evaluated during each API call, and if no match is found +The patterns will be evaluated during each API call, and if no match is found the request will be denied. Because it's evaluated every time, a crates scope will allow interacting with matching crates published after token creation. From 28049400becab8047c68b0ee861dca8e30613565 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Tue, 8 Nov 2022 11:08:10 +0100 Subject: [PATCH 19/19] token scopes: Adjust RFC number and metadata --- ...es-io-token-scopes.md => 2947-crates-io-token-scopes.md} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename text/{0000-crates-io-token-scopes.md => 2947-crates-io-token-scopes.md} (97%) diff --git a/text/0000-crates-io-token-scopes.md b/text/2947-crates-io-token-scopes.md similarity index 97% rename from text/0000-crates-io-token-scopes.md rename to text/2947-crates-io-token-scopes.md index 04dacb44133..8ab48ac9736 100644 --- a/text/0000-crates-io-token-scopes.md +++ b/text/2947-crates-io-token-scopes.md @@ -1,9 +1,9 @@ # crates.io token scopes RFC - Feature Name: `crates_io_token_scopes` -- Start Date: (fill me in with today's date, YYYY-MM-DD) -- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) -- crates.io issue: [rust-lang/crates.io#0000](https://github.com/rust-lang/crates.io/issues/0000) +- Start Date: 2020-06-24 +- RFC PR: [rust-lang/rfcs#2947](https://github.com/rust-lang/rfcs/pull/2947) +- crates.io issue: [rust-lang/crates.io#5443](https://github.com/rust-lang/crates.io/issues/5443) # Summary [summary]: #summary