-
Notifications
You must be signed in to change notification settings - Fork 983
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
OIDC: Threat model for Warehouse #10644
Comments
Summarizing:
|
I think we can move forward under the assumption that we will eventually have a unique user ID available in the claim. |
Yep! I'm working under that assumption in #10753. |
I think we've fully fleshed out the threat/security considerations here, so I'm inclined to close this for now. The only thing that's currently missing is a way to verify a GitHub user's unique ID, which is blocked on GitHub rather than us (and is more of a development action item than a threat model design item). Is that good with you @di? |
Yep. Let's open an issue to capture the eventual migration of the user ID check from the API call to an OIDC claim, which is blocked on the token having this claim. |
We're still going to need the API call for the trusted setup, unfortunately -- we still need to establish the initial ID to trust when verifying actual JWTs. But yeah, I can make a sub-issue for tracking GitHub's progress on this + adding it to our verification impl. |
Ah, yep, I meant for verification. |
#11239 will more or less round out the intended threat model here, by preventing "account resurrection" attacks. To summarize:
|
@di assuming that #10644 (comment) matches your mental model of the threat model, I think this is safe to close. |
This is a summary of my own notes from conversations with @di concerning Warehouse's threat model around OIDC (and GitHub, in particular, as an OIDC provider).
JWT considerations
JWT reuse
Warehouse needs well-defined and well-documented behavior around handling of a JWT seen more than once. For example, a GitHub action might do the following (pseudocode):
In this case, the JWT gets used
N
times: once for each access token minting. This is probably not what we want; instead, we want this:In this use pattern, we invalidate the JWT in Warehouse's backend after its first use. The process for that is probably as simple as performing uniqing on the
jti
claim after JWT verification, and then adding(jti, exp)
to some table, whereexp
is the JWT's expiration claim (which gives us the ability to automatically clear out old JWTs once they expire).Non-JWT considerations
Access token ephemerality
We should determine exactly how long-lived our ephemeral access tokens/API keys will be: how long is a reasonable period to allow uploads for? Should we cap the number of individual requests at some high number (e.g., is there any legitimate packaging workflow that creates more than 100 separate distribution files and uploads them)?
Provider-specific considerations
GitHub: account resurrection/reuse
GitHub allows a deleted user's username to be reused. When this happens, JWTs minted by the new user are indistinguishable from JWTs minted by the old one. This is a potential problem if PyPI is configured to accept JWTs from
user/repo @ workflow
, whereuser
changes hands on GitHub -- the new (malicious)user
would still be able to authenticate with PyPI as if they were the olduser
.We probably need a mitigation for this before we fully enable support for GitHub as an OIDC provider. Two potential solutions:
repository_owner
claim in the JWT with some sidecar information: on trusted setup, retrieve the GitHub User ID (which is hopefully unique) for the user and cross-check it against the current ID. This is not the preferred solution.repository_owner_id
claim in the JWT, or something similar (like arepository_owner_epoch
, if they don't want to guarantee the ID's uniqueness).Neither of these is a great solution, because both still require some amount of sidecar state: we still have to either initially store the GitHub user's ID during trusted setup or during TOFU, so that we can check for changes during subsequent authentications. That complicates our DB schema, which we'd like to keep generic.
GitHub: JWTs minted for other consumers on the same workflow
GitHub allows any action to mint a JWT. Warehouse's consumer will only accept JWTs with acceptable claims (e.g., a matching
ref
), but that might not be sufficient.In particular, it's conceivable for a
publish
workflow to have two jobs:publish-pypi
andpublish-rubygems
, both of which mint JWTs for their respective services. Currently, there is no way for Warehouse to distinguish between these two JWTs: both originate from the same workflow. We could distinguish them with theaud
claim, which Warehouse would then filter on, but that claim does not provide authenticity: an attacker who manages to take over thepublish-rubygems
job could mint a JWT withaud=pypi
. We should determine whether this is a situation we need to handle on Warehouse's side.GitHub: access token leakage
We should make sure that any (official) actions that mint access tokens via an OIDC JWT add the access token as a "mask value" so that it does not appear in CI logs: https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#masking-a-value-in-log
GitHub: trusted workflows
Warehouse has no visibility into workflow access: a user could misconfigure their GitHub Actions such that anybody can run a publish/release action and thereby publish malicious distributions. We can't prevent this, but we should probably provide documentation/guidance to steer users in the right direction.
This is true also for trusted branches/tags: anybody who can push a new tag to the repo could conceivably authenticate with PyPI if the action is e.g. configured to match against tags like
v*
.The text was updated successfully, but these errors were encountered: