@@ -31,13 +31,14 @@ var (
31
31
` )
32
32
33
33
verifyImageSignatureExample = templates .Examples (`
34
- # Verify the image signature using the public key and record the status as a condition to image
35
- %[1]s sha256:c841e9b64e4579bd56c794bdd7c36e1c257110fd2404bebbb8b613e4935228c4 --public-key=production.gpg --confirm
34
+ # Verify the image signature using the local GNUPG keychan and record the status as a condition to image
35
+ %[1]s sha256:c841e9b64e4579bd56c794bdd7c36e1c257110fd2404bebbb8b613e4935228c4 --expected-identity=registry.local:5000/foo/bar:v1
36
36
` )
37
37
)
38
38
39
39
type VerifyImageSignatureOptions struct {
40
40
InputImage string
41
+ ExpectedIdentity string
41
42
PublicKeyFilename string
42
43
PublicKey []byte
43
44
Confirm bool
@@ -65,6 +66,7 @@ func NewCmdVerifyImageSignature(name, fullName string, f *clientcmd.Factory, out
65
66
cmd .Flags ().BoolVar (& opts .Confirm , "confirm" , opts .Confirm , "If true, the result of the verification will be recorded to an image object." )
66
67
cmd .Flags ().BoolVar (& opts .Remove , "remove" , opts .Remove , "If set, the current signature verification will be removed from the image." )
67
68
cmd .Flags ().StringVar (& opts .PublicKeyFilename , "public-key" , opts .PublicKeyFilename , "A path to a public GPG key to be used for verification." )
69
+ cmd .Flags ().StringVar (& opts .ExpectedIdentity , "expected-identity" , opts .ExpectedIdentity , "An expected image docker reference to verify." )
68
70
return cmd
69
71
}
70
72
@@ -73,6 +75,9 @@ func (o *VerifyImageSignatureOptions) Complete(f *clientcmd.Factory, cmd *cobra.
73
75
return kcmdutil .UsageError (cmd , "exactly one image must be specified" )
74
76
}
75
77
o .InputImage = args [0 ]
78
+ if len (o .ExpectedIdentity ) == 0 {
79
+ return kcmdutil .UsageError (cmd , "the --expected-identity must be specified" )
80
+ }
76
81
var err error
77
82
78
83
// 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,
128
133
129
134
// verifySignatureContent verifies that the signature content matches the given image.
130
135
// TODO: This should be done by calling the 'containers/image' library in future.
131
- func (o * VerifyImageSignatureOptions ) verifySignatureContent (content []byte ) (string , string , error ) {
136
+ func (o * VerifyImageSignatureOptions ) verifySignatureContent (content []byte ) (string , error ) {
132
137
// TODO: The types here are just to decompose the JSON. The fields should not change but
133
138
// we need to use containers/image library here to guarantee compatibility in future.
134
139
type criticalImage struct {
@@ -146,31 +151,20 @@ func (o *VerifyImageSignatureOptions) verifySignatureContent(content []byte) (st
146
151
}
147
152
m := message {}
148
153
if err := json .Unmarshal (content , & m ); err != nil {
149
- return "" , "" , err
154
+ return "" , err
150
155
}
151
156
if o .InputImage != m .Critical .Image .Digest {
152
- return "" , "" , fmt .Errorf ("signature is valid for digest %q not for %q" , m .Critical .Image .Digest , o .InputImage )
157
+ return "" , fmt .Errorf ("signature is valid for digest %q not for %q" , m .Critical .Image .Digest , o .InputImage )
153
158
}
154
- return m .Critical .Image . Digest , m . Critical . Identity .DockerReference , nil
159
+ return m .Critical .Identity .DockerReference , nil
155
160
}
156
161
157
162
// verifyImageIdentity verifies the source of the image specified in the signature is
158
163
// valid.
159
- func (o * VerifyImageSignatureOptions ) verifyImageIdentity (reference , digest string ) error {
160
- ref , err := imageapi .ParseDockerImageReference (reference )
161
- if err != nil {
162
- return err
164
+ func (o * VerifyImageSignatureOptions ) verifyImageIdentity (reference string ) error {
165
+ if reference != o .ExpectedIdentity {
166
+ return fmt .Errorf ("signature identity %q does not match expected image identity %q" , reference , o .ExpectedIdentity )
163
167
}
164
- // Verify the tag exists
165
- tag , err := o .Client .ImageStreamTags (ref .Namespace ).Get (ref .Name , ref .Tag )
166
- if err != nil {
167
- return err
168
- }
169
-
170
- if tag .Image .Name != o .InputImage {
171
- return fmt .Errorf ("signature identity %q does not match image %q" , reference , tag .Image .Name )
172
- }
173
-
174
168
return nil
175
169
}
176
170
@@ -207,12 +201,12 @@ func (o *VerifyImageSignatureOptions) Run() error {
207
201
}
208
202
209
203
// Verify the signed message content matches with the provided image id
210
- digest , identity , signatureContentErr := o .verifySignatureContent (content )
204
+ identity , signatureContentErr := o .verifySignatureContent (content )
211
205
if signatureContentErr != nil {
212
206
fmt .Fprintf (o .ErrOut , "%s signature content cannot be verified: %v\n " , o .InputImage , signatureContentErr )
213
207
}
214
208
215
- identityError := o .verifyImageIdentity (identity , digest )
209
+ identityError := o .verifyImageIdentity (identity )
216
210
if identityError != nil {
217
211
fmt .Fprintf (o .ErrOut , "%s identity cannot be verified: %v\n " , o .InputImage , identityError )
218
212
}
0 commit comments