1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-04-09 02:29:22 +00:00

Multiple keys (#3636)

* fix autogen check

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* allow multiple keys and fix root/intermediate certs

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* fix test

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* make issuer/subject optional

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* enable CTLog options

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* fix split

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* make fmt

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* make codegen

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* rename CTLog -> Rekor

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* make fmt

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* api/kyverno/v1/image_verification_test.go

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* fix tests

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

Co-authored-by: Vyankatesh Kudtarkar <vyankateshkd@gmail.com>
This commit is contained in:
Jim Bugwadia 2022-04-22 00:10:02 -07:00 committed by GitHub
parent 78a6f20572
commit 9fde4fd6a1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 594 additions and 109 deletions

View file

@ -28,7 +28,6 @@ func Test_ImageVerification(t *testing.T) {
errors: func(i *ImageVerification) field.ErrorList {
return field.ErrorList{
field.Invalid(path, i, "Either a static key, keyless, or an attestor is required"),
field.Invalid(path, i, "An issuer and a subject are required for keyless verification"),
}
},
}, {
@ -150,7 +149,7 @@ func Test_ImageVerification(t *testing.T) {
ImageReferences: []string{"*"},
Attestors: []*AttestorSet{
{Entries: []*Attestor{{
StaticKey: &StaticKeyAttestor{Key: "bla"},
StaticKey: &StaticKeyAttestor{Keys: "bla"},
}}},
},
},
@ -161,16 +160,14 @@ func Test_ImageVerification(t *testing.T) {
ImageReferences: []string{"*"},
Attestors: []*AttestorSet{
{Entries: []*Attestor{{
Keyless: &KeylessAttestor{Issuer: "", Subject: ""},
Keyless: &KeylessAttestor{Rekor: &CTLog{}, Issuer: "", Subject: ""},
}}},
},
},
errors: func(i *ImageVerification) field.ErrorList {
return field.ErrorList{
field.Invalid(path.Child("attestors").Index(0).Child("entries").Index(0).Child("keyless"),
i.Attestors[0].Entries[0].Keyless, "An issuer is required"),
field.Invalid(path.Child("attestors").Index(0).Child("entries").Index(0).Child("keyless"),
i.Attestors[0].Entries[0].Keyless, "A subject is required"),
i.Attestors[0].Entries[0].Keyless, "An URL is required"),
}
},
},
@ -180,7 +177,7 @@ func Test_ImageVerification(t *testing.T) {
ImageReferences: []string{"*"},
Attestors: []*AttestorSet{
{Entries: []*Attestor{{
Keyless: &KeylessAttestor{Issuer: "bla", Subject: "bla"},
Keyless: &KeylessAttestor{Rekor: &CTLog{URL: "https://rekor.sigstore.dev"}, Issuer: "bla", Subject: "bla"},
}}},
},
},

View file

@ -109,10 +109,12 @@ type Attestor struct {
type StaticKeyAttestor struct {
// Key is an X.509 public key used to verify image signatures. The key can be directly
// Keys is a set of X.509 public keys used to verify image signatures. The keys can be directly
// specified or can be a variable reference to a key specified in a ConfigMap (see
// https://kyverno.io/docs/writing-policies/variables/).
Key string `json:"key,omitempty" yaml:"key,omitempty"`
// https://kyverno.io/docs/writing-policies/variables/). When multiple keys are specified each
// key is processed as a separate staticKey entry (.attestors[*].entries.staticKey) within the set of
// attestors and the count is applied across the keys.
Keys string `json:"key,omitempty" yaml:"key,omitempty"`
// Intermediates is an optional PEM encoded set of certificates that are not trust
// anchors, but can be used to form a chain from the leaf certificate to a
@ -128,12 +130,18 @@ type StaticKeyAttestor struct {
type KeylessAttestor struct {
// Rekor provides information of the Rekor transparency log service. If the value is nil,
// Rekor is not checked and a root certificate chain is expected instead. If an empty object
// is provided the public instance of Rekor (https://rekor.sigstore.dev) is used.
// +kubebuilder:validation:Optional
Rekor *CTLog `json:"rekor,omitempty" yaml:"rekor,omitempty"`
// Issuer is the certificate issuer used for keyless signing.
// +kubebuilder:validation:Required
// +kubebuilder:validation:Optional
Issuer string `json:"issuer,omitempty" yaml:"issuer,omitempty"`
// Subject is the verified identity used for keyless signing, for example the email address
// +kubebuilder:validation:Required
// +kubebuilder:validation:Optional
Subject string `json:"subject,omitempty" yaml:"subject,omitempty"`
// Intermediates is an optional PEM encoded set of certificates that are not trust
@ -152,6 +160,13 @@ type KeylessAttestor struct {
AdditionalExtensions map[string]string `json:"additionalExtensions,omitempty" yaml:"additionalExtensions,omitempty"`
}
type CTLog struct {
// URL is the address of the transparency log. Defaults to the public log https://rekor.sigstore.dev.
// +kubebuilder:validation:Required
// +kubebuilder:Default:=https://rekor.sigstore.dev
URL string `json:"url" yaml:"url"`
}
// Attestation are checks for signed in-toto Statements that are used to verify the image.
// See https://github.com/in-toto/attestation. Kyverno fetches signed attestations from the
// OCI registry and decodes them into a list of Statements.
@ -186,10 +201,6 @@ func (iv *ImageVerification) Validate(path *field.Path) (errs field.ErrorList) {
errs = append(errs, field.Invalid(path, iv, "Either a static key, keyless, or an attestor is required"))
}
if hasKeyless && (!hasIssuer || !hasSubject) {
errs = append(errs, field.Invalid(path, iv, "An issuer and a subject are required for keyless verification"))
}
if len(iv.Attestors) > 1 {
errs = append(errs, field.Invalid(path, iv, "Only one attestor is currently supported"))
}
@ -274,7 +285,7 @@ func AttestorSetUnmarshal(o *apiextv1.JSON) (*AttestorSet, error) {
}
func (ska *StaticKeyAttestor) Validate(path *field.Path) (errs field.ErrorList) {
if ska.Key == "" {
if ska.Keys == "" {
errs = append(errs, field.Invalid(path, ska, "A key is required"))
}
@ -282,12 +293,12 @@ func (ska *StaticKeyAttestor) Validate(path *field.Path) (errs field.ErrorList)
}
func (ka *KeylessAttestor) Validate(path *field.Path) (errs field.ErrorList) {
if ka.Issuer == "" {
errs = append(errs, field.Invalid(path, ka, "An issuer is required"))
if ka.Rekor == nil && ka.Roots == "" {
errs = append(errs, field.Invalid(path, ka, "Either Rekor URL or roots are required"))
}
if ka.Subject == "" {
errs = append(errs, field.Invalid(path, ka, "A subject is required"))
if ka.Rekor != nil && ka.Rekor.URL == "" {
errs = append(errs, field.Invalid(path, ka, "An URL is required"))
}
return errs
@ -311,7 +322,7 @@ func (iv *ImageVerification) Convert() *ImageVerification {
if iv.Key != "" {
attestor.StaticKey = &StaticKeyAttestor{
Key: iv.Key,
Keys: iv.Key,
}
} else if iv.Issuer != "" {
attestor.Keyless = &KeylessAttestor{

View file

@ -210,6 +210,21 @@ func (in *AutogenStatus) DeepCopy() *AutogenStatus {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CTLog) DeepCopyInto(out *CTLog) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CTLog.
func (in *CTLog) DeepCopy() *CTLog {
if in == nil {
return nil
}
out := new(CTLog)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CloneFrom) DeepCopyInto(out *CloneFrom) {
*out = *in
@ -662,6 +677,11 @@ func (in *ImageVerification) DeepCopy() *ImageVerification {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KeylessAttestor) DeepCopyInto(out *KeylessAttestor) {
*out = *in
if in.Rekor != nil {
in, out := &in.Rekor, &out.Rekor
*out = new(CTLog)
**out = **in
}
if in.AdditionalExtensions != nil {
in, out := &in.AdditionalExtensions, &out.AdditionalExtensions
*out = make(map[string]string, len(*in))

View file

@ -1364,6 +1364,15 @@ spec:
issuer:
description: Issuer is the certificate issuer used for keyless signing.
type: string
rekor:
description: Rekor provides information of the Rekor transparency log service. If the value is nil, Rekor is not checked and a root certificate chain is expected instead. If an empty object is provided the public instance of Rekor (https://rekor.sigstore.dev) is used.
properties:
url:
description: URL is the address of the transparency log. Defaults to the public log https://rekor.sigstore.dev.
type: string
required:
- url
type: object
roots:
description: Roots is an optional set of PEM encoded trusted root certificates. If not provided, the system roots are used.
type: string
@ -1381,7 +1390,7 @@ spec:
description: Intermediates is an optional PEM encoded set of certificates that are not trust anchors, but can be used to form a chain from the leaf certificate to a root certificate.
type: string
key:
description: Key is an X.509 public key used to verify image signatures. The key can be directly specified or can be a variable reference to a key specified in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/).
description: Keys is a set of X.509 public keys used to verify image signatures. The keys can be directly specified or can be a variable reference to a key specified in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/). When multiple keys are specified each key is processed as a separate staticKey entry (.attestors[*].entries.staticKey) within the set of attestors and the count is applied across the keys.
type: string
roots:
description: Roots is an optional set of PEM encoded trusted root certificates. If not provided, the system roots are used.
@ -2817,6 +2826,15 @@ spec:
issuer:
description: Issuer is the certificate issuer used for keyless signing.
type: string
rekor:
description: Rekor provides information of the Rekor transparency log service. If the value is nil, Rekor is not checked and a root certificate chain is expected instead. If an empty object is provided the public instance of Rekor (https://rekor.sigstore.dev) is used.
properties:
url:
description: URL is the address of the transparency log. Defaults to the public log https://rekor.sigstore.dev.
type: string
required:
- url
type: object
roots:
description: Roots is an optional set of PEM encoded trusted root certificates. If not provided, the system roots are used.
type: string
@ -2834,7 +2852,7 @@ spec:
description: Intermediates is an optional PEM encoded set of certificates that are not trust anchors, but can be used to form a chain from the leaf certificate to a root certificate.
type: string
key:
description: Key is an X.509 public key used to verify image signatures. The key can be directly specified or can be a variable reference to a key specified in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/).
description: Keys is a set of X.509 public keys used to verify image signatures. The keys can be directly specified or can be a variable reference to a key specified in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/). When multiple keys are specified each key is processed as a separate staticKey entry (.attestors[*].entries.staticKey) within the set of attestors and the count is applied across the keys.
type: string
roots:
description: Roots is an optional set of PEM encoded trusted root certificates. If not provided, the system roots are used.
@ -4979,6 +4997,15 @@ spec:
issuer:
description: Issuer is the certificate issuer used for keyless signing.
type: string
rekor:
description: Rekor provides information of the Rekor transparency log service. If the value is nil, Rekor is not checked and a root certificate chain is expected instead. If an empty object is provided the public instance of Rekor (https://rekor.sigstore.dev) is used.
properties:
url:
description: URL is the address of the transparency log. Defaults to the public log https://rekor.sigstore.dev.
type: string
required:
- url
type: object
roots:
description: Roots is an optional set of PEM encoded trusted root certificates. If not provided, the system roots are used.
type: string
@ -4996,7 +5023,7 @@ spec:
description: Intermediates is an optional PEM encoded set of certificates that are not trust anchors, but can be used to form a chain from the leaf certificate to a root certificate.
type: string
key:
description: Key is an X.509 public key used to verify image signatures. The key can be directly specified or can be a variable reference to a key specified in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/).
description: Keys is a set of X.509 public keys used to verify image signatures. The keys can be directly specified or can be a variable reference to a key specified in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/). When multiple keys are specified each key is processed as a separate staticKey entry (.attestors[*].entries.staticKey) within the set of attestors and the count is applied across the keys.
type: string
roots:
description: Roots is an optional set of PEM encoded trusted root certificates. If not provided, the system roots are used.
@ -6432,6 +6459,15 @@ spec:
issuer:
description: Issuer is the certificate issuer used for keyless signing.
type: string
rekor:
description: Rekor provides information of the Rekor transparency log service. If the value is nil, Rekor is not checked and a root certificate chain is expected instead. If an empty object is provided the public instance of Rekor (https://rekor.sigstore.dev) is used.
properties:
url:
description: URL is the address of the transparency log. Defaults to the public log https://rekor.sigstore.dev.
type: string
required:
- url
type: object
roots:
description: Roots is an optional set of PEM encoded trusted root certificates. If not provided, the system roots are used.
type: string
@ -6449,7 +6485,7 @@ spec:
description: Intermediates is an optional PEM encoded set of certificates that are not trust anchors, but can be used to form a chain from the leaf certificate to a root certificate.
type: string
key:
description: Key is an X.509 public key used to verify image signatures. The key can be directly specified or can be a variable reference to a key specified in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/).
description: Keys is a set of X.509 public keys used to verify image signatures. The keys can be directly specified or can be a variable reference to a key specified in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/). When multiple keys are specified each key is processed as a separate staticKey entry (.attestors[*].entries.staticKey) within the set of attestors and the count is applied across the keys.
type: string
roots:
description: Roots is an optional set of PEM encoded trusted root certificates. If not provided, the system roots are used.

View file

@ -2185,6 +2185,23 @@ spec:
description: Issuer is the certificate
issuer used for keyless signing.
type: string
rekor:
description: Rekor provides information
of the Rekor transparency log service.
If the value is nil, Rekor is not checked
and a root certificate chain is expected
instead. If an empty object is provided
the public instance of Rekor (https://rekor.sigstore.dev)
is used.
properties:
url:
description: URL is the address of
the transparency log. Defaults to
the public log https://rekor.sigstore.dev.
type: string
required:
- url
type: object
roots:
description: Roots is an optional set
of PEM encoded trusted root certificates.
@ -2216,11 +2233,16 @@ spec:
to a root certificate.
type: string
key:
description: Key is an X.509 public key
used to verify image signatures. The
key can be directly specified or can
be a variable reference to a key specified
in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/).
description: Keys is a set of X.509 public
keys used to verify image signatures.
The keys can be directly specified or
can be a variable reference to a key
specified in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/).
When multiple keys are specified each
key is processed as a separate staticKey
entry (.attestors[*].entries.staticKey)
within the set of attestors and the
count is applied across the keys.
type: string
roots:
description: Roots is an optional set
@ -4536,6 +4558,23 @@ spec:
description: Issuer is the certificate
issuer used for keyless signing.
type: string
rekor:
description: Rekor provides information
of the Rekor transparency log service.
If the value is nil, Rekor is not checked
and a root certificate chain is expected
instead. If an empty object is provided
the public instance of Rekor (https://rekor.sigstore.dev)
is used.
properties:
url:
description: URL is the address of
the transparency log. Defaults to
the public log https://rekor.sigstore.dev.
type: string
required:
- url
type: object
roots:
description: Roots is an optional set
of PEM encoded trusted root certificates.
@ -4567,11 +4606,16 @@ spec:
to a root certificate.
type: string
key:
description: Key is an X.509 public key
used to verify image signatures. The
key can be directly specified or can
be a variable reference to a key specified
in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/).
description: Keys is a set of X.509 public
keys used to verify image signatures.
The keys can be directly specified or
can be a variable reference to a key
specified in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/).
When multiple keys are specified each
key is processed as a separate staticKey
entry (.attestors[*].entries.staticKey)
within the set of attestors and the
count is applied across the keys.
type: string
roots:
description: Roots is an optional set

View file

@ -2186,6 +2186,23 @@ spec:
description: Issuer is the certificate
issuer used for keyless signing.
type: string
rekor:
description: Rekor provides information
of the Rekor transparency log service.
If the value is nil, Rekor is not checked
and a root certificate chain is expected
instead. If an empty object is provided
the public instance of Rekor (https://rekor.sigstore.dev)
is used.
properties:
url:
description: URL is the address of
the transparency log. Defaults to
the public log https://rekor.sigstore.dev.
type: string
required:
- url
type: object
roots:
description: Roots is an optional set
of PEM encoded trusted root certificates.
@ -2217,11 +2234,16 @@ spec:
to a root certificate.
type: string
key:
description: Key is an X.509 public key
used to verify image signatures. The
key can be directly specified or can
be a variable reference to a key specified
in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/).
description: Keys is a set of X.509 public
keys used to verify image signatures.
The keys can be directly specified or
can be a variable reference to a key
specified in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/).
When multiple keys are specified each
key is processed as a separate staticKey
entry (.attestors[*].entries.staticKey)
within the set of attestors and the
count is applied across the keys.
type: string
roots:
description: Roots is an optional set
@ -4538,6 +4560,23 @@ spec:
description: Issuer is the certificate
issuer used for keyless signing.
type: string
rekor:
description: Rekor provides information
of the Rekor transparency log service.
If the value is nil, Rekor is not checked
and a root certificate chain is expected
instead. If an empty object is provided
the public instance of Rekor (https://rekor.sigstore.dev)
is used.
properties:
url:
description: URL is the address of
the transparency log. Defaults to
the public log https://rekor.sigstore.dev.
type: string
required:
- url
type: object
roots:
description: Roots is an optional set
of PEM encoded trusted root certificates.
@ -4569,11 +4608,16 @@ spec:
to a root certificate.
type: string
key:
description: Key is an X.509 public key
used to verify image signatures. The
key can be directly specified or can
be a variable reference to a key specified
in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/).
description: Keys is a set of X.509 public
keys used to verify image signatures.
The keys can be directly specified or
can be a variable reference to a key
specified in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/).
When multiple keys are specified each
key is processed as a separate staticKey
entry (.attestors[*].entries.staticKey)
within the set of attestors and the
count is applied across the keys.
type: string
roots:
description: Roots is an optional set

View file

@ -2202,6 +2202,23 @@ spec:
description: Issuer is the certificate
issuer used for keyless signing.
type: string
rekor:
description: Rekor provides information
of the Rekor transparency log service.
If the value is nil, Rekor is not checked
and a root certificate chain is expected
instead. If an empty object is provided
the public instance of Rekor (https://rekor.sigstore.dev)
is used.
properties:
url:
description: URL is the address of
the transparency log. Defaults to
the public log https://rekor.sigstore.dev.
type: string
required:
- url
type: object
roots:
description: Roots is an optional set
of PEM encoded trusted root certificates.
@ -2233,11 +2250,16 @@ spec:
to a root certificate.
type: string
key:
description: Key is an X.509 public key
used to verify image signatures. The
key can be directly specified or can
be a variable reference to a key specified
in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/).
description: Keys is a set of X.509 public
keys used to verify image signatures.
The keys can be directly specified or
can be a variable reference to a key
specified in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/).
When multiple keys are specified each
key is processed as a separate staticKey
entry (.attestors[*].entries.staticKey)
within the set of attestors and the
count is applied across the keys.
type: string
roots:
description: Roots is an optional set
@ -4553,6 +4575,23 @@ spec:
description: Issuer is the certificate
issuer used for keyless signing.
type: string
rekor:
description: Rekor provides information
of the Rekor transparency log service.
If the value is nil, Rekor is not checked
and a root certificate chain is expected
instead. If an empty object is provided
the public instance of Rekor (https://rekor.sigstore.dev)
is used.
properties:
url:
description: URL is the address of
the transparency log. Defaults to
the public log https://rekor.sigstore.dev.
type: string
required:
- url
type: object
roots:
description: Roots is an optional set
of PEM encoded trusted root certificates.
@ -4584,11 +4623,16 @@ spec:
to a root certificate.
type: string
key:
description: Key is an X.509 public key
used to verify image signatures. The
key can be directly specified or can
be a variable reference to a key specified
in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/).
description: Keys is a set of X.509 public
keys used to verify image signatures.
The keys can be directly specified or
can be a variable reference to a key
specified in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/).
When multiple keys are specified each
key is processed as a separate staticKey
entry (.attestors[*].entries.staticKey)
within the set of attestors and the
count is applied across the keys.
type: string
roots:
description: Roots is an optional set
@ -7792,6 +7836,23 @@ spec:
description: Issuer is the certificate
issuer used for keyless signing.
type: string
rekor:
description: Rekor provides information
of the Rekor transparency log service.
If the value is nil, Rekor is not checked
and a root certificate chain is expected
instead. If an empty object is provided
the public instance of Rekor (https://rekor.sigstore.dev)
is used.
properties:
url:
description: URL is the address of
the transparency log. Defaults to
the public log https://rekor.sigstore.dev.
type: string
required:
- url
type: object
roots:
description: Roots is an optional set
of PEM encoded trusted root certificates.
@ -7823,11 +7884,16 @@ spec:
to a root certificate.
type: string
key:
description: Key is an X.509 public key
used to verify image signatures. The
key can be directly specified or can
be a variable reference to a key specified
in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/).
description: Keys is a set of X.509 public
keys used to verify image signatures.
The keys can be directly specified or
can be a variable reference to a key
specified in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/).
When multiple keys are specified each
key is processed as a separate staticKey
entry (.attestors[*].entries.staticKey)
within the set of attestors and the
count is applied across the keys.
type: string
roots:
description: Roots is an optional set
@ -10144,6 +10210,23 @@ spec:
description: Issuer is the certificate
issuer used for keyless signing.
type: string
rekor:
description: Rekor provides information
of the Rekor transparency log service.
If the value is nil, Rekor is not checked
and a root certificate chain is expected
instead. If an empty object is provided
the public instance of Rekor (https://rekor.sigstore.dev)
is used.
properties:
url:
description: URL is the address of
the transparency log. Defaults to
the public log https://rekor.sigstore.dev.
type: string
required:
- url
type: object
roots:
description: Roots is an optional set
of PEM encoded trusted root certificates.
@ -10175,11 +10258,16 @@ spec:
to a root certificate.
type: string
key:
description: Key is an X.509 public key
used to verify image signatures. The
key can be directly specified or can
be a variable reference to a key specified
in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/).
description: Keys is a set of X.509 public
keys used to verify image signatures.
The keys can be directly specified or
can be a variable reference to a key
specified in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/).
When multiple keys are specified each
key is processed as a separate staticKey
entry (.attestors[*].entries.staticKey)
within the set of attestors and the
count is applied across the keys.
type: string
roots:
description: Roots is an optional set

View file

@ -2191,6 +2191,23 @@ spec:
description: Issuer is the certificate
issuer used for keyless signing.
type: string
rekor:
description: Rekor provides information
of the Rekor transparency log service.
If the value is nil, Rekor is not checked
and a root certificate chain is expected
instead. If an empty object is provided
the public instance of Rekor (https://rekor.sigstore.dev)
is used.
properties:
url:
description: URL is the address of
the transparency log. Defaults to
the public log https://rekor.sigstore.dev.
type: string
required:
- url
type: object
roots:
description: Roots is an optional set
of PEM encoded trusted root certificates.
@ -2222,11 +2239,16 @@ spec:
to a root certificate.
type: string
key:
description: Key is an X.509 public key
used to verify image signatures. The
key can be directly specified or can
be a variable reference to a key specified
in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/).
description: Keys is a set of X.509 public
keys used to verify image signatures.
The keys can be directly specified or
can be a variable reference to a key
specified in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/).
When multiple keys are specified each
key is processed as a separate staticKey
entry (.attestors[*].entries.staticKey)
within the set of attestors and the
count is applied across the keys.
type: string
roots:
description: Roots is an optional set
@ -4542,6 +4564,23 @@ spec:
description: Issuer is the certificate
issuer used for keyless signing.
type: string
rekor:
description: Rekor provides information
of the Rekor transparency log service.
If the value is nil, Rekor is not checked
and a root certificate chain is expected
instead. If an empty object is provided
the public instance of Rekor (https://rekor.sigstore.dev)
is used.
properties:
url:
description: URL is the address of
the transparency log. Defaults to
the public log https://rekor.sigstore.dev.
type: string
required:
- url
type: object
roots:
description: Roots is an optional set
of PEM encoded trusted root certificates.
@ -4573,11 +4612,16 @@ spec:
to a root certificate.
type: string
key:
description: Key is an X.509 public key
used to verify image signatures. The
key can be directly specified or can
be a variable reference to a key specified
in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/).
description: Keys is a set of X.509 public
keys used to verify image signatures.
The keys can be directly specified or
can be a variable reference to a key
specified in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/).
When multiple keys are specified each
key is processed as a separate staticKey
entry (.attestors[*].entries.staticKey)
within the set of attestors and the
count is applied across the keys.
type: string
roots:
description: Roots is an optional set
@ -7757,6 +7801,23 @@ spec:
description: Issuer is the certificate
issuer used for keyless signing.
type: string
rekor:
description: Rekor provides information
of the Rekor transparency log service.
If the value is nil, Rekor is not checked
and a root certificate chain is expected
instead. If an empty object is provided
the public instance of Rekor (https://rekor.sigstore.dev)
is used.
properties:
url:
description: URL is the address of
the transparency log. Defaults to
the public log https://rekor.sigstore.dev.
type: string
required:
- url
type: object
roots:
description: Roots is an optional set
of PEM encoded trusted root certificates.
@ -7788,11 +7849,16 @@ spec:
to a root certificate.
type: string
key:
description: Key is an X.509 public key
used to verify image signatures. The
key can be directly specified or can
be a variable reference to a key specified
in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/).
description: Keys is a set of X.509 public
keys used to verify image signatures.
The keys can be directly specified or
can be a variable reference to a key
specified in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/).
When multiple keys are specified each
key is processed as a separate staticKey
entry (.attestors[*].entries.staticKey)
within the set of attestors and the
count is applied across the keys.
type: string
roots:
description: Roots is an optional set
@ -10109,6 +10175,23 @@ spec:
description: Issuer is the certificate
issuer used for keyless signing.
type: string
rekor:
description: Rekor provides information
of the Rekor transparency log service.
If the value is nil, Rekor is not checked
and a root certificate chain is expected
instead. If an empty object is provided
the public instance of Rekor (https://rekor.sigstore.dev)
is used.
properties:
url:
description: URL is the address of
the transparency log. Defaults to
the public log https://rekor.sigstore.dev.
type: string
required:
- url
type: object
roots:
description: Roots is an optional set
of PEM encoded trusted root certificates.
@ -10140,11 +10223,16 @@ spec:
to a root certificate.
type: string
key:
description: Key is an X.509 public key
used to verify image signatures. The
key can be directly specified or can
be a variable reference to a key specified
in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/).
description: Keys is a set of X.509 public
keys used to verify image signatures.
The keys can be directly specified or
can be a variable reference to a key
specified in a ConfigMap (see https://kyverno.io/docs/writing-policies/variables/).
When multiple keys are specified each
key is processed as a separate staticKey
entry (.attestors[*].entries.staticKey)
within the set of attestors and the
count is applied across the keys.
type: string
roots:
description: Roots is an optional set

View file

@ -398,6 +398,36 @@ automatically generating rules.</p>
</tbody>
</table>
<hr />
<h3 id="kyverno.io/v1.CTLog">CTLog
</h3>
<p>
(<em>Appears on:</em>
<a href="#kyverno.io/v1.KeylessAttestor">KeylessAttestor</a>)
</p>
<p>
</p>
<table class="table table-striped">
<thead class="thead-dark">
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>url</code></br>
<em>
string
</em>
</td>
<td>
<p>URL is the address of the transparency log. Defaults to the public log <a href="https://rekor.sigstore.dev">https://rekor.sigstore.dev</a>.</p>
</td>
</tr>
</tbody>
</table>
<hr />
<h3 id="kyverno.io/v1.CloneFrom">CloneFrom
</h3>
<p>
@ -1602,6 +1632,21 @@ The repository can also be overridden per Attestor or Attestation.</p>
<tbody>
<tr>
<td>
<code>rekor</code></br>
<em>
<a href="#kyverno.io/v1.CTLog">
CTLog
</a>
</em>
</td>
<td>
<p>Rekor provides information of the Rekor transparency log service. If the value is nil,
Rekor is not checked and a root certificate chain is expected instead. If an empty object
is provided the public instance of Rekor (<a href="https://rekor.sigstore.dev">https://rekor.sigstore.dev</a>) is used.</p>
</td>
</tr>
<tr>
<td>
<code>issuer</code></br>
<em>
string
@ -2661,9 +2706,11 @@ string
</em>
</td>
<td>
<p>Key is an X.509 public key used to verify image signatures. The key can be directly
<p>Keys is a set of X.509 public keys used to verify image signatures. The keys can be directly
specified or can be a variable reference to a key specified in a ConfigMap (see
<a href="https://kyverno.io/docs/writing-policies/variables/)">https://kyverno.io/docs/writing-policies/variables/)</a>.</p>
<a href="https://kyverno.io/docs/writing-policies/variables/)">https://kyverno.io/docs/writing-policies/variables/)</a>. When multiple keys are specified each
key is processed as a separate staticKey entry (.attestors[*].entries.staticKey) within the set of
attestors and the count is applied across the keys.</p>
</td>
</tr>
<tr>

View file

@ -44,10 +44,11 @@ type Options struct {
AdditionalExtensions map[string]string
Annotations map[string]string
Repository string
RekorURL string
Log logr.Logger
}
// VerifySignature verifies that the image has the expected key
// VerifySignature verifies that the image has the expected signatures
func VerifySignature(opts Options) (digest string, err error) {
log := opts.Log
ctx := context.Background()
@ -64,22 +65,44 @@ func VerifySignature(opts Options) (digest string, err error) {
ClaimVerifier: cosign.SimpleClaimVerifier,
}
if opts.Roots != nil {
cp, err := loadCertPool(opts.Roots)
if err != nil {
return "", errors.Wrapf(err, "failed to load Root certificates")
}
cosignOpts.RootCerts = cp
}
if opts.Intermediates != nil {
cp, err := loadCertPool(opts.Intermediates)
if err != nil {
return "", errors.Wrapf(err, "failed to load intermediate certificates")
}
cosignOpts.IntermediateCerts = cp
}
if opts.Key != "" {
if strings.HasPrefix(opts.Key, "-----BEGIN PUBLIC KEY-----") {
cosignOpts.SigVerifier, err = decodePEM([]byte(opts.Key))
} else {
cosignOpts.SigVerifier, err = sigs.PublicKeyFromKeyRef(ctx, opts.Key)
}
if err != nil {
return "", errors.Wrap(err, "loading credentials")
}
} else {
cosignOpts.CertEmail = ""
cosignOpts.RootCerts, err = getFulcioRoots(opts.Roots)
if err == nil {
cosignOpts.RekorClient, err = rekor.NewClient("https://rekor.sigstore.dev")
if cosignOpts.RootCerts == nil {
cosignOpts.RootCerts = fulcio.GetRoots()
}
}
if err != nil {
return "", errors.Wrap(err, "loading credentials")
if opts.RekorURL != "" {
cosignOpts.RekorClient, err = rekor.NewClient(opts.RekorURL)
if err != nil {
return "", errors.Wrapf(err, "failed to create Rekor client from URL %s", opts.RekorURL)
}
}
if opts.Repository != "" {
@ -141,6 +164,10 @@ func getFulcioRoots(roots []byte) (*x509.CertPool, error) {
return fulcio.GetRoots(), nil
}
return loadCertPool(roots)
}
func loadCertPool(roots []byte) (*x509.CertPool, error) {
cp := x509.NewCertPool()
if !cp.AppendCertsFromPEM(roots) {
return nil, fmt.Errorf("error creating root cert pool")

View file

@ -3,6 +3,7 @@ package engine
import (
"encoding/json"
"fmt"
"strings"
"time"
"github.com/go-logr/logr"
@ -203,7 +204,9 @@ func (iv *imageVerifier) verifySignatures(imageVerify *v1.ImageVerification, ima
func (iv *imageVerifier) verifyAttestorSet(attestorSet *v1.AttestorSet, imageVerify *v1.ImageVerification, image, path string) (string, error) {
var errorList []error
verifiedCount := 0
attestorSet = expandStaticKeys(attestorSet)
requiredCount := getRequiredCount(attestorSet)
for i, a := range attestorSet.Entries {
var digest string
var entryError error
@ -241,6 +244,53 @@ func (iv *imageVerifier) verifyAttestorSet(attestorSet *v1.AttestorSet, imageVer
return "", err
}
func expandStaticKeys(attestorSet *v1.AttestorSet) *v1.AttestorSet {
var entries []*v1.Attestor
for _, e := range attestorSet.Entries {
if e.StaticKey != nil {
keys := splitPEM(e.StaticKey.Keys)
if len(keys) > 1 {
moreEntries := createStaticKeyAttestors(e.StaticKey, keys)
entries = append(entries, moreEntries...)
continue
}
}
entries = append(entries, e)
}
return &v1.AttestorSet{
Count: attestorSet.Count,
Entries: entries,
}
}
func splitPEM(pem string) []string {
keys := strings.SplitAfter(pem, "-----END PUBLIC KEY-----")
if len(keys) < 1 {
return keys
}
return keys[0 : len(keys)-1]
}
func createStaticKeyAttestors(ska *v1.StaticKeyAttestor, keys []string) []*v1.Attestor {
var attestors []*v1.Attestor
for _, k := range keys {
a := &v1.Attestor{
StaticKey: &v1.StaticKeyAttestor{
Keys: k,
Intermediates: ska.Intermediates,
Roots: ska.Roots,
},
}
attestors = append(attestors, a)
}
return attestors
}
func getRequiredCount(as *v1.AttestorSet) int {
if as.Count == nil || *as.Count == 0 {
return len(as.Entries)
@ -264,7 +314,7 @@ func (iv *imageVerifier) buildOptionsAndPath(attestor *v1.Attestor, imageVerify
if attestor.StaticKey != nil {
path = path + ".staticKey"
opts.Key = attestor.StaticKey.Key
opts.Key = attestor.StaticKey.Keys
if attestor.StaticKey.Roots != "" {
opts.Roots = []byte(attestor.StaticKey.Roots)
}
@ -273,6 +323,9 @@ func (iv *imageVerifier) buildOptionsAndPath(attestor *v1.Attestor, imageVerify
}
} else if attestor.Keyless != nil {
path = path + ".keyless"
if attestor.Keyless.Rekor != nil {
opts.RekorURL = attestor.Keyless.Rekor.URL
}
if attestor.Keyless.Roots != "" {
opts.Roots = []byte(attestor.Keyless.Roots)
}

View file

@ -460,3 +460,26 @@ func Test_NestedAttestors(t *testing.T) {
assert.Equal(t, len(err.PolicyResponse.Rules), 1)
assert.Equal(t, err.PolicyResponse.Rules[0].Status, response.RuleStatusPass)
}
func Test_ExpandKeys(t *testing.T) {
as := expandStaticKeys(createStaticKeyAttestorSet(""))
assert.Equal(t, 1, len(as.Entries))
as = expandStaticKeys(createStaticKeyAttestorSet(testOtherKey))
assert.Equal(t, 1, len(as.Entries))
as = expandStaticKeys(createStaticKeyAttestorSet(testOtherKey + testOtherKey + testOtherKey))
assert.Equal(t, 3, len(as.Entries))
}
func createStaticKeyAttestorSet(s string) *kyverno.AttestorSet {
return &kyverno.AttestorSet{
Entries: []*kyverno.Attestor{
{
StaticKey: &kyverno.StaticKeyAttestor{
Keys: s,
},
},
},
}
}

View file

@ -1013,6 +1013,10 @@ func jsonPatchOnPod(rule kyverno.Rule) bool {
func podControllerAutoGenExclusion(policy kyverno.PolicyInterface) bool {
annotations := policy.GetAnnotations()
val, ok := annotations[kyverno.PodControllersAnnotation]
if !ok || val == "none" {
return false
}
reorderVal := strings.Split(strings.ToLower(val), ",")
sort.Slice(reorderVal, func(i, j int) bool { return reorderVal[i] < reorderVal[j] })
if ok && reflect.DeepEqual(reorderVal, []string{"cronjob", "daemonset", "deployment", "job", "statefulset"}) == false {

View file

@ -2,6 +2,9 @@ package registryclient
import (
"context"
"io/ioutil"
"github.com/google/go-containerregistry/pkg/authn/github"
ecr "github.com/awslabs/amazon-ecr-credential-helper/ecr-login"
"github.com/chrismellard/docker-credential-acr-env/pkg/credhelper"
@ -15,19 +18,19 @@ import (
var (
Secrets []string
kubeClient kubernetes.Interface
kyvernoNamespace string
kyvernoServiceAccount string
kubeClient kubernetes.Interface
namespace string
serviceAccount string
amazonKeychain authn.Keychain = authn.NewKeychainFromHelper(ecr.NewECRHelper())
azureKeychain authn.Keychain = authn.NewKeychainFromHelper(credhelper.NewACRCredentialsHelper())
defaultKeychain authn.Keychain = authn.NewMultiKeychain(
defaultKeychain = authn.NewMultiKeychain(
authn.DefaultKeychain,
google.Keychain,
amazonKeychain,
azureKeychain,
authn.NewKeychainFromHelper(ecr.NewECRHelper(ecr.WithLogger(ioutil.Discard))),
authn.NewKeychainFromHelper(credhelper.NewACRCredentialsHelper()),
github.Keychain,
)
DefaultKeychain authn.Keychain = defaultKeychain
DefaultKeychain = defaultKeychain
)
// InitializeLocal loads the docker credentials and initializes the default auth method for container registry API calls
@ -36,10 +39,10 @@ func InitializeLocal() {
}
// Initialize loads the image pull secrets and initializes the default auth method for container registry API calls
func Initialize(client kubernetes.Interface, namespace, serviceAccount string, imagePullSecrets []string) error {
func Initialize(client kubernetes.Interface, ns, sa string, imagePullSecrets []string) error {
kubeClient = client
kyvernoNamespace = namespace
kyvernoServiceAccount = serviceAccount
namespace = ns
serviceAccount = sa
Secrets = imagePullSecrets
var kc authn.Keychain
@ -64,7 +67,7 @@ func Initialize(client kubernetes.Interface, namespace, serviceAccount string, i
// UpdateKeychain reinitializes the image pull secrets and default auth method for container registry API calls
func UpdateKeychain() error {
var err = Initialize(kubeClient, kyvernoNamespace, kyvernoServiceAccount, Secrets)
var err = Initialize(kubeClient, namespace, serviceAccount, Secrets)
if err != nil {
return err
}