diff --git a/docs/user/trusted-publishers/adding-a-publisher.md b/docs/user/trusted-publishers/adding-a-publisher.md index 928ae74345fc..8f9643a0c24f 100644 --- a/docs/user/trusted-publishers/adding-a-publisher.md +++ b/docs/user/trusted-publishers/adding-a-publisher.md @@ -2,9 +2,9 @@ title: Adding a Trusted Publisher to an Existing PyPI Project --- -# Adding a trusted publisher to an existing PyPI project +# Adding a Trusted Publisher to an existing PyPI project -Adding a trusted publisher to a PyPI project only requires a single setup step. +Adding a Trusted Publisher to a PyPI project only requires a single setup step. On the ["Your projects" page](https://pypi.org/manage/projects/), click "Manage" on any project you'd like to configure: @@ -16,7 +16,7 @@ Then, click on "Publishing" in the project's sidebar: ![Image showing the 'Publishing' link in the project sidebar](/assets/trusted-publishing/project-publishing-link.png) That link will take you to the publisher configuration page for the project, -which will allow you to configure trusted publishers for the different +which will allow you to configure Trusted Publishers for the different platforms supported by PyPI (such as GitHub Actions). To enable a publisher, you need to tell PyPI how to trust it. Each trusted diff --git a/docs/user/trusted-publishers/creating-a-project-through-oidc.md b/docs/user/trusted-publishers/creating-a-project-through-oidc.md index 37a47deac6ac..960b2b308de6 100644 --- a/docs/user/trusted-publishers/creating-a-project-through-oidc.md +++ b/docs/user/trusted-publishers/creating-a-project-through-oidc.md @@ -2,9 +2,9 @@ title: Creating a PyPI Project with a Trusted Publisher --- -# Creating a PyPI project with a trusted publisher +# Creating a PyPI project with a Trusted Publisher -Trusted publishers are not just for pre-existing PyPI projects: you can also use +Trusted Publishers are not just for pre-existing PyPI projects: you can also use them to *create* a PyPI project! This again reduces the number of steps needed to set up a fully automated PyPI @@ -21,7 +21,7 @@ instead of any project's sidebar (since the project doesn't exist yet): ![Image showing the 'Publishing' link in the account sidebar](/assets/trusted-publishing/publishing-link.png) Clicking on "publishing" will bring you to a page with different potential -trusted publishers. The forms on this page behave +Trusted Publishers. The forms on this page behave the same as with publishers for existing projects, except that you also need to provide the name of the PyPI project that will be created. @@ -45,7 +45,7 @@ provide the name of the PyPI project that will be created. !!! note - Like with "normal" trusted publishers, configuring a GitHub Actions + Like with "normal" Trusted Publishing, configuring a GitHub Actions environment is **optional but strongly recommended**. Clicking "Add" will register the "pending" publisher, and show it to you: @@ -63,7 +63,7 @@ provide the name of the PyPI project that will be created. !!! note - Like with "normal" trusted publishers, configuring the subject is optional. + Like with "normal" Trusted Publishing, configuring the subject is optional. Clicking "Add" will register the "pending" publisher, and show it to you: @@ -98,7 +98,7 @@ provide the name of the PyPI project that will be created. !!! note - Like with "normal" trusted publishers, configuring a GitLab CI/CD + Like with "normal" Trusted Publishing, configuring a GitLab CI/CD environment is **optional but strongly recommended**. Clicking "Add" will register the "pending" publisher, and show it to you: diff --git a/docs/user/trusted-publishers/index.md b/docs/user/trusted-publishers/index.md index 8a71f5f0874a..3fd45f5def5d 100644 --- a/docs/user/trusted-publishers/index.md +++ b/docs/user/trusted-publishers/index.md @@ -4,7 +4,7 @@ title: Getting Started # Publishing to PyPI with a Trusted Publisher -"Trusted publishing" is our term for using the [OpenID Connect +"Trusted Publishing" is our term for using the [OpenID Connect (OIDC)](https://openid.net/connect/) standard to exchange short-lived identity tokens between a trusted third-party service and PyPI. This method can be used in automated environments and eliminates the need to use manually generated API @@ -42,10 +42,10 @@ the TL;DR: This confers significant usability and security advantages when compared to PyPI's traditional authentication methods: -* Usability: with trusted publishing, users no longer need to manually create +* Usability: with Trusted Publishing, users no longer need to manually create API tokens on PyPI and copy-paste them into their CI provider. The only manual step is configuring the publisher on PyPI. * Security: PyPI's normal API tokens are long-lived, meaning that an attacker who compromises a package's release token can use it until its legitimate user - notices and manually revokes it. Trusted publishing avoids this problem because + notices and manually revokes it. Trusted Publishing avoids this problem because the tokens minted expire automatically. diff --git a/docs/user/trusted-publishers/internals.md b/docs/user/trusted-publishers/internals.md index cdba87d667f1..5fd5d7b619fb 100644 --- a/docs/user/trusted-publishers/internals.md +++ b/docs/user/trusted-publishers/internals.md @@ -11,9 +11,9 @@ title: Internals and Technical Details It's intended primarily for PyPI developers and developers of other package indices looking to support similar authentication models. -## How trusted publishing works +## How Trusted Publishing works -PyPI's trusted publishing functionality is built on top of +PyPI's Trusted Publishing functionality is built on top of [OpenID Connect], or "OIDC" for short. OIDC gives *services* (like GitHub Actions) a way to *provably identify* @@ -22,7 +22,7 @@ workflow) can present an *OIDC token* to a third-party service. That party service can then verify the token and determine whether it's authorized to perform some other action. -In the context of trusted publishing, the machinery is as follows: +In the context of Trusted Publishing, the machinery is as follows: * *OIDC identity providers* like GitHub ("providers" for short) generate OIDC tokens that contain scoped *claims*, which convey appropriate authorization @@ -32,11 +32,11 @@ In the context of trusted publishing, the machinery is as follows: `octo-org/example`, indicating that the token should be authorized to access resources for which `octo-org/example` is a valid repository. -* *Trusted publishers* are pieces of configuration on PyPI that tell PyPI +* *Trusted Publishers* are pieces of configuration on PyPI that tell PyPI *which* OIDC providers to trust, and *when* (i.e., which specific set of claims to consider valid). - * For example, a trusted publisher configuration for GitHub Actions might + * For example, a Trusted Publisher configuration for GitHub Actions might specify `repo: octo-org/example` with `workflow: release.yml` and `environment: pypi`, indicating that a presented OIDC token **must** contain exactly those claims to be considered valid. @@ -50,26 +50,26 @@ In the context of trusted publishing, the machinery is as follows: endpoint. * Token exchange boils down to a matching process between a presented - OIDC token and every trusted publisher currently configured on PyPI: + OIDC token and every Trusted Publisher currently configured on PyPI: the token's signature is first verified (to ensure that it's actually coming from the expected provider), and then its claims are matched - against zero or more projects with registered trusted publishers. + against zero or more projects with registered Trusted Publishers. - If the OIDC token corresponds to one or more trusted publishers, then + If the OIDC token corresponds to one or more Trusted Publishers, then a short-lived (15 minute) PyPI API token is issued. This API token - is scoped to every project with a matching trusted publisher, meaning + is scoped to every project with a matching Trusted Publisher, meaning that it can be used to upload to multiple projects (if so configured). -If everything goes correctly, a successful trusted publishing flow results in +If everything goes correctly, a successful Trusted Publishing flow results in a short-lived PyPI API token *without any user interaction*, which in turn offers security and ergonomic benefits to PyPI packagers: users no longer have to worry about token provisioning or revocation. ## Q&A -### Why does trusted publishing use a "two-phase" token exchange? +### Why does Trusted Publishing use a "two-phase" token exchange? -As noted above, trusted publishing uses a "token exchange" mechanism, which +As noted above, Trusted Publishing uses a "token exchange" mechanism, which happens in two phases: 1. The uploading client presents an OIDC token, which PyPI verifies. @@ -135,12 +135,12 @@ do similar "two-phase" exchange mechanisms. ### Why is the PyPI project to publisher relationship "many-many"? -If you play around with trusted publishers on PyPI, you'll notice that +If you play around with Trusted Publishing on PyPI, you'll notice that PyPI projects can have multiple publishers, and individual publishers can be registered to multiple projects. -This is a "many-many" relationship between PyPI projects and their trusted -publishers which, like "two-phase" exchange, seems more complicated in +This is a "many-many" relationship between PyPI projects and their Trusted +Publishers which, like "two-phase" exchange, seems more complicated in principle than necessary. In practice, this many-many relationship addresses publishing patterns commonly @@ -152,7 +152,7 @@ used by the Python packaging community: workflow, due to tandem releases (e.g., a simultaneous release of a library package and its corresponding CLI tool). - Trusted publishing's design accommodates this use case: maintainers + Trusted Publishing's design accommodates this use case: maintainers can use the same `release.yml` workflow for all of their packages, rather than having to split it up by packages. @@ -173,9 +173,9 @@ used by the Python packaging community: builds in a final platform-agnostic publishing step, which could then be a single publisher. - However, in the interest of getting trusted publishers into users' hands + However, in the interest of getting Trusted Publishers into users' hands without requiring them to make significant unrelated changes to the builds, - the trusted publishing feature allows users to register multiple + the Trusted Publishing feature allows users to register multiple publishers against a single project. Consequently, `sampleproject` can be published from both `release-linux.yml` and `release-macos.yml` without needing to be refactored into a single `release.yml`. @@ -184,7 +184,7 @@ used by the Python packaging community: Some OIDC providers support username changes, so a claim of `repository_owner: octo-org` might not necessarily refer to the same `octo-org` -that a user initially authorized in a trusted publisher configuration. +that a user initially authorized in a Trusted Publisher configuration. If a repository owner changes their username or deletes their account, a malicious actor may be able to take the freed username and create their @@ -193,7 +193,7 @@ resurrection attack*. To solve this issue for GitHub-based publishers, PyPI always checks the `repository_owner_id` claim. This claim attests to the ID of the repository -owner, which is stable and permanent unlike usernames. When a trusted publisher +owner, which is stable and permanent unlike usernames. When a Trusted Publisher is configured, PyPI looks up the configured username's ID and stores it. During API token minting, PyPI checks the `repository_owner_id` claim against the stored ID and fails if they don't match. Through this process, only the original diff --git a/docs/user/trusted-publishers/security-model.md b/docs/user/trusted-publishers/security-model.md index 687f3288e8f8..137c89cbc2d8 100644 --- a/docs/user/trusted-publishers/security-model.md +++ b/docs/user/trusted-publishers/security-model.md @@ -16,17 +16,17 @@ is not a panacea. In particular: OIDC tokens are also short-lived, but an attacker who successfully intercepts one can mint API tokens against it for as long as it lives. -* Configuring a trusted publisher means establishing trust in a particular piece +* Configuring a Trusted Publisher means establishing trust in a particular piece of external state (such as a GitHub Actions workflow); that state **must not** be controllable by untrusted parties. -In summary: treat your trusted publishers *as if* they were API tokens. If you +In summary: treat your Trusted Publishers *as if* they were API tokens. If you wouldn't let a user or piece of code access your API token, then they shouldn't -be able to invoke your trusted publisher. +be able to invoke your Trusted Publisher. ## Provider-specific considerations -Each trusted publishing provider is its own OIDC identity provider, with its +Each Trusted Publishing provider is its own OIDC identity provider, with its own security model and considerations. === "GitHub Actions" @@ -57,7 +57,7 @@ own security model and considerations.

Considerations

- * In particular, for trusted publishing with GitHub Actions, you + * In particular, for Trusted Publishing with GitHub Actions, you **must**: * Trust the correct username and repository: if you trust a repository @@ -81,17 +81,17 @@ own security model and considerations. This particular risk can be mitigated by using a dedicated environment with manual approvers, as described below. - * Trusted publishers are registered to projects, not to users. This means that - removing a user from a PyPI project does **not** remove any trusted publishers + * Trusted Publishers are registered to projects, not to users. This means that + removing a user from a PyPI project does **not** remove any Trusted Publishers that they might have registered, and that you should include a review - of any/all trusted publishers as part of "offboarding" a project maintainer. + of any/all Trusted Publishers as part of "offboarding" a project maintainer. PyPI has protections in place to make some attacks against OIDC more difficult (like [account resurrection attacks]). However, like all forms of authentication, the end user is **fundamentally responsible** for applying it correctly. In addition to the requirements above, you can do the following to - "ratchet down" the scope of your trusted publishing workflows: + "ratchet down" the scope of your Trusted Publishing workflows: * **Use per-job permissions**: The `permissions` key can be defined on the workflow level or the job level; the job level is **always more secure** @@ -135,7 +135,7 @@ own security model and considerations.

Security Model

- If a trusted publisher is configured for a given PyPI project, any service + If a Trusted Publisher is configured for a given PyPI project, any service that uses the configured service account can request an OpenID Connect token from Google's identity provider on behalf of that identity. That token can be exchanged for a PyPI API token with the ability to publish to the PyPI project. @@ -144,7 +144,7 @@ own security model and considerations.

Considerations

- When using trusted publishing with Google Cloud, you must trust the service account + When using Trusted Publishing with Google Cloud, you must trust the service account and _any service which uses it as the default ephemeral identity_. Specifically, it is not recommened to configure the [default service @@ -184,14 +184,14 @@ own security model and considerations. repository located at orgA/repo cannot impersonate a repository located at orgB/repo. * The claims defined in an OIDC token are *bound to the top-level pipeline*, meaning that any pipeline included by the top-level pipeline (usually `.gitlab-ci.yml`) - will be able to upload using a trusted publisher that trusts the `.gitlab-ci.yml` + will be able to upload using a Trusted Publisher that trusts the `.gitlab-ci.yml` pipeline. * An OIDC token for a specific repository and pipeline can be generated by anyone who has permissions to run that pipeline in the repository's CI/CD.

Considerations

- * In particular, for trusted publishing with GitLab CI/CD, you + * In particular, for Trusted Publishing with GitLab CI/CD, you **must**: * Trust the correct namespace and repository: if you trust a repository @@ -219,13 +219,13 @@ own security model and considerations. This particular risk can be mitigated by using a dedicated environment with manual approvers, as described below. - * Trusted publishers are registered to projects, not to users. This means that - removing a user from a PyPI project does **not** remove any trusted publishers + * Trusted Publishers are registered to projects, not to users. This means that + removing a user from a PyPI project does **not** remove any Trusted Publishers that they might have registered, and that you should include a review - of any/all trusted publishers as part of "offboarding" a project maintainer. + of any/all Trusted Publishers as part of "offboarding" a project maintainer. In addition to the requirements above, you can do the following to - "ratchet down" the scope of your trusted publishing workflows: + "ratchet down" the scope of your Trusted Publishing workflows: * **[Use a dedicated environment](https://docs.gitlab.com/ee/ci/environments/)**: GitLab CI/CD supports "environments", which can be used to isolate secrets to diff --git a/docs/user/trusted-publishers/troubleshooting.md b/docs/user/trusted-publishers/troubleshooting.md index 8ad5e998a363..3e9eec76cd53 100644 --- a/docs/user/trusted-publishers/troubleshooting.md +++ b/docs/user/trusted-publishers/troubleshooting.md @@ -6,13 +6,13 @@ title: Troubleshooting ## Reusable workflows on GitHub -[Reusable workflows] cannot currently be used as the workflow in a trusted -publisher. This is a practical limitation, and is being tracked in +[Reusable workflows] cannot currently be used as the workflow in a Trusted +Publisher. This is a practical limitation, and is being tracked in [warehouse#11096]. ## Ratelimiting -PyPI currently imposes ratelimits on trusted publisher registration: no more +PyPI currently imposes rate limits on Trusted Publisher registration: no more than 100 publishers can be registered by a single user or IP address within a 24 hour window. @@ -89,13 +89,13 @@ To fix this, you must determine which of the two names is the correct one: * If the name used in the pending publisher is the correct one, then you must update your project metadata to reflect that name. Subsequent uploads with the - trusted publisher will work automatically, and no further action is required. + Trusted Publisher will work automatically, and no further action is required. * If the name used in the project metadata is the correct one, then you must: 1. Go to [your projects] and delete the incorrectly created project. This will also have the effect of deleting the incorrectly registered - trusted publisher. + Trusted Publisher. 2. Create a new pending publisher with the corrected project name. diff --git a/docs/user/trusted-publishers/using-a-publisher.md b/docs/user/trusted-publishers/using-a-publisher.md index 1e4cc370116d..cefd5b061198 100644 --- a/docs/user/trusted-publishers/using-a-publisher.md +++ b/docs/user/trusted-publishers/using-a-publisher.md @@ -4,9 +4,9 @@ title: Publishing with a Trusted Publisher # Publishing with a Trusted Publisher -Once you have a trusted publisher configured on PyPI (whether "pending" or +Once you have a Trusted Publisher configured on PyPI (whether "pending" or "normal"), you can publish through it on the associated platform. The tabs -below describe the setup process for each supported trusted publisher. +below describe the setup process for each supported Trusted Publisher. === "GitHub Actions" @@ -28,7 +28,7 @@ below describe the setup process for each supported trusted publisher. # Specifying a GitHub environment is optional, but strongly encouraged environment: pypi permissions: - # IMPORTANT: this permission is mandatory for trusted publishing + # IMPORTANT: this permission is mandatory for Trusted Publishing id-token: write steps: # retrieve your distributions here @@ -48,7 +48,7 @@ below describe the setup process for each supported trusted publisher. + # Specifying a GitHub environment is optional, but strongly encouraged + environment: pypi + permissions: - + # IMPORTANT: this permission is mandatory for trusted publishing + + # IMPORTANT: this permission is mandatory for Trusted Publishing + id-token: write steps: # retrieve your distributions here @@ -72,9 +72,9 @@ below describe the setup process for each supported trusted publisher.

Publishing to indices other than PyPI

The PyPA's [`pypi-publish`](https://github.com/marketplace/actions/pypi-publish) - action also supports trusted publishing with other (non-PyPI) indices, provided - they have trusted publishing enabled (and you've configured your trusted - publisher on them). For example, here's how you can use trusted publishing on + action also supports Trusted Publishing with other (non-PyPI) indices, provided + they have Trusted Publishing enabled (and you've configured your Trusted + Publisher on them). For example, here's how you can use Trusted Publishing on [TestPyPI](https://test.pypi.org): ```yaml