-
Notifications
You must be signed in to change notification settings - Fork 385
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
Check for unsigned images #2035
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -253,6 +253,32 @@ func (pc *PolicyContext) GetSignaturesWithAcceptedAuthor(ctx context.Context, pu | |
return res, nil | ||
} | ||
|
||
// IsImagePolicySigned true iff the policy requirement for the image is not insecureAcceptAnything | ||
func (pc *PolicyContext) IsImagePolicySigned(publicImage types.UnparsedImage) (res bool, finalErr error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd say let's not replicate the "bool and error" that we now think was a mistake. IOW, let's call this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (I’m not really expressing an opinion on the API at this point. Should this be a flag to But at the very least, the function name must not be misleading. This one would succeed on a “policy: reject”, so it is clearly not “is the policy requiring signed images”. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes, I think that'd be better. Well, we can't change that API now, but hat we could do is introduce a new, Or maybe what would be nicer even is something like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I’m not much of a fan of the policy evaluation returning a multi-valued object, with callers making their own policy decisions on top. What if we flipped this around, and added a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just discovered But it seems to be related in that what we want is "evaluate the policy and require signatures". One thing I also want is something like a
The And that's a very useful thing to log for visibility. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I'm OK with that, yes. So are we iterating towards two new APIs?
Where There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I disagree. I want my tooling (at least bootc e.g.) to be able to highlight and make visible the signature state on success in a reliable fashion in the same way rpm-ostree does today. Parsing log messages is not a reliable approach. At a practical level because we use the proxy in skopeo as a subprocess, if we had "configure logrus so we can scrape out logs from success" the code would need to move there... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
IOW, that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
We did the same in ostree, and it caused performance problems to be constantly re-verifying the signature to display this state. Further, it's possible for the signature policy to change from when an image was pulled. So the policy check isn't actually quite reproducible.
I don't expect users to go to often verify that manually. But I do think it's reasonable for auditing/compliance tools to check the presence of this string. It acts as a "proof of work". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
BTW, rpm-software-management/dnf5#617 (comment) is a parallel in the dnf world, where also the signature verification state is not cached anywhere and tooling doesn't make it very visible. If dnf did something like rpm-ostree does, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It seems to me that “when a signature is verified / how that is recorded” is a fairly orthogonal discussion.
Sure, an audit log makes sense — that’s not a part of the UI; typically it would be reported to a dedicated machine ASAP. A later “does this system host anything suspicious” check would better be implemented verifying the stored image against the stored signatures, rather than trusting some local “verified on X and it matched fingerprint Y at that time” record. |
||
if err := pc.changeState(pcReady, pcInUse); err != nil { | ||
return false, err | ||
} | ||
defer func() { | ||
if err := pc.changeState(pcInUse, pcReady); err != nil { | ||
res = false | ||
finalErr = err | ||
} | ||
}() | ||
|
||
image := unparsedimage.FromPublic(publicImage) | ||
|
||
logrus.Debugf("IsImagePolicySigned for image %s", policyIdentityLogName(image.Reference())) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this is logging an operation, it should also log the outcome and/or a reason. Or maybe log nothing and let the caller do that. |
||
reqs := pc.requirementsForImageRef(image.Reference()) | ||
|
||
for _, req := range reqs { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Multiple requirements can apply; why does it make sense to fail on e.g. a ( |
||
if req == NewPRInsecureAcceptAnything() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Super minor nit, I think we can avoid instantiating a new instance of this on each iteration of the loop. IOW something more like:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This does not work at all, AFAICS. Nothing promises that (Frankly, submitting a security PR that clearly fails leaves a bad impression.) |
||
return false, PolicyRequirementError("The policy defined for the image must not be InsecureAcceptAnything") | ||
} | ||
} | ||
|
||
return true, nil | ||
} | ||
|
||
// IsRunningImageAllowed returns true iff the policy allows running the image. | ||
// If it returns false, err must be non-nil, and should be an PolicyRequirementError if evaluation | ||
// succeeded but the result was rejection. | ||
|
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 it'd be easy to add unit tests for this in
policy_eval_test.go