Skip to content

Conversation

jlebon
Copy link
Contributor

@jlebon jlebon commented Sep 24, 2025

In bootc, we want the ability to assert that signature verification is enforced, but there are no mechanisms for this in the library.

Add a new SetRejectInsecure method on the PolicyContext object which would allow this.

Since this only changes the behaviour of the insecureAcceptAnything policy requirement, rather than extending the policy requirement interface, I went with a filtering approach directly in IsRunningImageAllowed().

Test generation was Assisted-by: Claude Code v1.0.120.

Part of containers/skopeo#1829.

@github-actions github-actions bot added the image Related to "image" package label Sep 24, 2025
podmanbot pushed a commit to podmanbot/buildah that referenced this pull request Sep 24, 2025
@jlebon
Copy link
Contributor Author

jlebon commented Sep 24, 2025

rather than extending the policy requirement interface

I initially went that way so have code for this as well if we want to compare.

Keeping it in draft for now until there's agreement on the approach.

Copy link
Contributor

@mtrmac mtrmac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Just a very quick drive-by, looking at the implementation. The much more important part is designing the semantics of the new option, and I don’t have an opinion on that yet.

@cgwalters
Copy link
Contributor

Thanks for starting this! I think in the general case what we also want here is something like podman pull --require-signature or so.

@jlebon
Copy link
Contributor Author

jlebon commented Sep 26, 2025

Thanks for starting this! I think in the general case what we also want here is something like podman pull --require-signature or so.

I did briefly look at that. Worth noting that e.g. skopeo today has an --insecure-policy but podman does not. Not sure if that was on purpose or an oversight. But yeah, I would agree.

@mtrmac
Copy link
Contributor

mtrmac commented Oct 1, 2025

There’s a degree of implementation difficulty for Podman: Skopeo has the policy configuration centralized, as a top-level option; AFAIK Podman does not, really. So, an option would have to be added to each subcommand individually, or the policy setup would need to be fairly significantly refactored.

(Complicating this even more, for Podman, is the “remote” mode where the CLI is an API client to a server on a different VM / machine. Even if we did centralize the CLI handling, we would still need to add the “reject insecure” field (and the pre-existing “signature policy path”) to every single API operation individually. That’s one of the reasons the podman pull --signature-policy flag is entirely unavailable in remote mode — I suppose it would be viable to do the same here, and just not implement the feature for remote.)

@mtrmac mtrmac added the enhancement New feature or request label Oct 3, 2025
In bootc, we want the ability to assert that signature verification is
enforced, but there are no mechanisms for this in the library.

Add a new `SetRejectInsecure` method on the `PolicyContext` object which
would allow this.

Add a new `isInsecure` method on the `PolicyRequirement` interface which
then allows `IsRunningImageAllowed` to detect if at least one secure
requirement was present.

Test generation was `Assisted-by: Claude Code v1.0.120`.

Part of containers/skopeo#1829.

Signed-off-by: Jonathan Lebon <[email protected]>
podmanbot pushed a commit to podmanbot/buildah that referenced this pull request Oct 5, 2025
@podmanbot
Copy link

✅ A new PR has been created in buildah to vendor these changes: containers/buildah#6409

}

func (pr *prSignedBaseLayer) isInsecure() bool {
return false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deciding whether “signed base layer” is “secure” is … a weird question. Not really an interesting question, given that this is an unusable stub…

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I guess I should probably just flip this to true for now and add a FIXME here too to reconsider once it's implemented. It definitely stresses the binary secure vs insecure logic, so it might have to be reworked a bit at that point based on what semantics we want.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading #355 (comment) , if the semantics is “we authenticated the image at least once”, prSignedBaseLayer does not meaningfully do that — a child layer on top of the signed ones can change the image in unrestricted ways.

So I think this should just be true, and no FIXME necessary.

@jlebon jlebon marked this pull request as ready for review October 6, 2025 15:22
Copy link

@aguidirh aguidirh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, I left only a nit.

return false, PolicyRequirementError(fmt.Sprintf("No secure policy found for image %s.", transports.ImageName(image.Reference())))
}

// We have tested that len(reqs) != 0, so at least one req must have explicitly allowed this image.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Is it needed to update this comment? It seems that having at least one req allowed is not enough to get to R312, since R299 will do a early return if at least one req is not allowed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Either way, I don’t think this PR changes the situation.)

Copy link
Contributor

@mtrmac mtrmac Oct 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment is trying to say “if we get to this point, len(reqs) > 0 and there was at least one req where allowed == true”, not “if len(reqs) > 0 and there was at least one req where allowed == true, we always get to this point”.

Copy link
Contributor

@mtrmac mtrmac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A full review now.

// layers. Users must validate that the layers match their expected digests.
isRunningImageAllowed(ctx context.Context, image private.UnparsedImage) (bool, error)

// isInsecure returns true if the requirement allows images without any signatures.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

“allows images with unauthenticated contents”, per #355 (comment) ?

(A possible hypothetical to think about is a PolicyRequirement that “the input reference is a digested reference” — in that case the contents of the image would be authenticated, but by the caller-provided input, not cryptographically. “allows images with unsigned contents”, maybe? Which of the two?)

// SetRejectInsecure modifies insecure policy requirement handling. If
// passed `true`, policy checking by IsRunningImageAllowed will ignore the
// "insecureAcceptAnything" policy type.
func (pc *PolicyContext) SetRejectInsecure(val bool) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The description (and name?) will need updating per the “authenticated contents”/“signed contents” discussion elsewhere.

(Choose the semantics that bootc needs; we can always add one more option with some other semantics in the future if it turned out to be necessary for other users.)

}

if pc.rejectInsecure && !wasSecure {
return false, PolicyRequirementError(fmt.Sprintf("No secure policy found for image %s.", transports.ImageName(image.Reference())))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

policyIdentityLogName would be a bit more appropriate, it would more directly point at the relevant policy.json scope.

// SetRejectInsecure modifies insecure policy requirement handling. If
// passed `true`, policy checking by IsRunningImageAllowed will ignore the
// "insecureAcceptAnything" policy type.
func (pc *PolicyContext) SetRejectInsecure(val bool) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Thinking whether this should reject repeated calls, as an indication of a confused caller … we’d have to add an error return, and all callers would need to check it for all of this to make a difference — that wouldn’t really work, let’s not do that.)

// insecureAcceptAnything only: should be rejected (leaves no secure requirements)
img = pcImageMock(t, "fixtures/dir-img-valid", "testing/manifest:insecureOnly")
res, err = pc.IsRunningImageAllowed(context.Background(), img)
assert.Equal(t, false, res)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assertRunningRejectedPolicyRequirement please, in both of the “error” situations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request image Related to "image" package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants