diff --git a/pkg/cmd/admin/image/verify-signature.go b/pkg/cmd/admin/image/verify-signature.go index ef074c04a935..aae9f3693a47 100644 --- a/pkg/cmd/admin/image/verify-signature.go +++ b/pkg/cmd/admin/image/verify-signature.go @@ -31,13 +31,14 @@ var ( `) 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 + # Verify the image signature using the local GNUPG keychan and record the status as a condition to image + %[1]s sha256:c841e9b64e4579bd56c794bdd7c36e1c257110fd2404bebbb8b613e4935228c4 --expected-identity=registry.local:5000/foo/bar:v1 `) ) type VerifyImageSignatureOptions struct { InputImage string + ExpectedIdentity string PublicKeyFilename string PublicKey []byte Confirm bool @@ -65,6 +66,7 @@ func NewCmdVerifyImageSignature(name, fullName string, f *clientcmd.Factory, out 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.") cmd.Flags().StringVar(&opts.PublicKeyFilename, "public-key", opts.PublicKeyFilename, "A path to a public GPG key to be used for verification.") + cmd.Flags().StringVar(&opts.ExpectedIdentity, "expected-identity", opts.ExpectedIdentity, "An expected image docker reference to verify.") return cmd } @@ -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") + } var err error // If --public-key is provided only this key will be used for verification and the @@ -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) { // TODO: The types here are just to decompose the JSON. The fields should not change but // we need to use containers/image library here to guarantee compatibility in future. type criticalImage struct { @@ -146,31 +151,20 @@ func (o *VerifyImageSignatureOptions) verifySignatureContent(content []byte) (st } m := message{} if err := json.Unmarshal(content, &m); err != nil { - return "", "", err + return "", err } if o.InputImage != m.Critical.Image.Digest { - return "", "", fmt.Errorf("signature is valid for digest %q not for %q", m.Critical.Image.Digest, o.InputImage) + return "", fmt.Errorf("signature is valid for digest %q not for %q", m.Critical.Image.Digest, o.InputImage) } - return m.Critical.Image.Digest, m.Critical.Identity.DockerReference, nil + return m.Critical.Identity.DockerReference, nil } // verifyImageIdentity verifies the source of the image specified in the signature is // valid. -func (o *VerifyImageSignatureOptions) verifyImageIdentity(reference, digest string) error { - ref, err := imageapi.ParseDockerImageReference(reference) - if err != nil { - return err +func (o *VerifyImageSignatureOptions) verifyImageIdentity(reference string) error { + if reference != o.ExpectedIdentity { + return fmt.Errorf("signature identity %q does not match expected image identity %q", reference, o.ExpectedIdentity) } - // Verify the tag exists - tag, err := o.Client.ImageStreamTags(ref.Namespace).Get(ref.Name, ref.Tag) - if err != nil { - return err - } - - if tag.Image.Name != o.InputImage { - return fmt.Errorf("signature identity %q does not match image %q", reference, tag.Image.Name) - } - return nil } @@ -207,12 +201,12 @@ func (o *VerifyImageSignatureOptions) Run() error { } // Verify the signed message content matches with the provided image id - digest, identity, signatureContentErr := o.verifySignatureContent(content) + identity, signatureContentErr := o.verifySignatureContent(content) 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) if identityError != nil { fmt.Fprintf(o.ErrOut, "%s identity cannot be verified: %v\n", o.InputImage, identityError) }