-
Notifications
You must be signed in to change notification settings - Fork 556
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
Validate authority keys #1623
Validate authority keys #1623
Conversation
cb824e3
to
db8c7a7
Compare
tempKeys := keys | ||
config := config.FromContext(ctx) | ||
if config != nil { | ||
authorities, err := config.ImagePolicyConfig.GetAuthorities(ref.Name()) |
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.
Question: Wondering how I could structure a unit-test to mock out ctx
such that config.FromContext(ctx)
returns a config with mocked data for authorities[].key.data
. Currently, I tried to use context.WithValue(ctx, config.CfgKey{}, <ImagePolicyConfig populated struct>)
and this did not work (I made cfgKey{}
public in store.go
to temporarily try this).
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.
@DennyHoang Did you try to create a fake ConfigMap with the desired configuration in the tests ?
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.
Yup, pulling out the logic into a function and going to test that specifically. I will be passing in a mocked config now (and not consider mocking out context) so I can isolate the testing to the logic there.
As for testing the integration of that function, I'll look into that further afterwards.
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 think using this should work for this:
/~https://github.com/sigstore/cosign/blob/main/pkg/apis/config/store.go#L53
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 my, how did I not see that... Thanks, will give it a try!
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.
@vaikas @hectorj2f I tried to implement a test with the config.ToContext
1aa88d1
Please lemme know what you think and if I should/need to replicate this test case to the other test cases i.e TestValidateCronJob
, TestResolvePodSpec
, etc. I feel like it may not be required as this one test has enough coverage, but wanted a more concrete opinion from others who are more knowledgeable about how this all works.
(In the meantime, just noticed your comments below about error handling and will take a look now)
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.
It looks good to me.
Codecov Report
@@ Coverage Diff @@
## main #1623 +/- ##
==========================================
+ Coverage 27.97% 28.28% +0.30%
==========================================
Files 137 137
Lines 7820 7864 +44
==========================================
+ Hits 2188 2224 +36
- Misses 5403 5404 +1
- Partials 229 236 +7
Continue to review full report at Codecov.
|
2073be5
to
12f0c6b
Compare
Fantastic! Thanks for doing this. We also need to add validation here (since we didn't support it at the time, I made it disallowed). Then we should probably in the validation function see if the regex compiles, wdyt? I think this can then we caught earlier, during the creation of the resource. If we use something like this during the validation? And then maybe add a valid regex in here (or create a new file with just regex?): And maybe add an invalid regex file here as well? |
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 for doing this, and thanks for cleaning up the tests! I'm fine with this going on if you want to do the errors in the followup, but please create an issue to track that.
@@ -153,6 +161,29 @@ func (v *Validator) validatePodSpec(ctx context.Context, ps *corev1.PodSpec, opt | |||
return errs | |||
} | |||
|
|||
func getAuthorityKeys(ctx context.Context, ref name.Reference, config *config.Config) []*ecdsa.PublicKey { |
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 think this should not fail silently (L175). I'd first add err in the signature here. If we want to silently not fail things while we're working though, then where we call that, we can make that and create an issue to track that. But at least that way the flipping of the err/silent does not require changing the signature here.
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 if you want to do this as a followup, I'm fine with this going in now (so it won't break anything), but we should create an issue to ensure we don't forget about it :)
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.
+1 we should return an error here.
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.
Updated to surface errs and it is currently logged as a warning.
Tracking issue to actually enforce the errors in:
#1642
containerKeys := keys | ||
config := config.FromContext(ctx) | ||
if config != nil { | ||
containerKeys = append(containerKeys, getAuthorityKeys(ctx, ref, config)...) |
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.
So here, I think we should (if you change getAuthorityKeys to return a possible error), we could skip enforcing it now if we're worried about breaking things. That way when we flip things to fail on errors (which I think we should), the change is localiced to here only.
containerKeys := keys | ||
config := config.FromContext(ctx) | ||
if config != nil { | ||
containerKeys = append(containerKeys, getAuthorityKeys(ctx, ref, config)...) |
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.
So here, I think we should (if you change getAuthorityKeys to return a possible error), we could skip enforcing it now if we're worried about breaking things. That way when we flip things to fail on errors (which I think we should), the change is localiced to here only.
keys = append(keys, key.(*ecdsa.PublicKey)) | ||
} | ||
} | ||
if keys == 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.
Suggestion: you may want to do len(keys) == 0
instead.
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.
Do you want to switch from Draft? I think it's in a shape where we can get it in and continue working on it, wdyt?
@@ -153,6 +166,26 @@ func (v *Validator) validatePodSpec(ctx context.Context, ps *corev1.PodSpec, opt | |||
return errs | |||
} | |||
|
|||
func getAuthorityKeys(ctx context.Context, ref name.Reference, config *config.Config) (keys []*ecdsa.PublicKey, errs *apis.FieldError) { |
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'm not sure we want to make these as apis.FieldError. We usually use those as validation time errors because they are user facing directly. I'd just been thinking that we'll use err for the return value, not apis.FieldError. But then as I started thinking about it some more, the are user facing at least in some cases because they will be returned to the user when they try to deploy something.
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 also felt similar that it should have been errors
initially. I followed using apis.ErrGeneric
because getAuthorityKeys/parseAuthorityKeys
followed the same logic from getKeys
. getKeys
returned errors using apis.ErrGeneric
. I just tried to surface the lowest level error up and made it a common type. Should I change it such that getAuthorityKeys returns errors only and then have validatePodSpec
determine how to interpret generic error
such as into apis.FieldError?
Or is this something that can be changed later when we actually start erroring out more concretely? The change seems trivial enough either way you want it.
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.
Question: why do we even need to parse the authority keys here ? The function call comes from validatePodSpec, i assume the parsing of the authorities has been done when creating the image policy config, rather when validating the pod spec.
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.
When we get the ImagePolicyConfig
, it contains Policies.[]ClusterImagePolicySpec.[]Authority
. The returned Authority
contains KeyRef.Data
which is a string. parseAuthorityKeys
takes that string and parses it into ecdsa.PublicKey
. I do not believe we have a ecdsa.PublicKey
representation of the key earlier.
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.
Well, sorry I was thinking that we could be defining the signature as error, I think at least (too lazy to look up as I'm on the phone) we could still be returning apierrors as they are errors but not bleed that into the signature of the function.
Also I've been working on adding the Keyless stuff into this, so if we get this merged, we can keep working on respective pieces :) |
Signed-off-by: Denny Hoang <dhoang@vmware.com>
Signed-off-by: Denny Hoang <dhoang@vmware.com>
Signed-off-by: Denny Hoang <dhoang@vmware.com>
Signed-off-by: Denny Hoang <dhoang@vmware.com>
Signed-off-by: Denny Hoang <dhoang@vmware.com>
Signed-off-by: Denny Hoang <dhoang@vmware.com>
Signed-off-by: Denny Hoang <dhoang@vmware.com>
Signed-off-by: Denny Hoang <dhoang@vmware.com>
Signed-off-by: Denny Hoang <dhoang@vmware.com>
Signed-off-by: Denny Hoang <dhoang@vmware.com>
Signed-off-by: Denny Hoang <dhoang@vmware.com>
Signed-off-by: Denny Hoang <dhoang@vmware.com>
f149c6a
to
f0f659e
Compare
@vaikas @hectorj2f I can't update the PR from Draft since "Only those with write access to this repository can mark a draft pull request as ready for review." Could either of you two help me by updating it? |
Set to "Ready for Review" |
Signed-off-by: Denny Hoang <dhoang@vmware.com>
Signed-off-by: Denny Hoang <dhoang@vmware.com>
@hectorj2f @vaikas |
Rerunning! |
reran it one more time, looked like a GCP flake. |
Yes, it was a GCP flake. |
* Validate signature with authority keys Signed-off-by: Denny Hoang <dhoang@vmware.com> * Remove TODO log Signed-off-by: Denny Hoang <dhoang@vmware.com> * Add authority key info log & ko-apply to makefile Signed-off-by: Denny Hoang <dhoang@vmware.com> * Abstract and test getting authority keys Signed-off-by: Denny Hoang <dhoang@vmware.com> * Add authority regex matching for images Signed-off-by: Denny Hoang <dhoang@vmware.com> * Add more get authority key scenarios Signed-off-by: Denny Hoang <dhoang@vmware.com> * Rename and use variables Signed-off-by: Denny Hoang <dhoang@vmware.com> * Validate and compile regex Signed-off-by: Denny Hoang <dhoang@vmware.com> * Add regex cosigned testdata Signed-off-by: Denny Hoang <dhoang@vmware.com> * Fix lint error Signed-off-by: Denny Hoang <dhoang@vmware.com> * Test authority key integration Signed-off-by: Denny Hoang <dhoang@vmware.com> * Surface non-enforced errors Signed-off-by: Denny Hoang <dhoang@vmware.com> * Fix linting errors Signed-off-by: Denny Hoang <dhoang@vmware.com> * Fix e2e crd test to remove crd between tests Signed-off-by: Denny Hoang <dhoang@vmware.com> Co-authored-by: Denny Hoang <dhoang@vmware.com>
Resolves #1419
Summary
Begin integration of clusterimagepolicy into cosigned webhook.
@DennyHoang