-
Notifications
You must be signed in to change notification settings - Fork 50
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
signer: add basic sigstore signer and verifier #522
Conversation
need to update permissions ... |
NOTE: The ``signature`` attribute of the returned object | ||
contains the ``dict`` representation of a sigstore ``Bundle`. | ||
This is incompatible with the TUF specification and the | ||
``Signature` interface, which expect the attribute to be of type `str`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could store the bundle in a separate "bundle" field in the signature, nothing forces us to use "sig", right?
To keep spec conformance at 100% could even fill "sig" with the actual signature value -- even if it's useless without the bundle
Adds SigstoreSigner and SigstoreKey implementations to the securesystemslib signer interface. They can be used to create and verify signatures using an OIDC token and an identity/issuer pair respectively, as described in the TAP: "Ephemeral identity verification using sigstore's Fulcio for TUF developer key management" https://github.com/theupdateframework/taps/blob/3b0d8b108758266e36790b3a782b943d633ce585/candidate-fulcio-tap.md IMPORTANT NOTES: - the created signature does not strictly follow the typing requirements of the interface - currently, only offline verification is supported This patch also adds a GitHub Action workflow that runs a tailored test, using ambient credentials for signing. Signed-off-by: Lukas Puehringer <[email protected]>
Signed-off-by: Lukas Puehringer <[email protected]>
The sigstore library is an optional and circular dependency in securesystemslib. Importing it in the methods, where it is needed, allows importing the module from within sigstore (circular import), or if sigstore is not installed. This commit wraps the local scope imports in try/except to fail gracefully if the methods are called w/o sigstore available, and locally disables the related linter warning. The commit also disables a linter import warning in the related test, which requires sigstore. Alternatively, we could install sigstore in the lint job, which does not seem worth the cycles, just for one method call. Signed-off-by: Lukas Puehringer <[email protected]>
Key.verify_signature implementations should only raise UnverifiedSignatureError or VerificationError, even if an optional dependency is missing. This commit wraps everything in the corresponding try block and removes the previously added UnsupportedLibraryError on ImportError. Plus some minor renames for horizontal density. Signed-off-by: Lukas Puehringer <[email protected]>
The Signature.signature field is defined as hex string of the signature byte data. But for sigstore we need to store a complex signature bundle, which also contains signature byte data. To stay compatible with the API, we store both, the signature byte data from the bundle in the Signature.signature field, and the whole bundle under unrecognized_fields. Signed-off-by: Lukas Puehringer <[email protected]>
Signed-off-by: Lukas Puehringer <[email protected]>
Signed-off-by: Lukas Puehringer <[email protected]>
Appease linter w/o installing optional requirement in linter run. Signed-off-by: Lukas Puehringer <[email protected]>
Signed-off-by: Lukas Puehringer <[email protected]>
Okay, I think this is mergable as self-contained feature. To be a fully usable signer, we need to add from_priv_key_uri, but I suggest to do that in a follow-up PR. The "on: pull_request" test-sigstore job should start working once this PR is merged. A successful run is already available in my fork: https://github.com/lukpueh/securesystemslib/actions/runs/4355175849/jobs/7611437818 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good.
I think it's likely that the key format is not final but I think we should get this merged and just keep it "unstable":
- TAP really needs an implementation so this serves that need
- the implementation should work fine already as long as you don't want anything else than the public good instance
Thinking about the future changes: we can just add keytypes/schemes if we want to support this implementation and a newer one at some point
if not result: | ||
logger.info( | ||
"Key %s failed to verify sig: %s", self.keyid, result.reason | ||
) | ||
raise UnverifiedSignatureError( | ||
f"Failed to verify signature by {self.keyid}" | ||
) | ||
except UnverifiedSignatureError: | ||
raise |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: you could probably handle result
outside of the try block to avoid this raise-except-raise pattern.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point! Can you check if the commit I just pushed resolves this to your liking.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah that looks good to me
GITHUB_ACTIONS | ||
ACTIONS_ID_TOKEN_REQUEST_TOKEN | ||
ACTIONS_ID_TOKEN_REQUEST_URL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these are used by ambient credentials detection?
from sigstore.verify.policy import Identity | ||
from sigstore_protobuf_specs.dev.sigstore.bundle.v1 import Bundle | ||
|
||
verifier = Verifier.production() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seeing this code it seems clear that the content in our key should include everything needed to choose the sigstore "instance".
That said, it's quite unclear to me what that all means (rekor and tuf urls? fulcio?): this is really more a question for the TAP than this implementation which should focus on supporting the default instance for now
So no action requested here.
Should the module or the classes be marked "unstable API" or something? |
push: | ||
branches: | ||
- main | ||
pull_request: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should remove this as it will unfortunately keep failing for PRs
We should also maybe file an issue for managing these tests that can be only run on upstream branches... so that an issue would be raised when a test fails
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, I actually did that in kms-tests: you can probably copy the file-ticket-on-failure step from there
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should remove this as it will unfortunately keep failing for PRs
Is that the case? Shouldn't it work, once the workflow is merged?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so: pull requests have read only permissions and you need id-token: write
or in more OIDC terms, pull requests aren't allowed to "authenticate" as the project (even though sometimes it would make sense, since the authentication is not for the whole project but for the specific workflow which could be dedicated for PRs...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but feel free to test by merging: we can fix with another PR if it does not work
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jku: Looks like this actually works:
https://github.com/secure-systems-lab/securesystemslib/actions/runs/4382839569
Build was triggered via pull request and apparently had the required permissions.
Or maybe it only worked because the pr didn't come from a fork. 🤷
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe it only worked because the pr didn't come from a fork. shrug
yes, correct: I expect branches in upstream repo to work, but branches in forks to fail
As per Jussi's CR: - Add comments to explain env vars - Add comments to mark API as unstable - Refactor raise-except-raise pattern Signed-off-by: Lukas Puehringer <[email protected]>
Adds SigstoreSigner and SigstoreKey implementations to the securesystemslib signer interface. They can be used to create and verify signatures using an OIDC token and an identity/issuer pair respectively, as described in the TAP:
"Ephemeral identity verification using sigstore's Fulcio for TUF developer key management"
IMPORTANT NOTES:
the created signature does not strictly follow the typing requirements of the interfaceThis patch also adds a GitHub Action workflow that runs a tailored test, using ambient credentials for signing.
This should already work, but I'd like to fix a few things before I mark this "ready for review".
fix circular imports and inline-import workaround(local scope import seems like the right choice here)make online/offline verification configurable (maybe in follow-up PR)(let's discuss this in the TAP)