-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
Verify image signatures #12616
Verify image signatures #12616
Conversation
Note that we are supposed to use the https://github.com/containers/image library here to perform the verification, however in the current state we can't pull it to openshift godeps because:
This PR bundles the piece we need from @smarterclayton do we want to hold off this until the containers/image is ready? |
4599f49
to
e3bf3a3
Compare
Why does containers/image depend on Kube? That's a no-no for us.
On Jan 23, 2017, at 8:57 AM, Michal Fojtik <[email protected]> wrote:
Note that we are supposed to use the https://github.com/containers/image
library here to perform the verification, however in the current state we
can't pull it to openshift godeps because:
1. The openpgp support is not merged yet
2. containers/image#207 <containers/image#207>
adding the openpgp introduces a new build flag
3. It causes mess with Kubernetes imports (as containers/image pulls
latest Kubernetes in...)
This PR bundles the piece we need from containers/image we need to perform
the openpgp verification and it can be replaced with the library when it
become ready.
@smarterclayton <https://github.com/smarterclayton> do we want to hold off
this until the containers/image is ready?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#12616 (comment)>,
or mute
the thread
<https://github.com/notifications/unsubscribe-auth/ABG_p2SJ-wariStN5ug0ld8Ko6Csly6gks5rVLHfgaJpZM4LrEKf>
.
|
@smarterclayton they fixed it but another two emerge... containers/image#207 (comment) and I'm not really commited to bump distribution and go-connections :-/ |
@@ -39,9 +39,6 @@ func (s imageStrategy) PrepareForCreate(ctx kapi.Context, obj runtime.Object) { | |||
if err := api.ImageWithMetadata(newImage); err != nil { | |||
utilruntime.HandleError(fmt.Errorf("Unable to update image metadata for %q: %v", newImage.Name, err)) | |||
} | |||
|
|||
// clear signature fields that will be later set by server once it's able to parse the content | |||
s.clearSignatureDetails(newImage) |
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.
Validate the signatures. Right, the signatures are validated anyway.
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.
@miminar i think the signatures are already validated in API validation.
formatString(out, "\tStatus", "Verified") | ||
formatString(out, "\tIssued By", s.IssuedBy.CommonName) | ||
if len(s.Conditions) > 0 { | ||
for _, c := range s.Conditions { |
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.
Could you squash conditions of the same time? (Print just the latest value)
"github.com/spf13/cobra" | ||
kapi "k8s.io/kubernetes/pkg/api" | ||
"k8s.io/kubernetes/pkg/api/unversioned" | ||
kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" |
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.
Split OpenShift, kube and other deps into groups.
|
||
This command verifies if the signature attached to an image is trusted by | ||
using the provided public GPG key. | ||
By default this command will not record the signature condition back to the Image object but only |
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 default
comma
a signature condition
if o.Confirm && !o.Remove { | ||
if me, err := o.Client.Users().Get("~"); err != nil { | ||
return err | ||
} else { |
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.
no else
is necessary
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 is because me
exists only in the if
scope.
return err | ||
} | ||
if len(img.Signatures) == 0 { | ||
return fmt.Errorf("%s does not have signature", img.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.
any
if o.Confirm { | ||
fmt.Fprintf(o.ErrOut, "%s: %v\n", o.InputImage, signatureErr) | ||
} else { | ||
return fmt.Errorf("%s: %v", o.InputImage, signatureErr) |
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'd like to see all the errors regardless of --confirm
flag.
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.
you will, this is here just to support --remove
} | ||
} | ||
|
||
if o.Confirm { |
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 don't see o.Remove
being handled.
return err | ||
} | ||
} else { | ||
fmt.Fprintf(o.Out, "(add --confirm to record signature verification status to server\n") |
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.
not closed parenthesis
// TODO: This should not be just a key id but a human-readable identity. | ||
img.Signatures[i].IssuedBy.CommonName = signedBy | ||
// Record updated information back to the server | ||
if _, err := o.Client.Images().Update(img); err != 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.
Can this be called just once for all the signatures?
Sorry, merely doing a GPG verification and throwing away the contents is ABSOLUTELY INSUFFICIENT. This way any properly signed blob applies to any image; I can take a valid signature of RHEL7.3, attach it it to a container image of backdoored Kali Linux, and it would be accepted! |
@mtrmac agree, I will add the verification of the message content as well (iow. I will read the signature and compare the critical.image against the image you are verifying the image. Note that this is just a temporary solution, we still want to take advantage of containers/image once we resolve our dependencies. |
|
@mtrmac that one is tricky... Given I have this in message: Will a comparison of |
That depends on what the image is (is this a daily build created within this cluster? An base image from a supplier), and that’s one of the reasons why the fairly complex |
… but note that if the UI asks the user to specify a manifest digest (“image ID”) but not the tag, then the user can not make a distinction between |
So, the minimal, |
In manifest schema 1, there's a Tag specified in the manifest - equal to the tag the docker daemon used to upload the image. That may be what you want. However, manifest schema 2 doesn't have it. |
// .gnupg/pubring.gpg will be ignored. | ||
if len(o.PublicKeyFilename) > 0 { | ||
if o.Remove { | ||
return kcmdutil.UsageError(cmd, "cannot use public key when removing verifications status") |
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.
verification
// removeImageSignature removes the current image signature from the Image object by | ||
// erasing all signature fields that were previously set (when image signature was | ||
// previously verified). | ||
func (o *VerifyImageSignatureOptions) removeImageSignature(s *imageapi.ImageSignature) { |
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.
Name of this suggests that the whole signature will be removed. What about clearSignatureVerificationStatus
?
// If we have error and --confirm then remove the signature from the image which | ||
// changes the image to "unverified" state. | ||
if signatureErr != nil || signatureContentErr != nil { | ||
o.removeImageSignature(&img.Signatures[i]) |
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.
Can we record the error in the signature as as a condition {"Type": "Trusted", "Status": "false", "Reason": "error", "Message": err}
?
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.
@miminar we can but then you have to deal with the existing "trusted" condition that is set to "true", so should you set that to "false" 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.
Exactly ... {"Type": "Trusted", "Status": "False"}
➡️ `"Trusted": "False" ➡️ not trusted.
When you're dealing with "Trusted"
condition, you have to check the status for "True"
anyway to consider the image trusted.
6bf7f8e
to
562ebf6
Compare
@mtrmac I think we should discuss this IRL, but my take on this is:
However, I think the "digest" guarantees the content (if now, Docker will be out of business now). What I'm inclined to do here is to add extra option |
No; that value is inside the manifest and already authenticated by the manifest digest. The point is to match what the user wanted with the image they got. With manifest digest matching, it is impossible to use a RHEL 8.20.1 signature for a RHEL 5.0.0vulnerable image; but without docker reference matching it is still possible to use a RHEL 5.0.0vulnerable image with an old RHEL 5.0.0vulnerable signature, and the user would accept that combination even if they actually wanted a RHEL 8.20.1. |
@mtrmac would it be enough to get the IST based on what the image identity has and check that the IST points to an image with digest matching the signature digest? This will only work for images that has been imported to OpenShift (iow. has IST already created), I don't think this will work for external images where we will have to fetch the manifest. That brings up an interesting question whether we are OK sending user credentials to the IP:PORT contained in the identity (guess that is OK if the signature key is valid? ;-) |
Verified to be what? The ISV producing the image will not have an individual public key for every image (that wouldn’t make sense, in that case managing trust in unsigned images would be just as hard as managing trust in public keys), so necessarily there will be multiple images produced by the same ISV signed by the same key. And then it is insufficient to verify that “this image has been sometime in the past been signed by $ISV”; an overwhelming majority of such images will be old vulnerable versions. Or they may be properly signed images with debugging enabled such that they log highly private data into the logs. The user must know and specify what image they expect to get, and the signature must not only prove that the image came from that ISV, but also that it is the expected identity. When things align well, a registry reference ( Yes, it is sad that the “docker reference” format has no defined semantics and sometimes users care about the total identity up to the tag (
By default, yes. That’s why an image may have multiple signatures. And that’s also why the
No, signature verification is too late for that; by the time signature verification happens, at least the manifest has been fetched (= credentials have already been sent). Not sending credentials for $serverA to $serverB is something which must be implemented in the client, it is not something the signature verification can help with. [ref] For third parties, there is a different concern: the signature will contain the third-party registry hostname (isv.example.com/product:version), so when mirroring the images into a local registry, those signatures will no longer match the path used to fetch them (customer.example.com/isv-mirror/product:version). Again, the
The digest guarantees immutability of the content, i.e. that all images which are fetched using the digest are identical. It does not guarantee identity of the content: just because all nodes on the cluster have exactly the same backdoored image does not make that image safe to use. Or, to put it another way, it is perfectly fine for the user to say Or, yet another way, the signature is a cryptographic assertion that the ISV has, as $identity, published an image with $digest. $digest then allows fetching the whole image and knowing that that’s what the ISV intended, but $identity is what says that $digest is what the user wants.
That really must be the default, at least by the time we start signing RHEL images (hopefully in a few months).
(No, tags in the manifest are irrelevant. User intent is what matters.) |
} | ||
type critical struct { | ||
Image criticalImage `json:"image"` | ||
} |
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.
Any unknown JSON field in critical
, and any subobjects, must cause the signature to be rejected. That's what critical
means in this format.
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.
This is still outstanding.
Sorry, what is an ”IST”? |
IST is ImageStreamTag. See: b73ce56 |
@mtrmac note that above won't work if the ImageStreamTag "test/test:latest" does not exists (eg. it was not imported). Which might be fine for verification. |
return err | ||
} | ||
|
||
if tag.Image.Name != digest { |
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.
This verifies that there exists an image with reference
pointing to digest
. Where is the user intent?
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.
@mtrmac that verifies that the "tag" specified in the critical.identity exists and the image associated with that tag have digest that matches the critical.image.
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.
Yes but that tag value may be anything. How does that protect against the RHEL 8.20.5 vs. 5.0.0vulnerable substitution?
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.
@mtrmac I don't understand what you mean with substitution. How do you substitute that in signature without re-pushing the image again which will result in a different digest and that image, imported in OpenShift will have unverified signature by default.
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.
Pushing an image using a different tag (or repo) does not have to modify the manifest:
- With schema 2, neither the repo nor the tag are in the manifest (it is possible to tag a single image with multiple tags in multiple repos)
- With schema 1, strictly speaking the repo and tag are included in the manifest, so pushing to a different destination would change the manifest, but in practice most implementations (including recent OpenShift versions) completely ignore those fields (which is, overall, good, BTW).
Attack (on b73ce56 ): take an existing old |
@mtrmac if the signature has identity set to "test/vulneable" and you import it is as "test/test", the identity won't match with "test/test" and the verification will fail for that image. |
@mtrmac ok, maybe I understand the attack you mentioned... that means, we have to compare it with the o.InputImage which is the digest you expect the image to have. In that case we just need to match not against digest in signature but against the provided image id (sha256), which match the user intent to verify the image is the one it claims to be. See 85b5b00 |
Maybe I am just being stupid—which code path where does that? It certainly doesn’t happen on image import into the registry, and I couldn't see it in this code either. |
That needs to happen also, but the human does not assign any meaning to a digest. Where did the human get the digest, and how does the human know that the digest is the digest of the ISV-provided image and not a digest of any other backdoored image uploaded by anyone else with write access to the registry? AFAICT, when verifying an image signature, the human must specify the identity, either implicitly:
(pulling that tag, using the digest that tag points to, and verifying that a signature claims a combination of that tag and that digest) or perhaps explicitly
(pulling from (The latter allows you to create an implementation which does not depend on
) |
Excuse me and sorry for my ignorace. I'm getting lost in the discussion above. Can we build up a list of necessarry checks that need to pass in order for trusted condition to be set? If I understand this correctly, from what @mtrmac says, following need to hold true for at least one signature S of image I being verified:
Is that all? Have I forgotten something? On the other hand, here's a list of items that do not matter for the image to be considered trusted (again, please correct me if I'm wrong with an explanation, why?):
I don't quite get the meaning of |
Using the above terminology:
|
40d2a61
to
1dc186d
Compare
73b49ef
to
31418cf
Compare
@mtrmac @miminar @smarterclayton if there are no further objections about this command, I'm going to add some tests. |
} | ||
|
||
cmd.Flags().BoolVar(&opts.Confirm, "confirm", opts.Confirm, "If true, the result of the verification will be recorded to an image object.") | ||
cmd.Flags().BoolVar(&opts.Remove, "remove", opts.Remove, "If set, the current signature verification will be removed from the image.") |
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.
current
is a bit misleading. All signature verification statuses shall be removed, right?
|
||
verifyImageSignatureExample = templates.Examples(` | ||
# Verify the image signature using the public key and record the status as a condition to image | ||
%[1]s sha256:c841e9b64e4579bd56c794bdd7c36e1c257110fd2404bebbb8b613e4935228c4 --public-key=production.gpg --confirm |
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.
Can this include an example of removal?
opts := &VerifyImageSignatureOptions{ErrOut: errOut, Out: out} | ||
cmd := &cobra.Command{ | ||
Use: fmt.Sprintf("%s IMAGE [--confirm]", name), | ||
Short: "Verifies the given IMAGE signature with local public key", |
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 believe this should be Verify that the given IMAGE is signed with a good signature
. And define the good in the long description.
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.
@miminar s/good/trusted/ and I will explain what "trusted" means. ok?
|
||
// If --public-key is provided only this key will be used for verification and the | ||
// .gnupg/pubring.gpg will be ignored. | ||
if len(o.PublicKeyFilename) > 0 { |
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.
verifyImageSignatureLongDesc = templates.LongDesc(` | ||
Verifies the imported image signature using the local public key. | ||
|
||
This command verifies if the signature attached to an image is trusted by |
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'd find it helpful, if this help described what trusted
means.
return err | ||
} | ||
// Verify the tag exists | ||
tag, err := o.Client.ImageStreamTags(ref.Namespace).Get(ref.Name, ref.Tag) |
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 believe the :tag
part is optional in critical.identity.docker-reference
. OTOH it can contain digest instead. @mtrmac, can you please confirm?
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.
References either with a tag or a digest can happen. NameOnly
references should not.
(In principle, an attacker can put anything invalid in there, including empty strings, completely invalid reference formats, NameOnly
references, or references which contain both a tag and a digest.)
fmt.Fprintf(o.ErrOut, "%s identity cannot be verified: %v\n", o.InputImage, identityError) | ||
} | ||
|
||
// If we have error and --confirm then remove the signature from the image which |
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.
Remove the comment or rewrite to match what's happening. (I believe the code says it all).
@@ -73,6 +75,9 @@ func (o *VerifyImageSignatureOptions) Complete(f *clientcmd.Factory, cmd *cobra. | |||
return kcmdutil.UsageError(cmd, "exactly one image must be specified") | |||
} | |||
o.InputImage = args[0] | |||
if len(o.ExpectedIdentity) == 0 { | |||
return kcmdutil.UsageError(cmd, "the --expected-identity must be specified") |
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.
Since it's a required argument, can it be turned into regular positional argument?
Either way, cobra.Command.Use
needs to be updated.
@@ -128,7 +133,7 @@ func (o *VerifyImageSignatureOptions) verifySignature(signature []byte) (string, | |||
|
|||
// verifySignatureContent verifies that the signature content matches the given image. | |||
// TODO: This should be done by calling the 'containers/image' library in future. | |||
func (o *VerifyImageSignatureOptions) verifySignatureContent(content []byte) (string, string, error) { | |||
func (o *VerifyImageSignatureOptions) verifySignatureContent(content []byte) (string, error) { |
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.
Please, describe the returned value.
if signatureContentErr != nil { | ||
fmt.Fprintf(o.ErrOut, "%s signature content cannot be verified: %v\n", o.InputImage, signatureContentErr) | ||
} | ||
|
||
identityError := o.verifyImageIdentity(identity, digest) | ||
identityError := o.verifyImageIdentity(identity) |
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's perfectly fine to have multiple signatures included within an image with different identity references. The way this code is structured, prevents me from having two signatures with good verification status set at the same time, if they have different identity references.
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.
Bump.
31418cf
to
a1cd312
Compare
a1cd312
to
bd5bc5d
Compare
@miminar fixed. |
opts := &VerifyImageSignatureOptions{ErrOut: errOut, Out: out} | ||
cmd := &cobra.Command{ | ||
Use: fmt.Sprintf("%s IMAGE [--confirm]", name), | ||
Short: "Verify that the given IMAGE signature is trusted", |
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.
the given IMAGE is trusted
(signature is not given)
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.
the command is oc adm verify-image-signature
:-)
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 doesn't change the fact the image signature is nowhere given nor specified. It just may be associated with the given image.
Hmm, the name of the command is misleading 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.
OTOH the “has trust been verified” flag is a property of a signature, not of the image.
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 open to any name suggestions for the command :-)
The intent of this command is to verify the signature that is attached to an image is "trusted" (by GPG key) and "valid" (by signature content).
Signature is not specified BUT it has to be present as part of the image you want to verify.
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 is somewhat specified by the expected identity (though that may still match multiple).
Another thing perhaps worth pointing out is that AFAICS the “verify” operation will also automatically unset the verification status for any non-matching signature; i.e. it is impossible to mark two signatures with two different identities as verified at the same time. I don’t really have any suggestion about this, though, and this is perfectly fine with me for the first version.
It kinda seems to me that this command is really oc adm manage-image-signature-verification-status
with --remove
as a possible operation, but that’s impossibly cumbersome to type… I suck at naming.
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.
$ oc adm image-signature verify --identity=XYZ [IMAGE]
$ oc adm image-signature remove [IMAGE]
is this better?
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 seems to suggest that [IMAGE]
should be $IMAGE $SIGNATURE
. Really, I suck at UI and I’ll shut up.
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's good. I'd like even more oc adm image-signature verify [--confirm] IDENTITY IMAGE
but you don't have to spoil me be fulfilling all my tiny wishes 😄
Critical critical `json:"critical"` | ||
} | ||
m := message{} | ||
if err := json.Unmarshal(content, &m); err != 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.
According to @mtrmac, you should first unmarshal into an interface{}
and ensure it doesn't contain any unrecognized fields.
Any unknown JSON field in critical, and any subobjects, must cause the signature to be rejected. That's what critical means in this format.
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.
hrm... ok.
func NewCmdVerifyImageSignature(name, fullName string, f *clientcmd.Factory, out, errOut io.Writer) *cobra.Command { | ||
opts := &VerifyImageSignatureOptions{ErrOut: errOut, Out: out} | ||
cmd := &cobra.Command{ | ||
Use: fmt.Sprintf("%s IMAGE [--confirm]", 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.
Since --expected-identity
is mandatory, it should be listed here. I'd still prefer the expected identity as a positional argument though.
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.
what you mean with positional argument?
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.
oc verify-image-signature EXPECTED_IDENTITY IMAGE [--confirm]
Origin Action Required: Pull request cannot be automatically merged, please rebase your branch from latest HEAD and push again |
Closing in favor of #13585 |
This will allow
image-auditor
role to verify the image signatures (for images that were pushing usingskopeo
oratomic push
) using local GPG keys.Note that this is just to provide the information about whether the signature content is valid or not. It does not indicate whether the image is valid or not to be scheduled on node (it is node job to revoke running image with invalid signature when policy.json does not allow the signature itself).
The command has following syntax:
The
--confirm
flag indicates whether the Image object on the server should be updated to reflect the current verification state.To remove the signature verification you can use:
In both cases the "user" have to be at least "image-auditor" (@smarterclayton I don't think we need to add 'image-admin' role as the auditor seems pretty accurate and already exists?).
In addition, the describer for image is updated to show signature verification status (if image has signature) example: https://gist.github.com/mfojtik/834f51f92672f70885d1c0a724aa2d2a