-
Notifications
You must be signed in to change notification settings - Fork 402
Add field KeyPaths to prSigstoreSigned #2456
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
Conversation
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.
Thanks! We definitely want this feature.
I realize this is a quite early version — so just some higher-level comments; I didn’t carefully read the code line by line.
- I think it makes sense to add
KeyDatasat the same time. (It is not necessary for GPG, because the data format natively supports multiple keys.) - We might also want the same multi-key feature for
rekorPublicKey*. That does not need to happen in this PR, but it’s something to potentially keep in mind WRT sharing code (e.g. usingloadBytesFromDataOrPathfor both). - Ultimately, every line of code (and every user-visible feature) in
signatureshould either be covered by unit tests, or have a comment documenting why the line is unreachable. It would probably make sense to delay that after the basic implementation is OK, but something to keep in mind when structuring it.
6b6274e to
3354891
Compare
6dde503 to
87a954e
Compare
|
Just a quick ACK — I definitely want this feature to happen short-term, and I appreciate your work on it. Right now I need to finish some other work (related to the zstd:chunked), so I’m afraid I’ll only be able to review this in detail in a week or two. I just wanted to be transparent about it, while reaffirming that this is important both to me personally and to my employer, and that the effort is not wasted. |
|
Miloslav Trmač ***@***.***> writes:
Just a quick ACK — I definitely want this feature to happen short-term, and I appreciate your work on it. Right now I need to finish some other work (related to the zstd:chunked), so I’m afraid I’ll only be able to review this in detail in a week or two. I just wanted to be transparent about it, while reaffirming that this _is_ important both to me personally and to my employer, and that the effort is not wasted.
No worries, myself and Danish haven't been that responsive either. We'll
continue to work on improving the test coverage in the meantime.
|
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.
Thanks!
I’m finally back to this project — this looks very good overall, most of the comments are stylistic nitpicks.
I’ll work tomorrow on making those adjustments.
| @@ -320,13 +348,18 @@ func TestPRrSigstoreSignedIsSignatureAccepted(t *testing.T) { | |||
|
|
|||
| // Successful key+Rekor use | |||
| pr, err = newPRSigstoreSigned( | |||
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.
Also test: the second key, not the first one, matches the Rekor data.
| assertAccepted(sar, err) | ||
| tr, err := pr.prepareTrustRoot() | ||
| assert.NoError(t, err) | ||
| assert.Equal(t, sar.pk, tr.publicKeys[1]) | ||
|
|
||
| // key+Rekor, missing Rekor SET annotation | ||
| sar, err = pr.isSignatureAccepted(context.Background(), nil, |
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.
Also test: two keys + invalid Rekor SET
| // at this point we must have failed to verify the signature with every key | ||
| // => there must be at least one error | ||
| if len(errs) == 0 { | ||
| return nil, nil, fmt.Errorf("Internal error: signature verification failed but no errors have been recorded") |
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.
By convention in c/image/signature, this should have a // Coverage: … comment justifying why it is not covered by tests, maybe instead of the comment above.
(Alternatively, we could drop the len(publicKeys) check at the start of the function and only determine that here. That’s not obviously better.)
| PRSigstoreSignedWithKeyDatas([][]byte{[]byte("foo")}), | ||
| PRSigstoreSignedWithKeyData([]byte("bar")), | ||
| PRSigstoreSignedWithSignedIdentity(testIdentity), | ||
| }, |
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.
Also test: duplicate keyPaths, duplicate keyDatas
signature/policy_config_sigstore.go
Outdated
| PRSigstoreSignedWithSignedIdentity(signedIdentity), | ||
| ) | ||
| } | ||
|
|
||
| // Compile-time check that prSigstoreSigned implements json.Unmarshaler. | ||
| var _ json.Unmarshaler = (*prSigstoreSigned)(nil) |
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.
That implementation also needs to be extended with the new fields, otherwise using them in policy.json wouldn’t work.
The new fields `KeyPaths` and `KeyDatas` is taken directly from `/etc/containers/policy.json` and allows users to provide multiple signature keys to be used to verify images. Only one of the keys has to verify, thereby this mechanism allows us to have support seamless key rotation on a registry. This fixes containers#2319 Signed-off-by: Dan Čermák <dcermak@suse.com> Co-authored-by: Danish Prakash <danish.prakash@suse.com>
…ayload Signed-off-by: Dan Čermák <dcermak@suse.com> Co-authored-by: Danish Prakash <danish.prakash@suse.com>
It also contains the public key that verified the image signature and thereby allows us to check easier which key was picked in the presence of multiple keys Signed-off-by: Dan Čermák <dcermak@suse.com> Co-authored-by: Danish Prakash <danish.prakash@suse.com>
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.
Thanks so much for a quick update!
As promised, I have continued updating some of the style + test nits. See #2524, perhaps best without the last commit.
It is very much a WIP, e.g. we probably don’t need all those individual commits. Still, I hope that is useful.
| @@ -316,11 +316,13 @@ used with `exactReference` or `exactRepository`. | |||
|
|
|||
| This requirement requires an image to be signed using a sigstore signature with an expected identity and key. | |||
|
|
|||
| ```js | |||
| ```json | |||
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.
Using JSON here causes the identity_requirement value to be highlighted as an error.
|
|
||
| If `keyPath` or `keyData` is present, it contains a sigstore public key. | ||
| Only signatures made by this key are accepted. | ||
|
|
||
| If `keyPaths` or `keyDatas` is present, it contains sigstore public keys that | ||
| sign the images. Signatures from any key in the list is accepted. |
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.
“signatures … are accepted”.
I don’t feel too strongly about the “that sign the images” part, but it should probably consistent with the previous paragraph, so that users don’t try to look for a difference in meaning.
| if res.Fulcio != nil { | ||
| keySources++ | ||
| } | ||
|
|
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.
(Drop this line as well.)
| // unmarshal after the signature has been verified, this is more | ||
| // resilient against bugs in the JSON parser | ||
| // Only perform the unmarshal in the first loop iteration | ||
| if unmatchedPayload == nil { |
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.
Once we enter this area, we either succeed or fail; we never iterate the loop again.
So this condition is unnecessary…
… really I think this would be easier to follow moving the cryptographic verification loop into a separate function, and having VerifySigstorePayload be a straight line code, instead of the primary code path ending inside a loop. That’s non-blocking, but it would avoid these situations.
|
#2524 was merged. Thanks again! |
|
… and this is included in https://github.com/containers/image/releases/tag/v5.32.2 . |
The new field
KeyPathsis taken directly from/etc/containers/policy.jsonand allows users to provide multiple signature keys to be used to verify images. Only one of the keys has to verify, thereby this mechanism allows us to have support seamless key rotation on a registry.This fixes #2319