Skip to content

Commit

Permalink
add --expected-identity parameter
Browse files Browse the repository at this point in the history
  • Loading branch information
mfojtik committed Jan 27, 2017
1 parent e9cc14f commit 1dc186d
Showing 1 changed file with 16 additions and 22 deletions.
38 changes: 16 additions & 22 deletions pkg/cmd/admin/image/verify-signature.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}

Expand 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")
}
var err error

// If --public-key is provided only this key will be used for verification and the
Expand Down Expand Up @@ -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 {
Expand All @@ -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
}

Expand Down Expand Up @@ -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)
}
Expand Down

0 comments on commit 1dc186d

Please sign in to comment.