mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-28 18:38:40 +00:00
[ImageVerify] Verify additional certificate-extensions (#3404)
* feat: add additionalExtensions to keyless imageVerify Signed-off-by: Christian Kotzbauer <git@ckotzbauer.de> * feat: regenerate code Signed-off-by: Christian Kotzbauer <git@ckotzbauer.de>
This commit is contained in:
parent
b0860ba177
commit
860253d6aa
10 changed files with 172 additions and 8 deletions
|
@ -23,6 +23,9 @@ type ImageVerification struct {
|
|||
// Issuer is the certificate issuer used for keyless signing.
|
||||
Issuer string `json:"issuer,omitempty" yaml:"issuer,omitempty"`
|
||||
|
||||
// AdditionalExtensions are certificate-extensions used for keyless signing.
|
||||
AdditionalExtensions map[string]string `json:"additionalExtensions,omitempty" yaml:"additionalExtensions,omitempty"`
|
||||
|
||||
// Annotations are used for image verification.
|
||||
// Every specified key-value pair must exist and match in the verified payload.
|
||||
// The payload may contain other key-value pairs.
|
||||
|
|
|
@ -568,6 +568,13 @@ func (in *ImageRegistry) DeepCopy() *ImageRegistry {
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ImageVerification) DeepCopyInto(out *ImageVerification) {
|
||||
*out = *in
|
||||
if in.AdditionalExtensions != nil {
|
||||
in, out := &in.AdditionalExtensions, &out.AdditionalExtensions
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.Annotations != nil {
|
||||
in, out := &in.Annotations, &out.Annotations
|
||||
*out = make(map[string]string, len(*in))
|
||||
|
|
|
@ -1215,6 +1215,11 @@ spec:
|
|||
items:
|
||||
description: ImageVerification validates that images that match the specified pattern are signed with the supplied public key. Once the image is verified it is mutated to include the SHA digest retrieved during the registration.
|
||||
properties:
|
||||
additionalExtensions:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: AdditionalExtensions are certificate-extensions used for keyless signing.
|
||||
type: object
|
||||
annotations:
|
||||
additionalProperties:
|
||||
type: string
|
||||
|
@ -2530,6 +2535,11 @@ spec:
|
|||
items:
|
||||
description: ImageVerification validates that images that match the specified pattern are signed with the supplied public key. Once the image is verified it is mutated to include the SHA digest retrieved during the registration.
|
||||
properties:
|
||||
additionalExtensions:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: AdditionalExtensions are certificate-extensions used for keyless signing.
|
||||
type: object
|
||||
annotations:
|
||||
additionalProperties:
|
||||
type: string
|
||||
|
@ -5041,6 +5051,11 @@ spec:
|
|||
items:
|
||||
description: ImageVerification validates that images that match the specified pattern are signed with the supplied public key. Once the image is verified it is mutated to include the SHA digest retrieved during the registration.
|
||||
properties:
|
||||
additionalExtensions:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: AdditionalExtensions are certificate-extensions used for keyless signing.
|
||||
type: object
|
||||
annotations:
|
||||
additionalProperties:
|
||||
type: string
|
||||
|
@ -6356,6 +6371,11 @@ spec:
|
|||
items:
|
||||
description: ImageVerification validates that images that match the specified pattern are signed with the supplied public key. Once the image is verified it is mutated to include the SHA digest retrieved during the registration.
|
||||
properties:
|
||||
additionalExtensions:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: AdditionalExtensions are certificate-extensions used for keyless signing.
|
||||
type: object
|
||||
annotations:
|
||||
additionalProperties:
|
||||
type: string
|
||||
|
|
|
@ -1943,6 +1943,12 @@ spec:
|
|||
public key. Once the image is verified it is mutated to
|
||||
include the SHA digest retrieved during the registration.
|
||||
properties:
|
||||
additionalExtensions:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: AdditionalExtensions are certificate-extensions
|
||||
used for keyless signing.
|
||||
type: object
|
||||
annotations:
|
||||
additionalProperties:
|
||||
type: string
|
||||
|
@ -4057,6 +4063,12 @@ spec:
|
|||
public key. Once the image is verified it is mutated to
|
||||
include the SHA digest retrieved during the registration.
|
||||
properties:
|
||||
additionalExtensions:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: AdditionalExtensions are certificate-extensions
|
||||
used for keyless signing.
|
||||
type: object
|
||||
annotations:
|
||||
additionalProperties:
|
||||
type: string
|
||||
|
|
|
@ -1944,6 +1944,12 @@ spec:
|
|||
public key. Once the image is verified it is mutated to
|
||||
include the SHA digest retrieved during the registration.
|
||||
properties:
|
||||
additionalExtensions:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: AdditionalExtensions are certificate-extensions
|
||||
used for keyless signing.
|
||||
type: object
|
||||
annotations:
|
||||
additionalProperties:
|
||||
type: string
|
||||
|
@ -4059,6 +4065,12 @@ spec:
|
|||
public key. Once the image is verified it is mutated to
|
||||
include the SHA digest retrieved during the registration.
|
||||
properties:
|
||||
additionalExtensions:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: AdditionalExtensions are certificate-extensions
|
||||
used for keyless signing.
|
||||
type: object
|
||||
annotations:
|
||||
additionalProperties:
|
||||
type: string
|
||||
|
|
|
@ -1959,6 +1959,12 @@ spec:
|
|||
public key. Once the image is verified it is mutated to
|
||||
include the SHA digest retrieved during the registration.
|
||||
properties:
|
||||
additionalExtensions:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: AdditionalExtensions are certificate-extensions
|
||||
used for keyless signing.
|
||||
type: object
|
||||
annotations:
|
||||
additionalProperties:
|
||||
type: string
|
||||
|
@ -4073,6 +4079,12 @@ spec:
|
|||
public key. Once the image is verified it is mutated to
|
||||
include the SHA digest retrieved during the registration.
|
||||
properties:
|
||||
additionalExtensions:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: AdditionalExtensions are certificate-extensions
|
||||
used for keyless signing.
|
||||
type: object
|
||||
annotations:
|
||||
additionalProperties:
|
||||
type: string
|
||||
|
@ -7771,6 +7783,12 @@ spec:
|
|||
public key. Once the image is verified it is mutated to
|
||||
include the SHA digest retrieved during the registration.
|
||||
properties:
|
||||
additionalExtensions:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: AdditionalExtensions are certificate-extensions
|
||||
used for keyless signing.
|
||||
type: object
|
||||
annotations:
|
||||
additionalProperties:
|
||||
type: string
|
||||
|
@ -9886,6 +9904,12 @@ spec:
|
|||
public key. Once the image is verified it is mutated to
|
||||
include the SHA digest retrieved during the registration.
|
||||
properties:
|
||||
additionalExtensions:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: AdditionalExtensions are certificate-extensions
|
||||
used for keyless signing.
|
||||
type: object
|
||||
annotations:
|
||||
additionalProperties:
|
||||
type: string
|
||||
|
|
|
@ -1948,6 +1948,12 @@ spec:
|
|||
public key. Once the image is verified it is mutated to
|
||||
include the SHA digest retrieved during the registration.
|
||||
properties:
|
||||
additionalExtensions:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: AdditionalExtensions are certificate-extensions
|
||||
used for keyless signing.
|
||||
type: object
|
||||
annotations:
|
||||
additionalProperties:
|
||||
type: string
|
||||
|
@ -4062,6 +4068,12 @@ spec:
|
|||
public key. Once the image is verified it is mutated to
|
||||
include the SHA digest retrieved during the registration.
|
||||
properties:
|
||||
additionalExtensions:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: AdditionalExtensions are certificate-extensions
|
||||
used for keyless signing.
|
||||
type: object
|
||||
annotations:
|
||||
additionalProperties:
|
||||
type: string
|
||||
|
@ -7736,6 +7748,12 @@ spec:
|
|||
public key. Once the image is verified it is mutated to
|
||||
include the SHA digest retrieved during the registration.
|
||||
properties:
|
||||
additionalExtensions:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: AdditionalExtensions are certificate-extensions
|
||||
used for keyless signing.
|
||||
type: object
|
||||
annotations:
|
||||
additionalProperties:
|
||||
type: string
|
||||
|
@ -9851,6 +9869,12 @@ spec:
|
|||
public key. Once the image is verified it is mutated to
|
||||
include the SHA digest retrieved during the registration.
|
||||
properties:
|
||||
additionalExtensions:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: AdditionalExtensions are certificate-extensions
|
||||
used for keyless signing.
|
||||
type: object
|
||||
annotations:
|
||||
additionalProperties:
|
||||
type: string
|
||||
|
|
|
@ -1456,6 +1456,17 @@ string
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>additionalExtensions</code></br>
|
||||
<em>
|
||||
map[string]string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>AdditionalExtensions are certificate-extensions used for keyless signing.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>annotations</code></br>
|
||||
<em>
|
||||
map[string]string
|
||||
|
|
|
@ -38,14 +38,15 @@ import (
|
|||
var ImageSignatureRepository string
|
||||
|
||||
type Options struct {
|
||||
ImageRef string
|
||||
Key string
|
||||
Roots []byte
|
||||
Subject string
|
||||
Issuer string
|
||||
Annotations map[string]string
|
||||
Repository string
|
||||
Log logr.Logger
|
||||
ImageRef string
|
||||
Key string
|
||||
Roots []byte
|
||||
Subject string
|
||||
Issuer string
|
||||
AdditionalExtensions map[string]string
|
||||
Annotations map[string]string
|
||||
Repository string
|
||||
Log logr.Logger
|
||||
}
|
||||
|
||||
// VerifySignature verifies that the image has the expected key
|
||||
|
@ -120,6 +121,10 @@ func VerifySignature(opts Options) (digest string, err error) {
|
|||
return "", err
|
||||
}
|
||||
|
||||
if err := matchExtensions(signatures, opts.AdditionalExtensions, log); err != nil {
|
||||
return "", errors.Wrap(err, "extensions mismatch")
|
||||
}
|
||||
|
||||
err = checkAnnotations(pld, opts.Annotations)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "annotation mismatch")
|
||||
|
@ -378,6 +383,48 @@ func matchSubjectAndIssuer(signatures []oci.Signature, subject, issuer string) e
|
|||
return fmt.Errorf("subject mismatch: expected %s, got %s", s, subject)
|
||||
}
|
||||
|
||||
func matchExtensions(signatures []oci.Signature, requiredExtensions map[string]string, log logr.Logger) error {
|
||||
if len(requiredExtensions) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, sig := range signatures {
|
||||
cert, err := sig.Cert()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to read certificate")
|
||||
}
|
||||
|
||||
if cert == nil {
|
||||
return errors.Wrap(err, "certificate not found")
|
||||
}
|
||||
|
||||
// This will return a map which consists of readable extension-names as keys
|
||||
// or the raw extensionIDs as fallback and its values.
|
||||
certExtensions := sigs.CertExtensions(cert)
|
||||
for requiredKey, requiredValue := range requiredExtensions {
|
||||
certValue, ok := certExtensions[requiredKey]
|
||||
if !ok {
|
||||
// "requiredKey" seems to be an extensionID, try to resolve its human readable name
|
||||
readableName, ok := sigs.CertExtensionMap[requiredKey]
|
||||
if !ok {
|
||||
return fmt.Errorf("key %s not present", requiredKey)
|
||||
}
|
||||
|
||||
certValue, ok = certExtensions[readableName]
|
||||
if !ok {
|
||||
return fmt.Errorf("key %s (%s) not present", requiredKey, readableName)
|
||||
}
|
||||
}
|
||||
|
||||
if requiredValue != "" && !wildcard.Match(requiredValue, certValue) {
|
||||
return fmt.Errorf("extension mismatch: expected %s for key %s, got %s", requiredValue, requiredKey, certValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkAnnotations(payload []payload.SimpleContainerImage, annotations map[string]string) error {
|
||||
for _, p := range payload {
|
||||
for key, val := range annotations {
|
||||
|
|
|
@ -195,6 +195,10 @@ func (iv *imageVerifier) verifySignature(imageVerify *v1.ImageVerification, imag
|
|||
opts.Subject = imageVerify.Subject
|
||||
}
|
||||
|
||||
if imageVerify.AdditionalExtensions != nil {
|
||||
opts.AdditionalExtensions = imageVerify.AdditionalExtensions
|
||||
}
|
||||
|
||||
if imageVerify.Annotations != nil {
|
||||
opts.Annotations = imageVerify.Annotations
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue