Skip to content
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

Samples of OIDC JWTs from GitHub #10645

Closed
woodruffw opened this issue Jan 25, 2022 · 8 comments
Closed

Samples of OIDC JWTs from GitHub #10645

woodruffw opened this issue Jan 25, 2022 · 8 comments

Comments

@woodruffw
Copy link
Member

We need samples of each of the following:

  • A trusted user creating a workflow from a repo
  • A non-trusted user creating a workflow from a fork
  • Others?
@woodruffw
Copy link
Member Author

I created a couple of these.

Separately, I confirmed that GitHub does allow multiple workflows to have the same name.

Here's a JWT from a CI workflow, running in a test environment (on main push`):

{
  "jti": "17dfb15e-10fa-4139-86c7-86b4d77e1243",
  "sub": "repo:woodruffw/gha-oidc-jwt-test-repo:environment:test",
  "aud": "https://github.com/woodruffw",
  "ref": "refs/heads/main",
  "sha": "ff36d47d05072792d73ec3b521063e0d4efd6975",
  "repository": "woodruffw/gha-oidc-jwt-test-repo",
  "repository_owner": "woodruffw",
  "run_id": "1746933707",
  "run_number": "8",
  "run_attempt": "1",
  "actor": "woodruffw",
  "workflow": "CI",
  "head_ref": "",
  "base_ref": "",
  "event_name": "push",
  "ref_type": "branch",
  "environment": "test",
  "job_workflow_ref": "woodruffw/gha-oidc-jwt-test-repo/.github/workflows/ci.yml@refs/heads/main",
  "iss": "https://token.actions.githubusercontent.com",
  "nbf": 1643132751,
  "exp": 1643133651,
  "iat": 1643133351
}

From a different CI workflow, not in the test environment:

{
  "jti": "abe5b71c-a5ce-4035-a758-982a592cc63a",
  "sub": "repo:woodruffw/gha-oidc-jwt-test-repo:ref:refs/heads/main",
  "aud": "https://github.com/woodruffw",
  "ref": "refs/heads/main",
  "sha": "ff36d47d05072792d73ec3b521063e0d4efd6975",
  "repository": "woodruffw/gha-oidc-jwt-test-repo",
  "repository_owner": "woodruffw",
  "run_id": "1746933706",
  "run_number": "8",
  "run_attempt": "1",
  "actor": "woodruffw",
  "workflow": "CI",
  "head_ref": "",
  "base_ref": "",
  "event_name": "push",
  "ref_type": "branch",
  "job_workflow_ref": "woodruffw/gha-oidc-jwt-test-repo/.github/workflows/ci2.yml@refs/heads/main",
  "iss": "https://token.actions.githubusercontent.com",
  "nbf": 1643132745,
  "exp": 1643133645,
  "iat": 1643133345
}

From a release workflow, no environment, running on matching tag (v*) push:

{
  "jti": "c81328ba-016d-4e74-aef5-a7af45faceef",
  "sub": "repo:woodruffw/gha-oidc-jwt-test-repo:ref:refs/tags/v0.0.2",
  "aud": "https://github.com/woodruffw",
  "ref": "refs/tags/v0.0.2",
  "sha": "ff36d47d05072792d73ec3b521063e0d4efd6975",
  "repository": "woodruffw/gha-oidc-jwt-test-repo",
  "repository_owner": "woodruffw",
  "run_id": "1746934971",
  "run_number": "2",
  "run_attempt": "1",
  "actor": "woodruffw",
  "workflow": "release",
  "head_ref": "",
  "base_ref": "",
  "event_name": "push",
  "ref_type": "tag",
  "job_workflow_ref": "woodruffw/gha-oidc-jwt-test-repo/.github/workflows/release.yml@refs/tags/v0.0.2",
  "iss": "https://token.actions.githubusercontent.com",
  "nbf": 1643132768,
  "exp": 1643133668,
  "iat": 1643133368
}

@woodruffw
Copy link
Member Author

Some observations:

  • Every JWT so far has a pretty short (15 minute) expiration. That's good, and it makes the problem of JWT reuse identified in OIDC: Threat model for Warehouse #10644 less pressing.
  • The job_workflow_ref for the release treats the tag as the ref instead of main, so we can't treat that as a stable identifier.

@woodruffw
Copy link
Member Author

More JWTs, from experimenting with @di:

PR merge (fork to upstream):

{
  "jti": "2c3820db-1103-4bcb-a4b3-59d1d45c582d",
  "sub": "repo:woodruffw/gha-oidc-jwt-test-repo:ref:refs/heads/main",
  "aud": "https://github.com/woodruffw",
  "ref": "refs/heads/main",
  "sha": "738bfc299ee1f7383c3b673e2b3c490c024dce9d",
  "repository": "woodruffw/gha-oidc-jwt-test-repo",
  "repository_owner": "woodruffw",
  "run_id": "1747103237",
  "run_number": "13",
  "run_attempt": "1",
  "actor": "di",
  "workflow": "CI",
  "head_ref": "",
  "base_ref": "",
  "event_name": "push",
  "ref_type": "branch",
  "job_workflow_ref": "woodruffw/gha-oidc-jwt-test-repo/.github/workflows/ci2.yml@refs/heads/main",
  "iss": "https://token.actions.githubusercontent.com",
  "nbf": 1643135007,
  "exp": 1643135907,
  "iat": 1643135607
}

Release cut by an authorized collaborator:

{
  "jti": "4b7a0501-5598-43b9-974b-85ad31419188",
  "sub": "repo:woodruffw/gha-oidc-jwt-test-repo:ref:refs/tags/v0.0.3",
  "aud": "https://github.com/woodruffw",
  "ref": "refs/tags/v0.0.3",
  "sha": "738bfc299ee1f7383c3b673e2b3c490c024dce9d",
  "repository": "woodruffw/gha-oidc-jwt-test-repo",
  "repository_owner": "woodruffw",
  "run_id": "1747127980",
  "run_number": "3",
  "run_attempt": "1",
  "actor": "di",
  "workflow": "release",
  "head_ref": "",
  "base_ref": "",
  "event_name": "push",
  "ref_type": "tag",
  "job_workflow_ref": "woodruffw/gha-oidc-jwt-test-repo/.github/workflows/release.yml@refs/tags/v0.0.3",
  "iss": "https://token.actions.githubusercontent.com",
  "nbf": 1643135374,
  "exp": 1643136274,
  "iat": 1643135974
}

@woodruffw
Copy link
Member Author

To summarize: we want the following third-party claims:

  • repository and repository_owner: to sanity-check against the trusted setup
  • job_workflow_ref: this will be matched against {user}/{repo}/.github/workflows/{workflow_name}.yml@.*

And the following first-party claims:

  • jti: We'll use this as a JWT nonce
  • iss: We'll use this to sanity check the origin of the JWT
  • nbf and exp: We'll check the timeliness/expiredness of the JWT

@woodruffw
Copy link
Member Author

Samples are listed above, so I'm closing this.

@woodruffw
Copy link
Member Author

On @di's suggestion, I also tried to request two JWTs during the same task, and was able to confirm that GitHub mints unique JWTs with each request:

Token 1:

{
  "jti": "6fbebfe3-9eb4-4028-a592-5422768b53bc",
  "sub": "repo:woodruffw/gha-oidc-jwt-test-repo:environment:test",
  "aud": "https://github.com/woodruffw",
  "ref": "refs/pull/4/merge",
  "sha": "796a6cfb48152b077701fced55d480bf1d90e1e2",
  "repository": "woodruffw/gha-oidc-jwt-test-repo",
  "repository_owner": "woodruffw",
  "run_id": "1959414638",
  "run_number": "15",
  "run_attempt": "1",
  "actor": "woodruffw",
  "workflow": "CI",
  "head_ref": "two-tokens",
  "base_ref": "main",
  "event_name": "pull_request",
  "ref_type": "branch",
  "environment": "test",
  "job_workflow_ref": "woodruffw/gha-oidc-jwt-test-repo/.github/workflows/ci.yml@refs/pull/4/merge",
  "iss": "https://token.actions.githubusercontent.com/",
  "nbf": 1646855366,
  "exp": 1646856266,
  "iat": 1646855966
}

Token 2:

{
  "jti": "18e478d8-db96-4fe0-840a-6f5e963f54f9",
  "sub": "repo:woodruffw/gha-oidc-jwt-test-repo:environment:test",
  "aud": "https://github.com/woodruffw",
  "ref": "refs/pull/4/merge",
  "sha": "796a6cfb48152b077701fced55d480bf1d90e1e2",
  "repository": "woodruffw/gha-oidc-jwt-test-repo",
  "repository_owner": "woodruffw",
  "run_id": "1959414638",
  "run_number": "15",
  "run_attempt": "1",
  "actor": "woodruffw",
  "workflow": "CI",
  "head_ref": "two-tokens",
  "base_ref": "main",
  "event_name": "pull_request",
  "ref_type": "branch",
  "environment": "test",
  "job_workflow_ref": "woodruffw/gha-oidc-jwt-test-repo/.github/workflows/ci.yml@refs/pull/4/merge",
  "iss": "https://token.actions.githubusercontent.com/",
  "nbf": 1646855367,
  "exp": 1646856267,
  "iat": 1646855967
}

Note that the two are nearly identical, but with different unique IDs (jti) and slightly different expiries (nbf, exp, iat).

@di
Copy link
Member

di commented Apr 1, 2022

Here's some more samples around reusable workflows:

Within a user workflow:

 "aud": "https://github.com/<user-org>",
  "ref": "refs/heads/<user-ref>",
  "sha": "52969aa7482840955b3cca478e15bee77c3bc943"
  "repository": "<user-org>/<user-repo>",
  "repository_owner": "<user-org>",
  "run_id": "2001655687",
  "run_number": "30",
  "run_attempt": "1",
  "workflow": ".github/workflows/<user-workflow>.yml",
  "job_workflow_ref": "<user-org>/<user-repo>/.github/workflows/<user-workflow>.yml@refs/heads/<user-ref>",

Within a reusable workflow:

"aud": "https://github.com/<user-org>",
  "ref": "refs/heads/<user-ref>",
  "sha": "52969aa7482840955b3cca478e15bee77c3bc943"
  "repository": "<user-org>/<user-repo>",
  "repository_owner": "<user-org>",
  "run_id": "2001655687",
  "run_number": "30",
  "run_attempt": "1",
  "workflow": ".github/workflows/<user-workflow>.yml",
  "job_workflow_ref": "<trusted-org>/<trusted-repo>[/.github/workflows/<trusted-builder>@](https://goto.google.com/.github)some_ref",```

@di di reopened this Apr 1, 2022
@di di closed this as completed Apr 5, 2022
@woodruffw
Copy link
Member Author

GitHub has added the claims we asked for 🎉

{
  "jti": "6e67b1cb-2b8d-4be5-91cb-757edb2ec970",
  "sub": "repo:woodruffw/gha-oidc-jwt-test-repo:environment:test",
  "aud": "https://github.com/woodruffw",
  "ref": "refs/pull/6/merge",
  "sha": "b3c393cd27b93ca2b7287c0c6e5c299de2c7f727",
  "repository": "woodruffw/gha-oidc-jwt-test-repo",
  "repository_owner": "woodruffw",
  "repository_owner_id": "3059210",
  "run_id": "2210189049",
  "run_number": "19",
  "run_attempt": "1",
  "repository_id": "451973815",
  "actor_id": "3059210",
  "actor": "woodruffw",
  "workflow": "CI",
  "head_ref": "new-claims",
  "base_ref": "main",
  "event_name": "pull_request",
  "ref_type": "branch",
  "environment": "test",
  "job_workflow_ref": "woodruffw/gha-oidc-jwt-test-repo/.github/workflows/ci.yml@refs/pull/6/merge",
  "iss": "https://token.actions.githubusercontent.com",
  "nbf": 1650663265,
  "exp": 1650664165,
  "iat": 1650663865
}

Specifically, we'll want to verify repository_owner_id. We can probably put actor_id in our "intentionally ignored" set for now, since we don't want to constrain publishing based on the maintainer who triggers the workflow.

I think we can ignore repository_id entirely, since we always associate publishing with the tuple of (owner, repo).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants