-
Notifications
You must be signed in to change notification settings - Fork 309
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
Support the "Trusted Publishing" flow directly in twine
#999
Comments
I wonder if it makes sense to make authentication pluggable in some way? I'm pretty sure that twine right now assumes that every repository is authenticated with a username/password over basic auth. Things like API Tokens from PyPI get shoehorned into this by using a dummy username, but it would be nice to support any auth flow that a repository might want to implement. |
Yes, right now a Repository expects username/password Line 45 in 0bb428c
authentication parameter that accepts a pluggable interface. I haven't looked at the interfaces PyPI is expecting, but if this is intended to be contributed, then I'm not sure I or Brian need to care too much.
|
Thanks for the ping! I agree with the approach that @di has outlined.
I agree with this in principle, although that might be a premature optimization/generalization for this particular use case (since the trusted publishing flow ultimately produces a normal looking PyPI API token). But there may be other indices that I'm not aware of that would benefit from pluggable auth methods? |
PyPI itself would benefit from not having to use the BasicAuth hack anymore :) But more generally, most of the cloud providers don't use long lived secrets that are usable directly with twine, and they expect that you run some command to get a short lived token currently or they "fake" a pluggable auth method by making a keyring backend that doesn't actually do keyring stuff, but that does their auth flow.
So I think in principle there's already a need for this (and honestly the same is true for pip), and currently people are working around the lack of pluggable authentication by treating the keyring library as that pluggable authentication. Using the keyring library works, but it's kind of an abuse of the keyring API to do that. Keyrings are supposed to support |
I've been wondering if it makes sense to have vendor-specific OIDC in twine ever since it was implemented in the action… I think that this might not belong in twine because this is something specific to runtimes where twine is used, not twine itself. Implementing it here would introduce the burden of having to track ways of identifying if something is a GitHub or GitLab Runner, or some AWS env etc., and actively monitoring changes in those. Besides, twine calls are often wrapped via other command runners like tox. Tox screens the environment variables by default, making the auto-detection broken, putting the burden of knowing upfront that they must to pre-configure tox to pass specific environment variables that twine needs (and knowing what those are!) in order for it to work. I imagine other command wrappers may behave similarly. Keeping it in a GitHub Action, though, eliminates said burdens (and it also allows us to push the best practices to the wider community). I know that for GitLab, it'd also make sense to make some reusable pipeline. The idea with plugins is interesting, but why would one install such a plugin locally? They'd probably need to add their own env detection to install it conditionally, since it'd only be really needed @ GHA. I don't have very strong opinions on this, but I wanted to post the above thoughts to see if anybody else thinks that maybe having this inside twine might be not what people really need… |
This may help: https://github.com/marketplace/actions/pypi-token-mint Gets the token and nothing else... |
How about people that don't use GitHub actions? Would it be possible for twine to integrate with other CI providers that offer OIDC capability? |
Each OIDC provider will have to be special-cased. So if an ecosystem has standard means of implementing this, I probably wouldn't drag that into twine. |
The example there looks harmful security-wise — it puts the build step in a job with OIDC privileges. If you follow the security best practice and build in a separate job, you won't really need poetry for publishing. Hence, no need for the action as pypi-publish has that embedded. |
FWIW, this is the idea behind In principle, |
But the calling code would still have to special-case working with different platforms, right? |
Yes, good point: at the moment the token exchange needs to be done on a provider-specific endpoint (e.g. |
That does sound excessive, though. |
Yeah, potentially 🙂 -- I'll need to think about it some more, but doing so shouldn't be too heavyweight: all of these OIDC tokens are keyed on a Either way, that's all hypothetical 🙂 |
I am trying to understand here what are the interoperability challenges (sorry, last time I used openID connect was ages ago in a very specific context). Any pointers on that? As a standard it should be able to offer some form of interoperability... Is it a matter of parametrising the endpoints and/or asking for the user to provide the token (with the audience set to I tried to have a look on the links in the announcement post (e.g. https://docs.pypi.org/trusted-publishers/) but they are either too generic or too Github-centric, so I am not sure I understand... Footnotes
|
Thank you very much @webknjaz, after reading it seems to me that PyPI for the moment is not supporting generic "trusted publishers" with OIDC, but rather "one trusted publisher" which is GitHub. If that is the case, it does seem that concentrating in the GitHub actions is the best. (I might be wrong, but that is what seems to me, specially after going through https://docs.pypi.org/trusted-publishers/using-a-publisher/#the-manual-way). |
On top of what @webknjaz said: the primary interop problem with OIDC is that each IdP has a lot of control over the claims that it exposes, so PyPI is responsible for papering over the differences between them in a way that's coherent/useful for end users. But yeah, GitHub is really the only currently supported IdP (support for others is currently in progress). |
I think we could do that (likely based on the |
@abravalheri here's some other OIDC integrations scheduled FYI: https://github.com/pypi/warehouse/issues?q=is%3Aopen+label%3Atrusted-publishing+sort%3Aupdated-desc. |
In order to support trusted publishing. I believe twine doesn't support it yet, see: pypa/twine#999
In order to support trusted publishing. I believe twine doesn't support it yet, see: pypa/twine#999
Just to post an update here: PyPI now supports 4 different trusted publisher providers (GitHub, GitLab, Google, and ActiveState), and the token minting endpoint is now fully generic ( |
Last month PyPI added support for "Trusted Publishing": https://blog.pypi.org/posts/2023-04-20-introducing-trusted-publishers/. This uses an credential exchange flow to swap OIDC credentials with a short-lived PyPI API token, removing the need to maintain long-lived credentials/secrets. (More technical details on the exchange are here: https://docs.pypi.org/trusted-publishers/internals/)
We were able to do launch this without modifying
twine
directly because we instead updated https://github.com/pypa/gh-action-pypi-publish to do the token exchange prior to invokingtwine upload
.That said, we're actively working on expanding support to other providers for which we don't have "canonical" workflows (such as pypi/warehouse#13551, pypi/warehouse#13575, and pypi/warehouse#13888).
For these providers (as well as for GitHub users who prefer not to use the
pypi-publish
GitHub action for whatever reason) it would be preferable to havetwine
be able to support the OIDC/API token exchange directly.This would ideally include:
twine upload
is run (this can be handled by https://pypi.org/p/id, sotwine
doesn't need to understand how to do this for N different providers)aud
claim of the token is set to the audience of the index thattwine
is attempting to upload to)pypi-publish
workflow does here: https://github.com/pypa/gh-action-pypi-publish/blob/110f54a3871763056757c3e203635d4c5711439f/oidc-exchange.py)The alternative to
twine
supporting this directly is that the end user has to perform a fairly manual token exchange themselves directly (https://docs.pypi.org/trusted-publishers/using-a-publisher/#the-manual-way) which would be pretty bad UX overall.Opening this issue to make sure maintainers are on board with the general idea before any implementation is started, please let me know if you have any thoughts.
(cc @woodruffw)
The text was updated successfully, but these errors were encountered: