mirror of
https://github.com/kyverno/kyverno.git
synced 2024-12-14 11:57:48 +00:00
feat: add support for sigstore bundle verification (#10567)
* feat: add support for sigstore bundle verification Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: missed change Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: ci Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: linter Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: another linter Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: add size check in layer Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> --------- Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> Co-authored-by: shuting <shuting@nirmata.com> Co-authored-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
parent
f69ffe12ec
commit
06ffd1c961
35 changed files with 710 additions and 46 deletions
|
@ -9,7 +9,7 @@ import (
|
|||
)
|
||||
|
||||
// ImageVerificationType selects the type of verification algorithm
|
||||
// +kubebuilder:validation:Enum=Cosign;Notary
|
||||
// +kubebuilder:validation:Enum=Cosign;SigstoreBundle;Notary
|
||||
// +kubebuilder:default=Cosign
|
||||
type ImageVerificationType string
|
||||
|
||||
|
@ -18,8 +18,9 @@ type ImageVerificationType string
|
|||
type ImageRegistryCredentialsProvidersType string
|
||||
|
||||
const (
|
||||
Cosign ImageVerificationType = "Cosign"
|
||||
Notary ImageVerificationType = "Notary"
|
||||
Cosign ImageVerificationType = "Cosign"
|
||||
SigstoreBundle ImageVerificationType = "SigstoreBundle"
|
||||
Notary ImageVerificationType = "Notary"
|
||||
|
||||
DEFAULT ImageRegistryCredentialsProvidersType = "default"
|
||||
AWS ImageRegistryCredentialsProvidersType = "amazon"
|
||||
|
@ -46,7 +47,7 @@ type ImageVerification struct {
|
|||
ValidationFailureAction *ValidationFailureAction `json:"validationFailureAction,omitempty" yaml:"validationFailureAction,omitempty"`
|
||||
|
||||
// Type specifies the method of signature validation. The allowed options
|
||||
// are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
// are Cosign, Sigstore Bundle and Notary. By default Cosign is used if a type is not specified.
|
||||
// +kubebuilder:validation:Optional
|
||||
Type ImageVerificationType `json:"type,omitempty" yaml:"type,omitempty"`
|
||||
|
||||
|
|
|
@ -4295,9 +4295,10 @@ spec:
|
|||
type:
|
||||
description: |-
|
||||
Type specifies the method of signature validation. The allowed options
|
||||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
are Cosign, Sigstore Bundle and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
@ -8715,9 +8716,10 @@ spec:
|
|||
type:
|
||||
description: |-
|
||||
Type specifies the method of signature validation. The allowed options
|
||||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
are Cosign, Sigstore Bundle and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
@ -12879,6 +12881,7 @@ spec:
|
|||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
@ -17296,9 +17299,10 @@ spec:
|
|||
type:
|
||||
description: |-
|
||||
Type specifies the method of signature validation. The allowed options
|
||||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
are Cosign, Sigstore Bundle and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
|
|
@ -4296,9 +4296,10 @@ spec:
|
|||
type:
|
||||
description: |-
|
||||
Type specifies the method of signature validation. The allowed options
|
||||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
are Cosign, Sigstore Bundle and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
@ -8717,9 +8718,10 @@ spec:
|
|||
type:
|
||||
description: |-
|
||||
Type specifies the method of signature validation. The allowed options
|
||||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
are Cosign, Sigstore Bundle and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
@ -12882,6 +12884,7 @@ spec:
|
|||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
@ -17299,9 +17302,10 @@ spec:
|
|||
type:
|
||||
description: |-
|
||||
Type specifies the method of signature validation. The allowed options
|
||||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
are Cosign, Sigstore Bundle and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
|
|
@ -4289,9 +4289,10 @@ spec:
|
|||
type:
|
||||
description: |-
|
||||
Type specifies the method of signature validation. The allowed options
|
||||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
are Cosign, Sigstore Bundle and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
@ -8709,9 +8710,10 @@ spec:
|
|||
type:
|
||||
description: |-
|
||||
Type specifies the method of signature validation. The allowed options
|
||||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
are Cosign, Sigstore Bundle and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
@ -12873,6 +12875,7 @@ spec:
|
|||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
@ -17290,9 +17293,10 @@ spec:
|
|||
type:
|
||||
description: |-
|
||||
Type specifies the method of signature validation. The allowed options
|
||||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
are Cosign, Sigstore Bundle and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
|
|
@ -4290,9 +4290,10 @@ spec:
|
|||
type:
|
||||
description: |-
|
||||
Type specifies the method of signature validation. The allowed options
|
||||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
are Cosign, Sigstore Bundle and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
@ -8711,9 +8712,10 @@ spec:
|
|||
type:
|
||||
description: |-
|
||||
Type specifies the method of signature validation. The allowed options
|
||||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
are Cosign, Sigstore Bundle and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
@ -12876,6 +12878,7 @@ spec:
|
|||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
@ -17293,9 +17296,10 @@ spec:
|
|||
type:
|
||||
description: |-
|
||||
Type specifies the method of signature validation. The allowed options
|
||||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
are Cosign, Sigstore Bundle and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
|
|
@ -4289,9 +4289,10 @@ spec:
|
|||
type:
|
||||
description: |-
|
||||
Type specifies the method of signature validation. The allowed options
|
||||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
are Cosign, Sigstore Bundle and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
@ -8709,9 +8710,10 @@ spec:
|
|||
type:
|
||||
description: |-
|
||||
Type specifies the method of signature validation. The allowed options
|
||||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
are Cosign, Sigstore Bundle and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
@ -12873,6 +12875,7 @@ spec:
|
|||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
@ -17290,9 +17293,10 @@ spec:
|
|||
type:
|
||||
description: |-
|
||||
Type specifies the method of signature validation. The allowed options
|
||||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
are Cosign, Sigstore Bundle and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
|
|
@ -4290,9 +4290,10 @@ spec:
|
|||
type:
|
||||
description: |-
|
||||
Type specifies the method of signature validation. The allowed options
|
||||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
are Cosign, Sigstore Bundle and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
@ -8711,9 +8712,10 @@ spec:
|
|||
type:
|
||||
description: |-
|
||||
Type specifies the method of signature validation. The allowed options
|
||||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
are Cosign, Sigstore Bundle and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
@ -12876,6 +12878,7 @@ spec:
|
|||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
@ -17293,9 +17296,10 @@ spec:
|
|||
type:
|
||||
description: |-
|
||||
Type specifies the method of signature validation. The allowed options
|
||||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
are Cosign, Sigstore Bundle and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
|
|
@ -9487,9 +9487,10 @@ spec:
|
|||
type:
|
||||
description: |-
|
||||
Type specifies the method of signature validation. The allowed options
|
||||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
are Cosign, Sigstore Bundle and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
@ -13907,9 +13908,10 @@ spec:
|
|||
type:
|
||||
description: |-
|
||||
Type specifies the method of signature validation. The allowed options
|
||||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
are Cosign, Sigstore Bundle and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
@ -18071,6 +18073,7 @@ spec:
|
|||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
@ -22488,9 +22491,10 @@ spec:
|
|||
type:
|
||||
description: |-
|
||||
Type specifies the method of signature validation. The allowed options
|
||||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
are Cosign, Sigstore Bundle and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
@ -27189,9 +27193,10 @@ spec:
|
|||
type:
|
||||
description: |-
|
||||
Type specifies the method of signature validation. The allowed options
|
||||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
are Cosign, Sigstore Bundle and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
@ -31610,9 +31615,10 @@ spec:
|
|||
type:
|
||||
description: |-
|
||||
Type specifies the method of signature validation. The allowed options
|
||||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
are Cosign, Sigstore Bundle and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
@ -35775,6 +35781,7 @@ spec:
|
|||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
@ -40192,9 +40199,10 @@ spec:
|
|||
type:
|
||||
description: |-
|
||||
Type specifies the method of signature validation. The allowed options
|
||||
are Cosign and Notary. By default Cosign is used if a type is not specified.
|
||||
are Cosign, Sigstore Bundle and Notary. By default Cosign is used if a type is not specified.
|
||||
enum:
|
||||
- Cosign
|
||||
- SigstoreBundle
|
||||
- Notary
|
||||
type: string
|
||||
useCache:
|
||||
|
|
|
@ -2410,7 +2410,7 @@ ImageVerificationType
|
|||
</td>
|
||||
<td>
|
||||
<p>Type specifies the method of signature validation. The allowed options
|
||||
are Cosign and Notary. By default Cosign is used if a type is not specified.</p>
|
||||
are Cosign, Sigstore Bundle and Notary. By default Cosign is used if a type is not specified.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
|
@ -4743,7 +4743,7 @@ mutated to include the SHA digest retrieved during the registration.</p>
|
|||
|
||||
|
||||
<p>Type specifies the method of signature validation. The allowed options
|
||||
are Cosign and Notary. By default Cosign is used if a type is not specified.</p>
|
||||
are Cosign, Sigstore Bundle and Notary. By default Cosign is used if a type is not specified.</p>
|
||||
|
||||
|
||||
|
||||
|
|
15
go.mod
15
go.mod
|
@ -23,7 +23,7 @@ require (
|
|||
github.com/go-git/go-billy/v5 v5.5.0
|
||||
github.com/go-git/go-git/v5 v5.12.0
|
||||
github.com/go-logr/logr v1.4.2
|
||||
github.com/go-logr/zapr v1.3.0
|
||||
github.com/go-logr/zerologr v1.2.3
|
||||
github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49
|
||||
github.com/google/go-containerregistry v0.20.2
|
||||
github.com/google/go-containerregistry/pkg/authn/kubernetes v0.0.0-20240530172801-3764db238e3e
|
||||
|
@ -43,16 +43,20 @@ require (
|
|||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.19.0
|
||||
github.com/robfig/cron v1.2.0
|
||||
github.com/rs/zerolog v1.33.0
|
||||
github.com/sigstore/cosign/v2 v2.2.4
|
||||
github.com/sigstore/k8s-manifest-sigstore v0.5.4
|
||||
github.com/sigstore/protobuf-specs v0.3.2 // indirect
|
||||
github.com/sigstore/rekor v1.3.6
|
||||
github.com/sigstore/sigstore v1.8.4
|
||||
github.com/sigstore/sigstore-go v0.4.0
|
||||
github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.4
|
||||
github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.4
|
||||
github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.4
|
||||
github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.4
|
||||
github.com/spf13/cobra v1.8.1
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/theupdateframework/go-tuf/v2 v2.0.0-20240223092044-1e7978e83f63 // indirect
|
||||
github.com/zach-klippenstein/goregen v0.0.0-20160303162051-795b5e3961ea
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0
|
||||
go.opentelemetry.io/otel v1.26.0
|
||||
|
@ -66,7 +70,7 @@ require (
|
|||
go.opentelemetry.io/otel/trace v1.26.0
|
||||
go.uber.org/automaxprocs v1.5.3
|
||||
go.uber.org/multierr v1.11.0
|
||||
go.uber.org/zap v1.27.0
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/crypto v0.26.0
|
||||
golang.org/x/text v0.17.0
|
||||
gomodules.xyz/jsonpatch/v2 v2.4.0
|
||||
|
@ -94,11 +98,6 @@ require (
|
|||
sigs.k8s.io/yaml v1.4.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/go-logr/zerologr v1.2.3 // indirect
|
||||
github.com/rs/zerolog v1.33.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.114.0 // indirect
|
||||
cloud.google.com/go/auth v0.5.1 // indirect
|
||||
|
@ -232,7 +231,7 @@ require (
|
|||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/google/cel-go v0.20.1 // indirect
|
||||
github.com/google/certificate-transparency-go v1.1.7 // indirect
|
||||
github.com/google/certificate-transparency-go v1.1.8 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/go-github/v55 v55.0.0 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
|
|
22
go.sum
22
go.sum
|
@ -436,8 +436,8 @@ github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
|
|||
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
github.com/google/cel-go v0.17.8 h1:j9m730pMZt1Fc4oKhCLUHfjj6527LuhYcYw0Rl8gqto=
|
||||
github.com/google/cel-go v0.17.8/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY=
|
||||
github.com/google/certificate-transparency-go v1.1.7 h1:IASD+NtgSTJLPdzkthwvAG1ZVbF2WtFg4IvoA68XGSw=
|
||||
github.com/google/certificate-transparency-go v1.1.7/go.mod h1:FSSBo8fyMVgqptbfF6j5p/XNdgQftAhSmXcIxV9iphE=
|
||||
github.com/google/certificate-transparency-go v1.1.8 h1:LGYKkgZF7satzgTak9R4yzfJXEeYVAjV6/EAEJOf1to=
|
||||
github.com/google/certificate-transparency-go v1.1.8/go.mod h1:bV/o8r0TBKRf1X//iiiSgWrvII4d7/8OiA+3vG26gI8=
|
||||
github.com/google/flatbuffers v2.0.8+incompatible h1:ivUb1cGomAB101ZM1T0nOiWz9pSrTMoa9+EiY7igmkM=
|
||||
github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||
github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 h1:0VpGH+cDhbDtdcweoyCVsF3fhN8kejK6rFe/2FFX2nU=
|
||||
|
@ -788,10 +788,14 @@ github.com/sigstore/fulcio v1.4.3 h1:9JcUCZjjVhRF9fmhVuz6i1RyhCc/EGCD7MOl+iqCJLQ
|
|||
github.com/sigstore/fulcio v1.4.3/go.mod h1:BQPWo7cfxmJwgaHlphUHUpFkp5+YxeJes82oo39m5og=
|
||||
github.com/sigstore/k8s-manifest-sigstore v0.5.4 h1:XPLs7Dz2OXkRdt4sgAoLxuyNSfkb/n5SwfnYb23YlRk=
|
||||
github.com/sigstore/k8s-manifest-sigstore v0.5.4/go.mod h1:VN/nxjuAprSy1LrutFdhc5UsrQjij4DaCYV4Wklu5zo=
|
||||
github.com/sigstore/protobuf-specs v0.3.2 h1:nCVARCN+fHjlNCk3ThNXwrZRqIommIeNKWwQvORuRQo=
|
||||
github.com/sigstore/protobuf-specs v0.3.2/go.mod h1:RZ0uOdJR4OB3tLQeAyWoJFbNCBFrPQdcokntde4zRBA=
|
||||
github.com/sigstore/rekor v1.3.6 h1:QvpMMJVWAp69a3CHzdrLelqEqpTM3ByQRt5B5Kspbi8=
|
||||
github.com/sigstore/rekor v1.3.6/go.mod h1:JDTSNNMdQ/PxdsS49DJkJ+pRJCO/83nbR5p3aZQteXc=
|
||||
github.com/sigstore/sigstore v1.8.4 h1:g4ICNpiENFnWxjmBzBDWUn62rNFeny/P77HUC8da32w=
|
||||
github.com/sigstore/sigstore v1.8.4/go.mod h1:1jIKtkTFEeISen7en+ZPWdDHazqhxco/+v9CNjc7oNg=
|
||||
github.com/sigstore/sigstore-go v0.4.0 h1:0BxofjPnd+1LzyiCgsFP0NviMg8l20ZMf4aitkvYEU8=
|
||||
github.com/sigstore/sigstore-go v0.4.0/go.mod h1:KZQFwvDItf1sr5P8YhVIjjXBe1ZyeFuC4odn7/2Uie0=
|
||||
github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.4 h1:okxaVlaTrQowE1FA4UQ3rw54f7BUjdnzERIxbZTBZuc=
|
||||
github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.4/go.mod h1:jkcPErmnCECuSJajUaUq5pwCMOeBF19VzQo6bv4l1D0=
|
||||
github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.4 h1:1G6uLTZaqvu867DbgH7p75L6Y7Tu8LLnYJGZnWsTUu8=
|
||||
|
@ -869,6 +873,8 @@ github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gt
|
|||
github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU=
|
||||
github.com/theupdateframework/go-tuf v0.7.0 h1:CqbQFrWo1ae3/I0UCblSbczevCCbS31Qvs5LdxRWqRI=
|
||||
github.com/theupdateframework/go-tuf v0.7.0/go.mod h1:uEB7WSY+7ZIugK6R1hiBMBjQftaFzn7ZCDJcp1tCUug=
|
||||
github.com/theupdateframework/go-tuf/v2 v2.0.0-20240223092044-1e7978e83f63 h1:27XWhDZHPD+cufF6qSdYx6PgGQvD2jJ6pq9sDvR6VBk=
|
||||
github.com/theupdateframework/go-tuf/v2 v2.0.0-20240223092044-1e7978e83f63/go.mod h1:+gWwqe1pk4nvGeOKosGJqPgD+N/kbD9M0QVLL9TGIYU=
|
||||
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0=
|
||||
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs=
|
||||
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
|
||||
|
@ -928,12 +934,12 @@ go.etcd.io/etcd/client/v2 v2.305.12 h1:0m4ovXYo1CHaA/Mp3X/Fak5sRNIWf01wk/X1/G3sG
|
|||
go.etcd.io/etcd/client/v2 v2.305.12/go.mod h1:aQ/yhsxMu+Oht1FOupSr60oBvcS9cKXHrzBpDsPTf9E=
|
||||
go.etcd.io/etcd/client/v3 v3.5.13 h1:o0fHTNJLeO0MyVbc7I3fsCf6nrOqn5d+diSarKnB2js=
|
||||
go.etcd.io/etcd/client/v3 v3.5.13/go.mod h1:cqiAeY8b5DEEcpxvgWKsbLIWNM/8Wy2xJSDMtioMcoI=
|
||||
go.etcd.io/etcd/pkg/v3 v3.5.10 h1:WPR8K0e9kWl1gAhB5A7gEa5ZBTNkT9NdNWrR8Qpo1CM=
|
||||
go.etcd.io/etcd/pkg/v3 v3.5.10/go.mod h1:TKTuCKKcF1zxmfKWDkfz5qqYaE3JncKKZPFf8c1nFUs=
|
||||
go.etcd.io/etcd/raft/v3 v3.5.10 h1:cgNAYe7xrsrn/5kXMSaH8kM/Ky8mAdMqGOxyYwpP0LA=
|
||||
go.etcd.io/etcd/raft/v3 v3.5.10/go.mod h1:odD6kr8XQXTy9oQnyMPBOr0TVe+gT0neQhElQ6jbGRc=
|
||||
go.etcd.io/etcd/server/v3 v3.5.10 h1:4NOGyOwD5sUZ22PiWYKmfxqoeh72z6EhYjNosKGLmZg=
|
||||
go.etcd.io/etcd/server/v3 v3.5.10/go.mod h1:gBplPHfs6YI0L+RpGkTQO7buDbHv5HJGG/Bst0/zIPo=
|
||||
go.etcd.io/etcd/pkg/v3 v3.5.12 h1:OK2fZKI5hX/+BTK76gXSTyZMrbnARyX9S643GenNGb8=
|
||||
go.etcd.io/etcd/pkg/v3 v3.5.12/go.mod h1:UVwg/QIMoJncyeb/YxvJBJCE/NEwtHWashqc8A1nj/M=
|
||||
go.etcd.io/etcd/raft/v3 v3.5.12 h1:7r22RufdDsq2z3STjoR7Msz6fYH8tmbkdheGfwJNRmU=
|
||||
go.etcd.io/etcd/raft/v3 v3.5.12/go.mod h1:ERQuZVe79PI6vcC3DlKBukDCLja/L7YMu29B74Iwj4U=
|
||||
go.etcd.io/etcd/server/v3 v3.5.12 h1:EtMjsbfyfkwZuA2JlKOiBfuGkFCekv5H178qjXypbG8=
|
||||
go.etcd.io/etcd/server/v3 v3.5.12/go.mod h1:axB0oCjMy+cemo5290/CutIjoxlfA6KVYKD1w0uue10=
|
||||
go.mongodb.org/mongo-driver v1.15.0 h1:rJCKC8eEliewXjZGf0ddURtl7tTVy1TK3bfl0gkUSLc=
|
||||
go.mongodb.org/mongo-driver v1.15.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
|
|
|
@ -47,6 +47,19 @@ func NewVerifier() images.ImageVerifier {
|
|||
type cosignVerifier struct{}
|
||||
|
||||
func (v *cosignVerifier) VerifySignature(ctx context.Context, opts images.Options) (*images.Response, error) {
|
||||
if opts.SigstoreBundle {
|
||||
results, err := verifyBundleAndFetchAttestations(ctx, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(results) == 0 {
|
||||
return nil, fmt.Errorf("sigstore bundle verification failed: no matching signatures found")
|
||||
}
|
||||
|
||||
return &images.Response{Digest: results[0].Desc.Digest.String()}, nil
|
||||
}
|
||||
|
||||
ref, err := name.ParseReference(opts.ImageRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse image %s", opts.ImageRef)
|
||||
|
@ -266,6 +279,22 @@ func loadCertChain(pem []byte) ([]*x509.Certificate, error) {
|
|||
}
|
||||
|
||||
func (v *cosignVerifier) FetchAttestations(ctx context.Context, opts images.Options) (*images.Response, error) {
|
||||
if opts.SigstoreBundle {
|
||||
results, err := verifyBundleAndFetchAttestations(ctx, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(results) == 0 {
|
||||
return nil, fmt.Errorf("sigstore bundle verification failed: no matching signatures found")
|
||||
}
|
||||
|
||||
statements, err := decodeStatementsFromBundles(results)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &images.Response{Digest: results[0].Desc.Digest.String(), Statements: statements}, nil
|
||||
}
|
||||
cosignOpts, err := buildCosignOptions(ctx, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
254
pkg/cosign/sigstore.go
Normal file
254
pkg/cosign/sigstore.go
Normal file
|
@ -0,0 +1,254 @@
|
|||
package cosign
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
"github.com/in-toto/in-toto-golang/in_toto"
|
||||
"github.com/kyverno/kyverno/pkg/images"
|
||||
"github.com/kyverno/kyverno/pkg/utils/data"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sigstore/sigstore-go/pkg/bundle"
|
||||
"github.com/sigstore/sigstore-go/pkg/root"
|
||||
"github.com/sigstore/sigstore-go/pkg/verify"
|
||||
"github.com/sigstore/sigstore/pkg/tuf"
|
||||
)
|
||||
|
||||
var (
|
||||
maxLayerSize = int64(10 * 1000 * 1000) // 10 MB
|
||||
attestationlimit = 50
|
||||
)
|
||||
|
||||
type VerificationResult struct {
|
||||
Bundle *Bundle
|
||||
Result *verify.VerificationResult
|
||||
Desc *v1.Descriptor
|
||||
}
|
||||
|
||||
type Bundle struct {
|
||||
ProtoBundle *bundle.ProtobufBundle
|
||||
DSSE_Envelope *in_toto.Statement
|
||||
}
|
||||
|
||||
func verifyBundleAndFetchAttestations(ctx context.Context, opts images.Options) ([]*VerificationResult, error) {
|
||||
ref, err := name.ParseReference(opts.ImageRef)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse image reference: %v", opts.ImageRef)
|
||||
}
|
||||
|
||||
remoteOpts, err := opts.Client.Options(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to create remote opts: %v", opts.ImageRef)
|
||||
}
|
||||
|
||||
bundles, desc, err := fetchBundles(ref, attestationlimit, opts.Type, remoteOpts)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to fetch bundles: %v", opts.ImageRef)
|
||||
}
|
||||
|
||||
policy, err := buildPolicy(desc, opts)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to build policy: %v", opts.ImageRef)
|
||||
}
|
||||
|
||||
verifyOpts := buildVerifyOptions(opts)
|
||||
trustedMaterial, err := getTrustedRoot(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to get trusted root: %v", opts.ImageRef)
|
||||
}
|
||||
|
||||
results, err := verifyBundles(bundles, desc, trustedMaterial, policy, verifyOpts)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to get verify bundles: %v", opts.ImageRef)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func verifyBundles(bundles []*Bundle, desc *v1.Descriptor, trustedRoot *root.TrustedRoot, policy verify.PolicyBuilder, verifierOpts []verify.VerifierOption) ([]*VerificationResult, error) {
|
||||
verifier, err := verify.NewSignedEntityVerifier(trustedRoot, verifierOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
verificationResults := make([]*VerificationResult, 0)
|
||||
for _, bundle := range bundles {
|
||||
result, err := verifier.Verify(bundle.ProtoBundle, policy)
|
||||
if err == nil {
|
||||
verificationResults = append(verificationResults, &VerificationResult{Bundle: bundle, Result: result, Desc: desc})
|
||||
}
|
||||
}
|
||||
|
||||
return verificationResults, nil
|
||||
}
|
||||
|
||||
func fetchBundles(ref name.Reference, limit int, predicateType string, remoteOpts []remote.Option) ([]*Bundle, *v1.Descriptor, error) {
|
||||
bundles := make([]*Bundle, 0)
|
||||
|
||||
desc, err := remote.Head(ref, remoteOpts...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
referrers, err := remote.Referrers(ref.Context().Digest(desc.Digest.String()), remoteOpts...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
referrersDescs, err := referrers.IndexManifest()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if len(referrersDescs.Manifests) > limit {
|
||||
return nil, nil, fmt.Errorf("failed to fetch referrers: to many referrers found, max limit is %d", limit)
|
||||
}
|
||||
|
||||
for _, manifestDesc := range referrersDescs.Manifests {
|
||||
if !strings.HasPrefix(manifestDesc.ArtifactType, "application/vnd.dev.sigstore.bundle") {
|
||||
continue
|
||||
}
|
||||
|
||||
refImg, err := remote.Image(ref.Context().Digest(manifestDesc.Digest.String()), remoteOpts...)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to fetch referrer image: %w", err)
|
||||
}
|
||||
layers, err := refImg.Layers()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to fetch referrer layer: %w", err)
|
||||
}
|
||||
if len(layers) == 0 {
|
||||
return nil, nil, fmt.Errorf("layers not found")
|
||||
}
|
||||
layer := layers[0]
|
||||
layerSize, err := layer.Size()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if layerSize > maxLayerSize {
|
||||
return nil, nil, fmt.Errorf("layer size %d exceeds %d", layerSize, maxLayerSize)
|
||||
}
|
||||
layerBytes, err := layer.Uncompressed()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to fetch referrer layer: %w", err)
|
||||
}
|
||||
bundleBytes, err := io.ReadAll(layerBytes)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to fetch referrer layer: %w", err)
|
||||
}
|
||||
b := &bundle.ProtobufBundle{}
|
||||
err = b.UnmarshalJSON(bundleBytes)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to unmarshal bundle: %w", err)
|
||||
}
|
||||
bundles = append(bundles, &Bundle{ProtoBundle: b})
|
||||
}
|
||||
|
||||
if predicateType != "" {
|
||||
filteredBundles := make([]*Bundle, 0)
|
||||
for _, b := range bundles {
|
||||
dsseEnvelope := b.ProtoBundle.Bundle.GetDsseEnvelope()
|
||||
if dsseEnvelope != nil {
|
||||
if dsseEnvelope.PayloadType != "application/vnd.in-toto+json" {
|
||||
continue
|
||||
}
|
||||
var intotoStatement in_toto.Statement
|
||||
if err := json.Unmarshal(dsseEnvelope.Payload, &intotoStatement); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if intotoStatement.PredicateType == predicateType {
|
||||
filteredBundles = append(filteredBundles, &Bundle{
|
||||
ProtoBundle: b.ProtoBundle,
|
||||
DSSE_Envelope: &intotoStatement,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return filteredBundles, desc, nil
|
||||
}
|
||||
|
||||
return bundles, desc, nil
|
||||
}
|
||||
|
||||
func buildPolicy(desc *v1.Descriptor, opts images.Options) (verify.PolicyBuilder, error) {
|
||||
digest, err := hex.DecodeString(desc.Digest.Hex)
|
||||
if err != nil {
|
||||
return verify.PolicyBuilder{}, err
|
||||
}
|
||||
artifactDigestVerificationOption := verify.WithArtifactDigest(desc.Digest.Algorithm, digest)
|
||||
|
||||
// TODO: Add full regexp support to sigstore and cosign
|
||||
// Verify images only has subject field, and no subject regexp, subject cannot be passed to subject regexp
|
||||
// because then string containing the subjects will also work. We should just add an issuer regexp
|
||||
// Solve this in a separate PR,
|
||||
// See: https://github.com/sigstore/cosign/blob/7c20052077a81d667526af879ec40168899dde1f/pkg/cosign/verify.go#L339-L356
|
||||
subjectRegexp := ""
|
||||
if strings.Contains(opts.Subject, "*") {
|
||||
subjectRegexp = opts.Subject
|
||||
opts.Subject = ""
|
||||
}
|
||||
id, err := verify.NewShortCertificateIdentity(opts.Issuer, opts.Subject, "", subjectRegexp)
|
||||
if err != nil {
|
||||
return verify.PolicyBuilder{}, err
|
||||
}
|
||||
return verify.NewPolicy(artifactDigestVerificationOption, verify.WithCertificateIdentity(id)), nil
|
||||
}
|
||||
|
||||
func buildVerifyOptions(opts images.Options) []verify.VerifierOption {
|
||||
var verifierOptions []verify.VerifierOption
|
||||
if !opts.IgnoreTlog {
|
||||
verifierOptions = append(verifierOptions, verify.WithTransparencyLog(1))
|
||||
}
|
||||
|
||||
if !opts.IgnoreSCT {
|
||||
verifierOptions = append(verifierOptions, verify.WithObserverTimestamps(1))
|
||||
}
|
||||
|
||||
return verifierOptions
|
||||
}
|
||||
|
||||
func getTrustedRoot(ctx context.Context) (*root.TrustedRoot, error) {
|
||||
tufClient, err := tuf.NewFromEnv(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("initializing tuf: %w", err)
|
||||
}
|
||||
targetBytes, err := tufClient.GetTarget("trusted_root.json")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting targets: %w", err)
|
||||
}
|
||||
trustedRoot, err := root.NewTrustedRootFromJSON(targetBytes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating trusted root: %w", err)
|
||||
}
|
||||
|
||||
return trustedRoot, nil
|
||||
}
|
||||
|
||||
func decodeStatementsFromBundles(bundles []*VerificationResult) ([]map[string]interface{}, error) {
|
||||
if len(bundles) == 0 {
|
||||
return []map[string]interface{}{}, nil
|
||||
}
|
||||
|
||||
var err error
|
||||
var statement map[string]interface{}
|
||||
var intotostatement in_toto.Statement
|
||||
decodedStatements := make([]map[string]interface{}, len(bundles))
|
||||
for i, b := range bundles {
|
||||
intotostatement = *b.Bundle.DSSE_Envelope
|
||||
statement, err = data.ToMap(intotostatement)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to decode statement: %v", intotostatement.Type)
|
||||
}
|
||||
statement["type"] = intotostatement.PredicateType
|
||||
decodedStatements[i] = statement
|
||||
}
|
||||
return decodedStatements, nil
|
||||
}
|
89
pkg/cosign/sigstore_test.go
Normal file
89
pkg/cosign/sigstore_test.go
Normal file
|
@ -0,0 +1,89 @@
|
|||
package cosign
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
"github.com/kyverno/kyverno/pkg/images"
|
||||
"github.com/kyverno/kyverno/pkg/registryclient"
|
||||
"gotest.tools/assert"
|
||||
)
|
||||
|
||||
func TestSigstoreBundleSignatureVerification(t *testing.T) {
|
||||
opts := images.Options{
|
||||
SigstoreBundle: true,
|
||||
ImageRef: "ghcr.io/vishal-chdhry/artifact-attestation-example:artifact-attestation",
|
||||
Issuer: "https://token.actions.githubusercontent.com",
|
||||
Subject: "https://github.com/vishal-chdhry/artifact-attestation-example/.github/workflows/build-attested-image.yaml@refs/heads/main",
|
||||
}
|
||||
|
||||
rc, err := registryclient.New()
|
||||
assert.NilError(t, err)
|
||||
opts.Client = rc
|
||||
|
||||
verifier := &cosignVerifier{}
|
||||
_, err = verifier.VerifySignature(context.TODO(), opts)
|
||||
assert.NilError(t, err)
|
||||
|
||||
opts.Subject = "invalid"
|
||||
_, err = verifier.VerifySignature(context.TODO(), opts)
|
||||
assert.ErrorContains(t, err, "sigstore bundle verification failed: no matching signatures found")
|
||||
}
|
||||
|
||||
func TestSigstoreBundleSignatureResponse(t *testing.T) {
|
||||
opts := images.Options{
|
||||
SigstoreBundle: true,
|
||||
ImageRef: "ghcr.io/vishal-chdhry/artifact-attestation-example:artifact-attestation",
|
||||
Issuer: "https://token.actions.githubusercontent.com",
|
||||
Subject: "https://github.com/vishal-chdhry/artifact-attestation-example/.github/workflows/build-attested-image.yaml@refs/heads/main",
|
||||
}
|
||||
|
||||
rc, err := registryclient.New()
|
||||
assert.NilError(t, err)
|
||||
opts.Client = rc
|
||||
|
||||
verifier := &cosignVerifier{}
|
||||
response, err := verifier.VerifySignature(context.TODO(), opts)
|
||||
assert.NilError(t, err)
|
||||
|
||||
ref, err := name.ParseReference(opts.ImageRef)
|
||||
assert.NilError(t, err)
|
||||
|
||||
desc, err := remote.Head(ref)
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, desc.Digest.String(), response.Digest)
|
||||
assert.Equal(t, len(response.Statements), 0)
|
||||
}
|
||||
|
||||
func TestSigstoreBundleAttestation(t *testing.T) {
|
||||
opts := images.Options{
|
||||
SigstoreBundle: true,
|
||||
ImageRef: "ghcr.io/vishal-chdhry/artifact-attestation-example:artifact-attestation",
|
||||
Issuer: "https://token.actions.githubusercontent.com",
|
||||
Subject: "https://github.com/vishal-chdhry/artifact-attestation-example/.github/workflows/build-attested-image.yaml@refs/heads/main",
|
||||
Type: "https://slsa.dev/provenance/v1",
|
||||
}
|
||||
|
||||
rc, err := registryclient.New()
|
||||
assert.NilError(t, err)
|
||||
opts.Client = rc
|
||||
|
||||
verifier := &cosignVerifier{}
|
||||
response, err := verifier.FetchAttestations(context.TODO(), opts)
|
||||
assert.NilError(t, err)
|
||||
|
||||
ref, err := name.ParseReference(opts.ImageRef)
|
||||
assert.NilError(t, err)
|
||||
|
||||
desc, err := remote.Head(ref)
|
||||
assert.NilError(t, err)
|
||||
|
||||
assert.Equal(t, desc.Digest.String(), response.Digest)
|
||||
assert.Assert(t, len(response.Statements) > 0)
|
||||
|
||||
buildType, ok := response.Statements[0]["predicate"].(map[string]interface{})["buildDefinition"].(map[string]interface{})["buildType"].(string)
|
||||
assert.Assert(t, ok)
|
||||
assert.Equal(t, buildType, "https://actions.github.io/buildtypes/workflow/v1")
|
||||
}
|
|
@ -556,6 +556,10 @@ func (iv *ImageVerifier) buildCosignVerifier(
|
|||
Client: iv.rclient,
|
||||
}
|
||||
|
||||
if imageVerify.Type == kyvernov1.SigstoreBundle {
|
||||
opts.SigstoreBundle = true
|
||||
}
|
||||
|
||||
if imageVerify.Roots != "" {
|
||||
opts.Roots = imageVerify.Roots
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ type Client interface {
|
|||
}
|
||||
|
||||
type Options struct {
|
||||
SigstoreBundle bool
|
||||
ImageRef string
|
||||
Client Client
|
||||
FetchAttestations bool
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
## Description
|
||||
|
||||
This test verifies the predicate in sigstore bundle attached to an image using regex issuer
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: chainsaw.kyverno.io/v1alpha1
|
||||
kind: Test
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: sigstore-attestation-verification-regexp
|
||||
spec:
|
||||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: policy.yaml
|
||||
- assert:
|
||||
file: policy-assert.yaml
|
||||
- name: step-02
|
||||
try:
|
||||
- apply:
|
||||
file: pod.yaml
|
||||
- assert:
|
||||
file: pod-assert.yaml
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: test-pod
|
||||
namespace: default
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: test-pod
|
||||
namespace: default
|
||||
spec:
|
||||
containers:
|
||||
- image: ghcr.io/vishal-chdhry/artifact-attestation-example:artifact-attestation
|
||||
name: test-container
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: sigstore-attestation-verification-regexp
|
||||
status:
|
||||
conditions:
|
||||
- reason: Succeeded
|
||||
status: "True"
|
||||
type: Ready
|
|
@ -0,0 +1,36 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
annotations:
|
||||
pod-policies.kyverno.io/autogen-controllers: none
|
||||
name: sigstore-attestation-verification-regexp
|
||||
spec:
|
||||
background: false
|
||||
validationFailureAction: Enforce
|
||||
webhookTimeoutSeconds: 30
|
||||
rules:
|
||||
- match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- Pod
|
||||
name: sigstore-attestation-verification
|
||||
verifyImages:
|
||||
- imageReferences:
|
||||
- "*"
|
||||
type: SigstoreBundle
|
||||
attestations:
|
||||
- attestors:
|
||||
- entries:
|
||||
- keyless:
|
||||
issuer: https://token.actions.githubusercontent.com
|
||||
subject: https://github.com/vishal-chdhry/artifact-attestation-example/.github/workflows/*
|
||||
rekor:
|
||||
url: https://rekor.sigstore.dev
|
||||
conditions:
|
||||
- all:
|
||||
- key: '{{ buildDefinition.buildType }}'
|
||||
operator: Equals
|
||||
value: https://actions.github.io/buildtypes/workflow/v1
|
||||
type: https://slsa.dev/provenance/v1
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
## Description
|
||||
|
||||
This test verifies the predicate in sigstore bundle attached to an image
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: chainsaw.kyverno.io/v1alpha1
|
||||
kind: Test
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: sigstore-attestation-verification
|
||||
spec:
|
||||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: policy.yaml
|
||||
- assert:
|
||||
file: policy-assert.yaml
|
||||
- name: step-02
|
||||
try:
|
||||
- apply:
|
||||
file: pod.yaml
|
||||
- assert:
|
||||
file: pod-assert.yaml
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: test-pod
|
||||
namespace: default
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: test-pod
|
||||
namespace: default
|
||||
spec:
|
||||
containers:
|
||||
- image: ghcr.io/vishal-chdhry/artifact-attestation-example:artifact-attestation
|
||||
name: test-container
|
|
@ -0,0 +1,10 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: sigstore-attestation-verification
|
||||
status:
|
||||
conditions:
|
||||
- reason: Succeeded
|
||||
status: "True"
|
||||
type: Ready
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
annotations:
|
||||
pod-policies.kyverno.io/autogen-controllers: none
|
||||
name: sigstore-attestation-verification
|
||||
spec:
|
||||
background: false
|
||||
validationFailureAction: Enforce
|
||||
webhookTimeoutSeconds: 30
|
||||
rules:
|
||||
- match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- Pod
|
||||
name: sigstore-attestation-verification
|
||||
verifyImages:
|
||||
- imageReferences:
|
||||
- "*"
|
||||
type: SigstoreBundle
|
||||
attestations:
|
||||
- attestors:
|
||||
- entries:
|
||||
- keyless:
|
||||
issuer: https://token.actions.githubusercontent.com
|
||||
subject: https://github.com/vishal-chdhry/artifact-attestation-example/.github/workflows/build-attested-image.yaml@refs/heads/main
|
||||
rekor:
|
||||
url: https://rekor.sigstore.dev
|
||||
conditions:
|
||||
- all:
|
||||
- key: '{{ buildDefinition.buildType }}'
|
||||
operator: Equals
|
||||
value: https://actions.github.io/buildtypes/workflow/v1
|
||||
type: https://slsa.dev/provenance/v1
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
## Description
|
||||
|
||||
This test verifies sigstore bundle attached to an image.
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: chainsaw.kyverno.io/v1alpha1
|
||||
kind: Test
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: sigstore-image-verification
|
||||
spec:
|
||||
steps:
|
||||
- name: step-01
|
||||
try:
|
||||
- apply:
|
||||
file: policy.yaml
|
||||
- assert:
|
||||
file: policy-assert.yaml
|
||||
- name: step-02
|
||||
try:
|
||||
- apply:
|
||||
file: pod.yaml
|
||||
- assert:
|
||||
file: pod-assert.yaml
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: test-pod
|
||||
namespace: default
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: test-pod
|
||||
namespace: default
|
||||
spec:
|
||||
containers:
|
||||
- image: ghcr.io/vishal-chdhry/artifact-attestation-example:artifact-attestation
|
||||
name: test-container
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: sigstore-image-verification
|
||||
status:
|
||||
conditions:
|
||||
- reason: Succeeded
|
||||
status: "True"
|
||||
type: Ready
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
annotations:
|
||||
pod-policies.kyverno.io/autogen-controllers: none
|
||||
name: sigstore-image-verification
|
||||
spec:
|
||||
background: false
|
||||
validationFailureAction: Enforce
|
||||
webhookTimeoutSeconds: 30
|
||||
rules:
|
||||
- match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- Pod
|
||||
name: sigstore-image-verification
|
||||
verifyImages:
|
||||
- imageReferences:
|
||||
- "*"
|
||||
type: SigstoreBundle
|
||||
attestors:
|
||||
- entries:
|
||||
- keyless:
|
||||
issuer: https://token.actions.githubusercontent.com
|
||||
subject: https://github.com/vishal-chdhry/artifact-attestation-example/.github/workflows/build-attested-image.yaml@refs/heads/main
|
||||
rekor:
|
||||
url: https://rekor.sigstore.dev
|
||||
|
Loading…
Reference in a new issue