sigstore / sigstore-python

A Sigstore client written in Python
https://pypi.org/p/sigstore
Other
233 stars 49 forks source link

Document a workflow for signing with with an identity token #1227

Open stefanberger opened 1 day ago

stefanberger commented 1 day ago

Description

Could you document a workflow where I can avoid the interaction with oauth2.sigstore/.dev (using github login to get the token) but automate it? It's not straight-forward to figure out what to pass in the various parameters.

woodruffw commented 1 day ago

Could you document a workflow where I can avoid the interaction with oauth2.sigstore/.dev (using github login to get the token) but automate it?

Could you say a bit more about your scenario? Do you have an OIDC token already that you want to sign with, and therefore bypass the interactive token flow?

If that's what you mean, that workflow is documented here: https://github.com/sigstore/sigstore-python#signing-with-an-explicit-identity-token

stefanberger commented 1 day ago

Could you document a workflow where I can avoid the interaction with oauth2.sigstore/.dev (using github login to get the token) but automate it?

Could you say a bit more about your scenario? Do you have an OIDC token already that you want to sign with, and therefore bypass the interactive token flow?

If that's what you mean, that workflow is documented here: https://github.com/sigstore/sigstore-python#signing-with-an-explicit-identity-token

I would be interested in a workflow where I can use either my github account email+ password or github token (PAT) to automate the flow. I also don't know where the JWT token you mention in the docs comes from or how I could generate it or have it generated.

woodruffw commented 1 day ago

I also don't know where the JWT token you mention in the docs comes from or how I could generate it or have it generated.

It comes from performing an OAuth2 flow with your identity provider. For most users that means an interactive OAuth2 flow, or an identity token that comes from a latent/ambient source (like GitHub Actions).

You could probably script this flow with something like Playwright/puppeteer, but the interactive requirement is by design: OAuth2 providers (like GitHub and your email) get to choose what kinds of "grant" flows they support, and most (all?) choose to only support grants that require some amount of interactivity.

In particular, I don't think GitHub will allow you to use a PAT to obtain a suitable OIDC credential here. They would likely consider any flow that allows that to be a security hole.

TL;DR: I believe this isn't possible, at least not out of the box. You might be able to hack it together, but I think sigstore-python itself shouldn't provide an example of doing so (since bypassing interactive OAuth on a human identity is comparable to bypassing MFA by short-circuiting the touch sensor on a physical token -- you can always do it, but it defeats the point).

stefanberger commented 1 day ago

I also don't know where the JWT token you mention in the docs comes from or how I could generate it or have it generated.

It comes from performing an OAuth2 flow with your identity provider. For most users that means an interactive OAuth2 flow, or an identity token that comes from a latent/ambient source (like GitHub Actions).

Though it means that with the JWT token passed to sigstore sign the signing is then automated? The detail would then just be a description of the curl interactions with github. Is there documentation somewhere?

TL;DR: I believe this isn't possible, at least not out of the box. You might be able to hack it together, but I think sigstore-python itself shouldn't provide an example of doing so (since bypassing interactive OAuth on a human identity is comparable to bypassing MFA by short-circuiting the touch sensor on a physical token -- you can always do it, but it defeats the point).

So what I am wondering about are the ---oidc-* command line options that I don't know how to use, possibly with github and my github username etc. in mind, and what they will lead to:

OpenID Connect options:
  --identity-token TOKEN
                        the OIDC identity token to use (default: None)
  --oidc-client-id ID   The custom OpenID Connect client ID to use during OAuth2 (default: sigstore)
  --oidc-client-secret SECRET
                        The custom OpenID Connect client secret to use during OAuth2 (default: None)
  --oidc-disable-ambient-providers
                        Disable ambient OpenID Connect credential detection (e.g. on GitHub Actions) (default:
                        False)
  --oidc-issuer URL     The OpenID Connect issuer to use (conflicts with --staging) (default:
                        https://oauth2.sigstore.dev/auth)
  --oauth-force-oob     Force an out-of-band OAuth flow and do not automatically start the default web browser
                        (default: False)
woodruffw commented 1 day ago

Though it means that with the JWT token passed to sigstore sign the signing is then automated?

Yes. If you pass a valid JWT via --identity-token, then everything else is automated.

The detail would then just be a description of the curl interactions with github. Is there documentation somewhere?

I think what you're looking for is something like this: https://stackoverflow.com/questions/53357741/how-to-perform-oauth-2-0-using-the-curl-cli

However, even with curl, you're not going to be able to remove the interactivity when doing an OAuth2 flow -- the flow is designed to require interactivity. You might be able to automate that interactivity, but that will probably require something more powerful than curl (like a browser actor, e.g. Playwright).

So what I am wondering about are the ---oidc-* command line options that I don't know how to use, possibly with github and my github username etc. in mind, and what they will lead to:

If you're trying to script an interactive flow, then you don't need any of those. Obtaining the JWT and passing it in via --identity-token will be sufficient. The --oidc-* options exist to tweak the behavior of the OAuth2 interactive flow within sigstore-python itself.

stefanberger commented 1 day ago

Though it means that with the JWT token passed to sigstore sign the signing is then automated?

Yes. If you pass a valid JWT via --identity-token, then everything else is automated.

The detail would then just be a description of the curl interactions with github. Is there documentation somewhere?

I think what you're looking for is something like this: https://stackoverflow.com/questions/53357741/how-to-perform-oauth-2-0-using-the-curl-cli

Thanks for the link. I haven't tried this. Would the resulting JWT token be a one-time token or can it be used multiple times?

However, even with curl, you're not going to be able to remove the interactivity when doing an OAuth2 flow -- the flow is designed to require interactivity. You might be able to automate that interactivity, but that will probably require something more powerful than curl (like a browser actor, e.g. Playwright).

So what I am wondering about are the ---oidc-* command line options that I don't know how to use, possibly with github and my github username etc. in mind, and what they will lead to:

If you're trying to script an interactive flow, then you don't need any of those. Obtaining the JWT and passing it in via --identity-token will be sufficient. The --oidc-* options exist to tweak the behavior of the OAuth2 interactive flow within sigstore-python itself.

Thanks for the informatiom.

Along the lines of automation I am also wondering where the root of the security is in gh-action-sigstore-python, which I haven't tried, and slsa-github-generator, which I did try to sign a few files. I know the latter works entirely interaction-less , since it's run in a github action and it required no setup from my side, and the former I would suspect runs like this as well -- no user interaction required.

For gh-action-sigstore-python you seem to allow setup for a identitity token GitHub Actions credential will be used"

- uses: sigstore/gh-action-sigstore-python@v3.0.0
  with:
    inputs: file.txt
    identity-token: ${{ IDENTITY_TOKEN  }} # assigned elsewhere

Is this again the JWT I would have to get? Or is there also something available like for slsa-gtihub-generator that makes this fully automatic in the github environment - which makes me curious how the interaction-lessness works so that nobody else could impersonate a github action environment.

woodruffw commented 1 day ago

Thanks for the link. I haven't tried this. Would the resulting JWT token be a one-time token or can it be used multiple times?

You can use it multiple times, until it expires. If I remember correctly, most JWTs expire within 10-15 minutes.

Along the lines of automation I am also wondering where the root of the security is in gh-action-sigstore-python, which I haven't tried, and slsa-github-generator, which I did try to sign a few files. I know the latter works entirely interaction-less , since it's run in a github action and it required no setup from my side, and the former I would suspect runs like this as well -- no user interaction required.

Yes, the two use the exact same internal mechanism: both use "ambient" OIDC identities from GitHub Actions itself, which means they don't require interactivity by default.

Is this again the JWT I would have to get? Or is there also something available like for slsa-gtihub-generator that makes this fully automatic in the github environment

Yes, if you want to sign with a JWT identity other than the "ambient" one provided by your GitHub Actions workflow. If you want to sign with the ambient one, then you don't need to supply anything.

which makes me curious how the interaction-lessness works so that nobody else could impersonate a github action environment.

The interaction-less flow involves a JWT that's signed by the GitHub Actions IdP, and has claims that GitHub enforces. To impersonate it, an attacker would need to either compromise the GitHub IdP or compromise the exact workflow identity that produced the JWT.

stefanberger commented 1 day ago

The interaction-less flow involves a JWT that's signed by the GitHub Actions IdP, and has claims that GitHub enforces. To impersonate it, an attacker would need to either compromise the GitHub IdP or compromise the exact workflow identity that produced the JWT.

Ok, this is the part that requests the identity token in the github environment when the action is running:

      - name: Get OIDC token
        id: get-oidc-token
        run: |
          identity_token=$( \
            curl -H \
              "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
              "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=sigstore" \
            | jq -r .value \
          )
          echo "identity-token=$identity_token" >> $GITHUB_OUTPUT

Source: https://github.com/sigstore/gh-action-sigstore-python/blob/f514d46b907ebcd5bedc05145c03b69c1edd8b46/.github/workflows/selftest.yml#L297-L306 Documentation from github: https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments/about-security-hardening-with-openid-connect#updating-your-actions-for-oidc

Another aspect is the auto-detection occurring in the github environment in the id package: https://pypi.org/project/id/ Source: https://github.com/di/id/blob/0a35392a02b8492feafa7ed94003ad7170b9bda2/id/_internal/oidc/ambient.py#L59-L89