Open simonw opened 7 months ago
Related issue full of confused people:
Another issue about how confusing this is, closed without resolution:
This is my fault.
As I understand it, any contributor with write access could write to a repo a script which uses that token for nefarious purposes.
It's also very hard to lock-down once you've enabled the github OIDC as an AuthN provider; with a third-party provider.
The AuthZ you configure on the trusted (acting as) user is set, in the external system; so if I were to have a repo and manage it's infrastructure as code with Amazon AWS; then there are not great ways (I think environment is one) to restrict other workflows from say deleting an RDS. Recently a co-worker on a private repo, accidentally deleted a cognito user pool because they forgot to rebase.
Not the type of change or risk I would like to invite for the discussed use-case of deploying github pages sites. The convenience seems to be at the cost of needing to make sure nobody points the barrel at anything you value.
I Believe even less teams will use this responsibly than for novelty purposes; so I'd mentioned publicly to Simon that I am deeply distrustful of public repos using this as a mechanism.
I would like to seek clarification on the claims and grants that id-token: write
conveys to the running action.
iat
, nbf
, perform any kind of handshake with github to validate that the jti
is not revoked?In the same issue Simon just linked, there is a link to some docs which state that none
and read
are essentially the same thing. Seemingly like a boolean database column that is allowed to be null, two of the represented states are treated as not having access. But what it means to "have access" is also unclear, as if I must use this token type for pushing to github-pages via a github action; I'd like to make sure I understand what else it is capable of internally to GitHub. Can it for example write to another repo; can it be used to enumerate users of a repo, which might be leaked elsewhere to help a more skillful attack?
Another closed issue about this (apparently I'm collecting them now):
I filed an issue here with my own attempt at explaining this feature:
There is even a pages: write
. So here is the weird thing. What the heck do I need a token for?
When I use contents: write
I don't need an id-token alongside it to commit to a repo, so why does pages: write
need id-token: write
?
👋 I cannot talk for the questions about OIDC itself (though they are good ones and I see you have opened issues against the right repos already to get the confusions addressed).
I can talk about GitHub Pages' specific use case for an OIDC token.
First, you need to be aware of GitHub's automatic token authentication. This is the default GitHub API token (we usually refer as GITHUB_TOKEN
) a workflow is given that allows it to do certain operations. It's an opaque token that only GitHub understands.
The id-token: write
permission allows the GITHUB_TOKEN
to make an API call to generate an OIDC token (which is an extra security token, a standard one). The OIDC token is not dangerous in itself. It is minted and signed by GitHub and includes "claims" (more on that later). What's potentially dangerous is what a third-party may be configured to do with said OIDC tokens.
To start a Pages deployment today, the actions/deploy-pages
Action makes an API call. Like all authenticated GitHub APIs, it needs a GitHub API token (e.g. GITHUB_TOKEN
) and it requires pages: write
permission because we consider a deployment a change to a Pages site.
In the context of building and deploying a Pages site with Actions, a regular token like GITHUB_TOKEN
is not sufficient. While the token is opaque it does not include specific "context" Pages needs. If you set the source branch to say gh-pages
, how would you prevent a deployment from targeting another branch? There are various ways to handle this but for Pages we decided to leverage OIDC tokens. Claims they come with includes: repo name, environment, branch, etc. A lot of context. The OIDC token is used to make extra security checks (ensure a deployment is being requested via GitHub Actions, that it targets a valid environment and a valid branch when applicable).
In a perfect world, the Pages deploy API would not require an extra token. Unfortunately GitHub's API tokens predates the OIDC specification!
Thanks for the explainer @yoannchaudet I'll be interested to see what the other permissions of id-token are or if it's just "hey, it's me GitHub". There must be lots more information in there, otherwise AWS etc would be wide open from any github user
@Lewiscowles1986 The OIDC token is actually a big "hey it's me GitHub" (I like that image and I think you were spot on). It has no "permissions" associated on its own but it is minted in the context of an Action job and comes with a bunch of context. It's for third-party to decide if a token is allowed to do anything (say do something in AWS or Azure) – it's a trust relationship between GitHub and a third-party. GitHub Pages does use the token (like a third-party) to gate deployment but not alone, it has to be paired with a regular GitHub API token.
They actually document further what the claims look like here which I find useful: https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#understanding-the-oidc-token.
Anyhow, I agree that we can better elaborate about Pages' use of OIDC tokens in this repository. I'll track it on our side (Pages team).
Ah I think I see something here that I will get updated.
Looks like job_workflow_ref
paired with environment
and runner_environment
do satisfy things from the situation I was thinking of.
actor
also seems like a nice bit of auditing data when paired with actor_id
as the usernames are unique, hard to spoof, and even if someone managed a rename, I think their actor_id
might be a primary key that an attacker cannot change.
@simonw so from this I think I might be able to lock down a token at the integration level so that third-party actions are unable to use the id-token to escalate from within a step; which next to user-stupidity is a primary concern. What if an actions provider used the fact that my job had an id-token: write
to exploit an org.
This definitely isn't immediately obvious; but I also wonder if it's too dry and boring for most users.
It would also be nice if it was clearly documented that setting id-token:write reverts all other default permission scopes to "none." This is rather inconvenient, as there is no way to say "set id-token to write, but retain all previous permissions" (which could possibly have been set at the workflow level). As it is, using id-token:write requires one to explicitly supply permissions to scopes that were previously set to "read" or "write."
It would also be nice if it was clearly documented that setting id-token:write reverts all other default permission scopes to "none." This is rather inconvenient, as there is no way to say "set id-token to write, but retain all previous permissions" (which could possibly have been set at the workflow level). As it is, using id-token:write requires one to explicitly supply permissions to scopes that were previously set to "read" or "write."
If I'm reading these docs correctly, explicitly setting any permission will revoke access to almost everything that you don't set:
When the permissions key is used, all unspecified permissions are set to no access, with the exception of the metadata scope, which always gets read access.
@terryf82
When the permissions key is used, all unspecified permissions are set to no access, with the exception of the metadata scope, which always gets read access.
Should be in a callout box, everywhere folks are documenting just changing some flags.
The README includes this comment: https://github.com/actions/deploy-pages/blob/d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e/README.md?plain=1#L32
Could we get more information on this?
It looks pretty scary.
id-token: write
implies that there is some deep and mysterious extra permission being granted to this workflow, potentially involving the ability to make writes and involving a token which might have permission to do other privileged things, maybe even at the account or organization level.It's really hard to figure out the security impact of this configuration from existing GitHub documentation.