Skip to content

Conversation

@haircommander
Copy link
Member

What type of PR is this?

/kind bug

What this PR does / why we need it:

So we can check a signature of an image that has both a tag and a digest

Which issue(s) this PR fixes:

fixes #8603

Special notes for your reviewer:

Does this PR introduce a user-facing change?

Fix a bug where signature checking failed if an image specified both a tag and a digest

@openshift-ci openshift-ci bot added release-note Denotes a PR that will be considered when it comes time to generate release notes. dco-signoff: yes Indicates the PR's author has DCO signed all their commits. kind/bug Categorizes issue or PR as related to a bug. labels Sep 13, 2024
// Such image references are supported by docker but, due to their ambiguity, explicitly not by containers/image.
//
// This should only be called from internal/storage.
func RegistryImageReferenceFromRawSerialized(rawNamed reference.Named) (RegistryImageReference, error) {
Copy link
Member Author

Choose a reason for hiding this comment

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

not crazy about this name, @mtrmac do you have any suggestions?

Copy link
Collaborator

Choose a reason for hiding this comment

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

See the other comment for a bit higher-level view…

… which still leaves open the naming of this canonicalization. My starting point is canonicalize{TagDigest,DockerLike} somewhere in the name, but that might get awfully long.

@openshift-ci openshift-ci bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Sep 13, 2024
@codecov
Copy link

codecov bot commented Sep 13, 2024

Codecov Report

Attention: Patch coverage is 37.50000% with 5 lines in your changes missing coverage. Please review.

Project coverage is 48.85%. Comparing base (ac758bb) to head (4a2d29e).
Report is 26 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8605      +/-   ##
==========================================
- Coverage   48.91%   48.85%   -0.07%     
==========================================
  Files         153      153              
  Lines       17372    17371       -1     
==========================================
- Hits         8498     8486      -12     
- Misses       7807     7819      +12     
+ Partials     1067     1066       -1     

@haircommander
Copy link
Member Author

/retest

Copy link
Collaborator

@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.

ACK to the overall functionality this achieves.


WRT the implementation … my question is “what rules are implied by the RegistryImageReference data type”? I think it should be one of:

  • :tag@digest references are unambiguously allowed by the data type.
    • In that case the mapping of :tag@digest to @digest-only must be in consumers of RegistryImageReference, i.e. in PullImage/IsRunningImageAllowed (and what value should be used in MetricImagePullsSuccessesInc, with or without the tag?)
    • or maybe RegistryImageReference should have a RawCanonicalized method that returns a value suitable for c/image, and most callers of Raw should migrate
  • :tag@digest references are unambiguously invalid in the data type. In that case
    • the constructor of RegistryImageReferenceFromRaw should reject that value to enforce the rule
    • It would be consistent for ParseRegistryImageReferenceFromOutOfProcessData to reject the data as well
    • We’d probably need some kind of …FromRawCanonicalizing and Parse…CanonicalizingFromOutOfProcesss… helpers, so that top-level callers don’t manipulate values directly.

The current PR is ambiguous about the permissibility of such values — the text parser canonicalizes them, but …FromRaw does not.

I weakly prefer the variant where :tag@digest values are invalid in RegistryImageReference, forcing its users to explicitly choose, by the constructor they call, whether they want to accept such values or not. If nothing else, the parseImageParent/parseImageChild RPC should never generate such values, and it can use the stricter parser/constructor.

// Such image references are supported by docker but, due to their ambiguity, explicitly not by containers/image.
//
// This should only be called from internal/storage.
func RegistryImageReferenceFromRawSerialized(rawNamed reference.Named) (RegistryImageReference, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

See the other comment for a bit higher-level view…

… which still leaves open the naming of this canonicalization. My starting point is canonicalize{TagDigest,DockerLike} somewhere in the name, but that might get awfully long.

[[ "$output" == *"SignatureValidationFailed"* ]]
}

@test "allow signed image with restrictive policy on container creation7 if already pulled (by tag and ID)" {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is fundamentally confusing things. “Image ID” (StorageImageID) is, historically (nowadays not always) the sha256 digest of the config, and usually expressed without the leading sha256:.

“image digest” is the sha256 of the manifest. The two are ~never the same for a single image.

In busybox:latest@sha256:…, the second value is the manifest digest. So assuming the value from crictl images -q is an image ID, using it in the manifest digest syntax should never find a match; and the test name is misleading.

(Also for the other added test.)

@haircommander
Copy link
Member Author

I agree the library should take care of canonicalizing. In fact, I just replaced *FromRaw with this behavior. Also i believe I updated the test to test digest and not storage ID. PTAL again @mtrmac

Copy link
Collaborator

@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.

I’d prefer two variants of constructors, one only in the “XOR” form, one canonicalizing — but this works, up to you.

Assuming this design, code LGTM, just some documentation suggestions.

Comment on lines 27 to 29
// It does two validations on rawNamed:
// - It validates the image either has a tag or a digest, but not both (preferring digest)
// - Verifies the image is not only a name.
Copy link
Collaborator

Choose a reason for hiding this comment

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

(The first one is a silent fix-up, and the second one causes an error; the phrasing suggests to me that both are treated equally.)

if isTagged && isDigested {
canonical, err := reference.WithDigest(reference.TrimNamed(rawNamed), canonical.Digest())
if err != nil {
return RegistryImageReference{}, err
Copy link
Collaborator

Choose a reason for hiding this comment

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

(The only way this can fail is if canonical.Digest() is invalid, and that shouldn’t have happened by induction, so I’d be fine with a panic here. But returning an error explicitly is perfectly valid as well.)

Copy link
Member Author

Choose a reason for hiding this comment

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

that's better because then I don't need to change the function signature

Copy link
Collaborator

Choose a reason for hiding this comment

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

Also using panic does not leave around (supposedly) 100% unreachable error handling code paths, considering that CRI-O is measuring code coverage.

}
ref = reference.TagNameOnly(ref)
return RegistryImageReferenceFromRaw(ref), nil
return RegistryImageReferenceFromRaw(ref)
Copy link
Collaborator

Choose a reason for hiding this comment

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

The documentation of ParseRegistryImageReferenceFromOutOfProcessData should document that it removes the tag from tag@digest inputs.

// Strip the tag from ambiguous image references that have a
// digest as well (e.g. `image:tag@sha256:123...`). Such
// image references are supported by docker but, due to their
// ambiguity, explicitly not by containers/image.
Copy link
Collaborator

Choose a reason for hiding this comment

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

(Absolutely non-blocking: Consider preserving some form of this comment, to have a documentation for the reason we modify the inputs.)

// It is only intended for communication with OUT-OF-PROCESS APIs,
// like registry references provided by CRI by Kubelet.
// It will modify the reference if both digest and tag are specified, stripping the tag and leaving the digest.
// It will also verifies the image is not only a name. If it is only a name, the function errors.
Copy link
Collaborator

Choose a reason for hiding this comment

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

The function does not fail in such a situation: The TagNameOnly call turns name-only references into name:latest

Copy link
Collaborator

@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.

Do you also want to fix the linter-highlighted typo?

LGTM either way.

So we can check a signature of an image that has both a tag and a digest

Signed-off-by: Peter Hunt <[email protected]>
@haircommander
Copy link
Member Author

whoops, fixed!

Copy link
Collaborator

@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.

/lgtm

@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Sep 16, 2024
@haircommander
Copy link
Member Author

/cherry-pick release-1.31

@openshift-cherrypick-robot

@haircommander: once the present PR merges, I will cherry-pick it on top of release-1.31 in a new PR and assign it to you.

In response to this:

/cherry-pick release-1.31

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@kwilczynski
Copy link
Contributor

/approve
/lgtm

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Sep 16, 2024

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: haircommander, kwilczynski

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@haircommander
Copy link
Member Author

/retest

2 similar comments
@haircommander
Copy link
Member Author

/retest

@haircommander
Copy link
Member Author

/retest

@openshift-merge-bot openshift-merge-bot bot merged commit a6805d8 into cri-o:main Sep 18, 2024
76 of 84 checks passed
@openshift-cherrypick-robot

@haircommander: new pull request created: #8618

In response to this:

/cherry-pick release-1.31

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

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

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. dco-signoff: yes Indicates the PR's author has DCO signed all their commits. kind/bug Categorizes issue or PR as related to a bug. lgtm Indicates that a PR is ready to be merged. release-note Denotes a PR that will be considered when it comes time to generate release notes.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[V1.31.0] Error: checking signature : Docker references with both a tag and digest are currently not supported

4 participants