Introduce Initial OCIRepository Source Verification
Fixes #863 Signed-off-by: Furkan <furkan.turkal@trendyol.com> Co-authored-by: Batuhan <batuhan.apaydin@trendyol.com> Signed-off-by: Batuhan Apaydın <batuhan.apaydin@trendyol.com>
This commit is contained in:
parent
54d706a226
commit
697f260dba
|
@ -9,6 +9,7 @@ on:
|
|||
push:
|
||||
branches:
|
||||
- main
|
||||
- feature/863
|
||||
|
||||
permissions:
|
||||
contents: read # for actions/checkout to fetch code
|
||||
|
|
|
@ -71,6 +71,10 @@ const (
|
|||
// required fields, or the provided credentials do not match.
|
||||
AuthenticationFailedReason string = "AuthenticationFailed"
|
||||
|
||||
// VerificationError signals that the Source's verification
|
||||
// check failed.
|
||||
VerificationError string = "VerificationError"
|
||||
|
||||
// DirCreationFailedReason signals a failure caused by a directory creation
|
||||
// operation.
|
||||
DirCreationFailedReason string = "DirectoryCreationFailed"
|
||||
|
|
|
@ -78,6 +78,12 @@ type OCIRepositorySpec struct {
|
|||
// +optional
|
||||
SecretRef *meta.LocalObjectReference `json:"secretRef,omitempty"`
|
||||
|
||||
// Verify contains the secret name containing the trusted public keys
|
||||
// used to verify the signature and specifies which provider to use to check
|
||||
// whether OCI image is authentic.
|
||||
// +optional
|
||||
Verify *OCIRepositoryVerification `json:"verify,omitempty"`
|
||||
|
||||
// ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate
|
||||
// the image pull if the service account has attached pull secrets. For more information:
|
||||
// https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account
|
||||
|
@ -156,11 +162,13 @@ type OCILayerSelector struct {
|
|||
type OCIRepositoryVerification struct {
|
||||
// Provider specifies the technology used to sign the OCI Artifact.
|
||||
// +kubebuilder:validation:Enum=cosign
|
||||
// +kubebuilder:default:=cosign
|
||||
Provider string `json:"provider"`
|
||||
|
||||
// SecretRef specifies the Kubernetes Secret containing the
|
||||
// trusted public keys.
|
||||
SecretRef meta.LocalObjectReference `json:"secretRef"`
|
||||
// +optional
|
||||
SecretRef *meta.LocalObjectReference `json:"secretRef"`
|
||||
}
|
||||
|
||||
// OCIRepositoryStatus defines the observed state of OCIRepository
|
||||
|
|
|
@ -729,6 +729,11 @@ func (in *OCIRepositorySpec) DeepCopyInto(out *OCIRepositorySpec) {
|
|||
*out = new(meta.LocalObjectReference)
|
||||
**out = **in
|
||||
}
|
||||
if in.Verify != nil {
|
||||
in, out := &in.Verify, &out.Verify
|
||||
*out = new(OCIRepositoryVerification)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.CertSecretRef != nil {
|
||||
in, out := &in.CertSecretRef, &out.CertSecretRef
|
||||
*out = new(meta.LocalObjectReference)
|
||||
|
@ -788,7 +793,11 @@ func (in *OCIRepositoryStatus) DeepCopy() *OCIRepositoryStatus {
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *OCIRepositoryVerification) DeepCopyInto(out *OCIRepositoryVerification) {
|
||||
*out = *in
|
||||
out.SecretRef = in.SecretRef
|
||||
if in.SecretRef != nil {
|
||||
in, out := &in.SecretRef, &out.SecretRef
|
||||
*out = new(meta.LocalObjectReference)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OCIRepositoryVerification.
|
||||
|
|
|
@ -148,6 +148,31 @@ spec:
|
|||
on a remote container registry.
|
||||
pattern: ^oci://.*$
|
||||
type: string
|
||||
verify:
|
||||
description: Verify contains the secret name containing the trusted
|
||||
public keys used to verify the signature and specifies which provider
|
||||
to use to check whether OCI image is authentic.
|
||||
properties:
|
||||
provider:
|
||||
default: cosign
|
||||
description: Provider specifies the technology used to sign the
|
||||
OCI Artifact.
|
||||
enum:
|
||||
- cosign
|
||||
type: string
|
||||
secretRef:
|
||||
description: SecretRef specifies the Kubernetes Secret containing
|
||||
the trusted public keys.
|
||||
properties:
|
||||
name:
|
||||
description: Name of the referent.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
required:
|
||||
- provider
|
||||
type: object
|
||||
required:
|
||||
- interval
|
||||
- url
|
||||
|
|
|
@ -51,6 +51,8 @@ spec:
|
|||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
- name: TUF_ROOT
|
||||
value: "/tmp/.sigstore"
|
||||
args:
|
||||
- --watch-all-namespaces
|
||||
- --log-level=info
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
apiVersion: source.toolkit.fluxcd.io/v1beta2
|
||||
kind: OCIRepository
|
||||
metadata:
|
||||
name: podinfo-deploy-signed-with-key
|
||||
spec:
|
||||
interval: 5m
|
||||
url: oci://ghcr.io/stefanprodan/podinfo-deploy
|
||||
ref:
|
||||
semver: "6.2.x"
|
||||
verify:
|
||||
provider: cosign
|
||||
secretRef:
|
||||
name: cosign-key
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
apiVersion: source.toolkit.fluxcd.io/v1beta2
|
||||
kind: OCIRepository
|
||||
metadata:
|
||||
name: podinfo-deploy-signed-with-keyless
|
||||
spec:
|
||||
interval: 5m
|
||||
url: oci://ghcr.io/stefanprodan/manifests/podinfo
|
||||
ref:
|
||||
semver: "6.2.x"
|
||||
verify:
|
||||
provider: cosign
|
|
@ -28,6 +28,8 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
soci "github.com/fluxcd/source-controller/internal/oci"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"github.com/google/go-containerregistry/pkg/authn"
|
||||
"github.com/google/go-containerregistry/pkg/authn/k8schain"
|
||||
|
@ -408,6 +410,20 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
|
|||
|
||||
// Extract the content of the first artifact layer
|
||||
if !obj.GetArtifact().HasRevision(revision) {
|
||||
if obj.Spec.Verify != nil {
|
||||
provider := obj.Spec.Verify.Provider
|
||||
err := r.verifyOCISourceSignature(ctx, obj, url, keychain)
|
||||
if err != nil {
|
||||
e := serror.NewGeneric(
|
||||
fmt.Errorf("failed to verify OCI image signature '%s' using provider '%s': %w", url, provider, err),
|
||||
sourcev1.VerificationError,
|
||||
)
|
||||
conditions.MarkFalse(obj, sourcev1.SourceVerifiedCondition, e.Reason, e.Err.Error())
|
||||
return sreconcile.ResultEmpty, e
|
||||
}
|
||||
|
||||
conditions.MarkTrue(obj, sourcev1.SourceVerifiedCondition, meta.SucceededReason, "OCI image %s with digest %s verified.", url, imgDigest)
|
||||
}
|
||||
layers, err := img.Layers()
|
||||
if err != nil {
|
||||
e := serror.NewGeneric(
|
||||
|
@ -484,6 +500,90 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
|
|||
return sreconcile.ResultSuccess, nil
|
||||
}
|
||||
|
||||
// verifyOCISourceSignature verifies the authenticity of the given image reference url. First, it tries to keyful approach
|
||||
// by looking at whether the given secret exists. Then, if it does not exist, it pushes a keyless approach for verification.
|
||||
func (r *OCIRepositoryReconciler) verifyOCISourceSignature(ctx context.Context, obj *sourcev1.OCIRepository, url string, keychain authn.Keychain) error {
|
||||
// Verify the image
|
||||
if obj.Spec.Verify != nil {
|
||||
provider := obj.Spec.Verify.Provider
|
||||
switch provider {
|
||||
case "cosign":
|
||||
// get the public keys from the given secret
|
||||
secretRef := obj.Spec.Verify.SecretRef
|
||||
|
||||
defaultCosignOciOpts := []soci.Options{
|
||||
soci.WithAuthnKeychain(keychain),
|
||||
soci.WithContext(ctx),
|
||||
}
|
||||
|
||||
ref, err := name.ParseReference(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if secretRef != nil {
|
||||
certSecretName := types.NamespacedName{
|
||||
Namespace: obj.Namespace,
|
||||
Name: secretRef.Name,
|
||||
}
|
||||
|
||||
var pubSecret corev1.Secret
|
||||
if err := r.Get(ctx, certSecretName, &pubSecret); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
signatureVerified := false
|
||||
// traverse all public keys and try to verify the signature
|
||||
// this is brute-force approach, but it is ok for now
|
||||
for k, data := range pubSecret.Data {
|
||||
// search for public keys in the secret
|
||||
if strings.HasSuffix(k, ".pub") {
|
||||
verifier, err := soci.New(append(defaultCosignOciOpts, soci.WithPublicKey(data))...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
signatures, _, err := verifier.VerifyImageSignatures(ctx, ref)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if signatures != nil {
|
||||
signatureVerified = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !signatureVerified {
|
||||
ctrl.LoggerFrom(ctx).Error(err, "none of the keys in the secret %s succeeded to verify for the image %s", secretRef.Name)
|
||||
return fmt.Errorf("no matching signatures were found for the image %s", url)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
} else {
|
||||
ctrl.LoggerFrom(ctx).Info("no secret reference is provided, trying to verify the image using keyless approach")
|
||||
verifier, err := soci.New(defaultCosignOciOpts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
signatures, _, err := verifier.VerifyImageSignatures(ctx, ref)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(signatures) > 0 {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseRepositoryURL validates and extracts the repository URL.
|
||||
func (r *OCIRepositoryReconciler) parseRepositoryURL(obj *sourcev1.OCIRepository) (string, error) {
|
||||
if !strings.HasPrefix(obj.Spec.URL, sourcev1.OCIRepositoryPrefix) {
|
||||
|
@ -651,7 +751,6 @@ func (r *OCIRepositoryReconciler) transport(ctx context.Context, obj *sourcev1.O
|
|||
tlsConfig.RootCAs = syscerts
|
||||
}
|
||||
return transport, nil
|
||||
|
||||
}
|
||||
|
||||
// oidcAuth generates the OIDC credential authenticator based on the specified cloud provider.
|
||||
|
@ -883,7 +982,8 @@ func (r *OCIRepositoryReconciler) garbageCollect(ctx context.Context, obj *sourc
|
|||
// that this is a simple log. While the debug log contains complete details
|
||||
// about the event.
|
||||
func (r *OCIRepositoryReconciler) eventLogf(ctx context.Context,
|
||||
obj runtime.Object, eventType string, reason string, messageFmt string, args ...interface{}) {
|
||||
obj runtime.Object, eventType, reason, messageFmt string, args ...interface{},
|
||||
) {
|
||||
msg := fmt.Sprintf(messageFmt, args...)
|
||||
// Log and emit event.
|
||||
if eventType == corev1.EventTypeWarning {
|
||||
|
|
|
@ -24,6 +24,9 @@ import (
|
|||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
coptions "github.com/sigstore/cosign/cmd/cosign/cli/options"
|
||||
"github.com/sigstore/cosign/cmd/cosign/cli/sign"
|
||||
"github.com/sigstore/cosign/pkg/cosign"
|
||||
"math/big"
|
||||
"net"
|
||||
"net/http"
|
||||
|
@ -1213,6 +1216,128 @@ func TestOCIRepository_getArtifactURL(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestOCIRepository_verifyOCISourceSignature(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
tmpDir := t.TempDir()
|
||||
regServer, err := setupRegistryServer(ctx, tmpDir, registryOptions{})
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
_, err = pushMultiplePodinfoImages(regServer.registryHost, "6.1.4", "6.1.5", "6.1.6")
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
url string
|
||||
reference *sourcev1.OCIRepositoryRef
|
||||
shouldSign bool
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "signed image should pass verification",
|
||||
reference: &sourcev1.OCIRepositoryRef{
|
||||
Tag: "6.1.4",
|
||||
},
|
||||
shouldSign: true,
|
||||
},
|
||||
{
|
||||
name: "unsigned image should not pass verification",
|
||||
reference: &sourcev1.OCIRepositoryRef{
|
||||
Tag: "6.1.5",
|
||||
},
|
||||
shouldSign: false,
|
||||
},
|
||||
}
|
||||
|
||||
builder := fakeclient.NewClientBuilder().WithScheme(testEnv.GetScheme())
|
||||
r := &OCIRepositoryReconciler{
|
||||
Client: builder.Build(),
|
||||
EventRecorder: record.NewFakeRecorder(32),
|
||||
Storage: testStorage,
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
obj := &sourcev1.OCIRepository{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
GenerateName: "artifact-url-",
|
||||
},
|
||||
Spec: sourcev1.OCIRepositorySpec{
|
||||
URL: fmt.Sprintf("oci://%s/podinfo", regServer.registryHost),
|
||||
Reference: tt.reference,
|
||||
Verify: &sourcev1.OCIRepositoryVerification{
|
||||
Provider: "cosign",
|
||||
SecretRef: &meta.LocalObjectReference{Name: "cosign-key"}},
|
||||
Interval: metav1.Duration{Duration: interval},
|
||||
Timeout: &metav1.Duration{Duration: timeout},
|
||||
},
|
||||
}
|
||||
|
||||
pf := func(b bool) ([]byte, error) {
|
||||
return []byte("foo"), nil
|
||||
}
|
||||
|
||||
keys, err := cosign.GenerateKeyPair(pf)
|
||||
if err != nil {
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
err = os.WriteFile("cosign.key", keys.PrivateBytes, 0600)
|
||||
if err != nil {
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
secret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "cosign-key",
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"cosign.pub": keys.PublicBytes,
|
||||
}}
|
||||
|
||||
err = r.Create(ctx, secret)
|
||||
if err != nil {
|
||||
g.Expect(err).NotTo(HaveOccurred())
|
||||
}
|
||||
|
||||
keychain, err := r.keychain(ctx, obj)
|
||||
if err != nil {
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
options := r.craneOptions(ctx, obj.Spec.Insecure)
|
||||
options = append(options, crane.WithAuthFromKeychain(keychain))
|
||||
url, err := r.getArtifactURL(obj, options)
|
||||
if err != nil {
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
if tt.shouldSign {
|
||||
|
||||
ko := coptions.KeyOpts{
|
||||
KeyRef: "cosign.key",
|
||||
PassFunc: pf,
|
||||
}
|
||||
|
||||
t.Logf("url: %s", url)
|
||||
|
||||
ro := &coptions.RootOptions{}
|
||||
err = sign.SignCmd(ro, ko, coptions.RegistryOptions{Keychain: keychain}, nil, []string{url}, "", "", false, "", "", "", false, false, "", false)
|
||||
if err != nil {
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
}
|
||||
|
||||
err = r.verifyOCISourceSignature(ctx, obj, url, keychain)
|
||||
if tt.wantErr {
|
||||
g.Expect(err).To(HaveOccurred())
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestOCIRepository_stalled(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
|
|
|
@ -1028,6 +1028,22 @@ The secret must be of type kubernetes.io/dockerconfigjson.</p>
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>verify</code><br>
|
||||
<em>
|
||||
<a href="#source.toolkit.fluxcd.io/v1beta2.OCIRepositoryVerification">
|
||||
OCIRepositoryVerification
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Verify contains the secret name containing the trusted public keys
|
||||
used to verify the signature and specifies which provider to use to check
|
||||
whether OCI image is authentic.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>serviceAccountName</code><br>
|
||||
<em>
|
||||
string
|
||||
|
@ -2772,6 +2788,22 @@ The secret must be of type kubernetes.io/dockerconfigjson.</p>
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>verify</code><br>
|
||||
<em>
|
||||
<a href="#source.toolkit.fluxcd.io/v1beta2.OCIRepositoryVerification">
|
||||
OCIRepositoryVerification
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Verify contains the secret name containing the trusted public keys
|
||||
used to verify the signature and specifies which provider to use to check
|
||||
whether OCI image is authentic.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>serviceAccountName</code><br>
|
||||
<em>
|
||||
string
|
||||
|
@ -2967,6 +2999,10 @@ github.com/fluxcd/pkg/apis/meta.ReconcileRequestStatus
|
|||
</div>
|
||||
<h3 id="source.toolkit.fluxcd.io/v1beta2.OCIRepositoryVerification">OCIRepositoryVerification
|
||||
</h3>
|
||||
<p>
|
||||
(<em>Appears on:</em>
|
||||
<a href="#source.toolkit.fluxcd.io/v1beta2.OCIRepositorySpec">OCIRepositorySpec</a>)
|
||||
</p>
|
||||
<p>OCIRepositoryVerification verifies the authenticity of an OCI Artifact</p>
|
||||
<div class="md-typeset__scrollwrap">
|
||||
<div class="md-typeset__table">
|
||||
|
@ -2999,6 +3035,7 @@ github.com/fluxcd/pkg/apis/meta.LocalObjectReference
|
|||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>SecretRef specifies the Kubernetes Secret containing the
|
||||
trusted public keys.</p>
|
||||
</td>
|
||||
|
|
165
go.mod
165
go.mod
|
@ -58,6 +58,8 @@ require (
|
|||
github.com/otiai10/copy v1.7.0
|
||||
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5
|
||||
github.com/prometheus/client_golang v1.13.0
|
||||
github.com/sigstore/cosign v1.11.1
|
||||
github.com/sigstore/sigstore v1.4.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
golang.org/x/crypto v0.0.0-20220824171710-5757bc0c5503
|
||||
golang.org/x/net v0.0.0-20220822230855-b0a4917ee28c
|
||||
|
@ -78,14 +80,15 @@ require (
|
|||
replace github.com/emicklei/go-restful => github.com/emicklei/go-restful v2.16.0+incompatible
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.102.1 // indirect
|
||||
bitbucket.org/creachadair/shell v0.0.7 // indirect
|
||||
cloud.google.com/go v0.103.0 // indirect
|
||||
cloud.google.com/go/compute v1.7.0 // indirect
|
||||
cloud.google.com/go/iam v0.3.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go v66.0.0+incompatible // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest/autorest v0.11.27 // indirect
|
||||
github.com/Azure/go-autorest/autorest v0.11.28 // indirect
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.20 // indirect
|
||||
github.com/Azure/go-autorest/autorest/azure/auth v0.5.11 // indirect
|
||||
github.com/Azure/go-autorest/autorest/azure/cli v0.4.5 // indirect
|
||||
|
@ -100,33 +103,47 @@ require (
|
|||
github.com/Masterminds/squirrel v1.5.3 // indirect
|
||||
github.com/Microsoft/go-winio v0.5.2 // indirect
|
||||
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d // indirect
|
||||
github.com/ThalesIgnite/crypto11 v1.2.5 // indirect
|
||||
github.com/acomagu/bufpipe v1.0.3 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
|
||||
github.com/aws/aws-sdk-go v1.44.84 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.16.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.15.14 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.12.9 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.14 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.16.11 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.17.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.12.14 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.12 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.18 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.12 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.19 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ecr v1.17.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.13.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.12 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.16.9 // indirect
|
||||
github.com/aws/smithy-go v1.12.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.12 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.16.13 // indirect
|
||||
github.com/aws/smithy-go v1.12.1 // indirect
|
||||
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20220706184558-ce46abcd012b // indirect
|
||||
github.com/benbjohnson/clock v1.1.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bgentry/speakeasy v0.1.0 // indirect
|
||||
github.com/blang/semver v3.5.1+incompatible // indirect
|
||||
github.com/bshuster-repo/logrus-logstash-hook v1.0.2 // indirect
|
||||
github.com/bugsnag/bugsnag-go v2.1.2+incompatible // indirect
|
||||
github.com/bugsnag/panicwrap v1.3.4 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
|
||||
github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect
|
||||
github.com/chrismellard/docker-credential-acr-env v0.0.0-20220327082430-c57b701bfc08 // indirect
|
||||
github.com/cloudflare/circl v1.1.0 // indirect
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490 // indirect
|
||||
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect
|
||||
github.com/containerd/containerd v1.6.6 // indirect
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.12.0 // indirect
|
||||
github.com/coreos/go-oidc/v3 v3.2.0 // indirect
|
||||
github.com/coreos/go-semver v0.3.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/cyberphone/json-canonicalization v0.0.0-20210823021906-dc406ceaf94b // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dimchansky/utfbom v1.1.1 // indirect
|
||||
github.com/docker/distribution v2.8.1+incompatible // indirect
|
||||
|
@ -139,47 +156,80 @@ require (
|
|||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.8.0 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v0.6.2 // indirect
|
||||
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
|
||||
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.1 // indirect
|
||||
github.com/fluxcd/pkg/apis/acl v0.1.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
github.com/fullstorydev/grpcurl v1.8.6 // indirect
|
||||
github.com/go-chi/chi v4.1.2+incompatible // indirect
|
||||
github.com/go-errors/errors v1.0.1 // indirect
|
||||
github.com/go-git/gcfg v1.5.0 // indirect
|
||||
github.com/go-gorp/gorp/v3 v3.0.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-logr/zapr v1.2.3 // indirect
|
||||
github.com/go-openapi/analysis v0.21.4 // indirect
|
||||
github.com/go-openapi/errors v0.20.3 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.0 // indirect
|
||||
github.com/go-openapi/swag v0.21.1 // indirect
|
||||
github.com/go-openapi/loads v0.21.2 // indirect
|
||||
github.com/go-openapi/runtime v0.24.1 // indirect
|
||||
github.com/go-openapi/spec v0.20.7 // indirect
|
||||
github.com/go-openapi/strfmt v0.21.3 // indirect
|
||||
github.com/go-openapi/swag v0.22.3 // indirect
|
||||
github.com/go-openapi/validate v0.22.0 // indirect
|
||||
github.com/go-piv/piv-go v1.10.0 // indirect
|
||||
github.com/go-playground/locales v0.14.0 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.0 // indirect
|
||||
github.com/go-playground/validator/v10 v10.11.0 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/gofrs/uuid v4.2.0+incompatible // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt v3.2.1+incompatible // indirect
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
|
||||
github.com/golang/glog v1.0.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/gomodule/redigo v1.8.2 // indirect
|
||||
github.com/google/btree v1.0.1 // indirect
|
||||
github.com/google/certificate-transparency-go v1.1.3 // indirect
|
||||
github.com/google/gnostic v0.6.9 // indirect
|
||||
github.com/google/go-cmp v0.5.8 // indirect
|
||||
github.com/google/go-containerregistry/pkg/authn/kubernetes v0.0.0-20220719135131-f79ec2192282 // indirect
|
||||
github.com/google/go-github/v45 v45.2.0 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/google/trillian v1.4.1 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.1.0 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.4.0 // indirect
|
||||
github.com/gorilla/handlers v1.5.1 // indirect
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
github.com/gosuri/uitable v0.0.4 // indirect
|
||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.2 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.1 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/huandu/xstrings v1.3.2 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/in-toto/in-toto-golang v0.3.4-0.20220709202702-fa494aaa0add // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/jedisct1/go-minisign v0.0.0-20211028175153-1c139d1cc84b // indirect
|
||||
github.com/jhump/protoreflect v1.12.0 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/jmoiron/sqlx v1.3.5 // indirect
|
||||
github.com/jonboulle/clockwork v0.3.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
|
||||
|
@ -189,18 +239,23 @@ require (
|
|||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/letsencrypt/boulder v0.0.0-20220723181115-27de4befb95e // indirect
|
||||
github.com/lib/pq v1.10.6 // indirect
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
|
||||
github.com/magiconair/properties v1.8.6 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
||||
github.com/miekg/pkcs11 v1.1.1 // indirect
|
||||
github.com/minio/md5-simd v1.1.2 // indirect
|
||||
github.com/minio/sha256-simd v1.0.0 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/go-wordwrap v1.0.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/moby/locker v1.0.1 // indirect
|
||||
github.com/moby/spdystream v0.2.0 // indirect
|
||||
|
@ -210,8 +265,13 @@ require (
|
|||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/oklog/ulid v1.3.1 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.3-0.20220729202839-6ad7100eb087 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.1 // indirect
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
|
@ -219,42 +279,94 @@ require (
|
|||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.37.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/rs/xid v1.4.0 // indirect
|
||||
github.com/rubenv/sql-migrate v1.1.2 // indirect
|
||||
github.com/russross/blackfriday v1.6.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sassoftware/relic v0.0.0-20210427151427-dfb082b79b74 // indirect
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.4.0 // indirect
|
||||
github.com/segmentio/ksuid v1.0.4 // indirect
|
||||
github.com/sergi/go-diff v1.2.0 // indirect
|
||||
github.com/shibumi/go-pathspec v1.3.0 // indirect
|
||||
github.com/shopspring/decimal v1.2.0 // indirect
|
||||
github.com/sigstore/fulcio v0.5.3 // indirect
|
||||
github.com/sigstore/rekor v0.11.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.0 // indirect
|
||||
github.com/spf13/cast v1.4.1 // indirect
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
|
||||
github.com/soheilhy/cmux v0.1.5 // indirect
|
||||
github.com/spf13/afero v1.8.2 // indirect
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
github.com/spf13/cobra v1.5.0 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/viper v1.12.0 // indirect
|
||||
github.com/spiffe/go-spiffe/v2 v2.1.1 // indirect
|
||||
github.com/stretchr/testify v1.8.0 // indirect
|
||||
github.com/subosito/gotenv v1.3.0 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
|
||||
github.com/tent/canonical-json-go v0.0.0-20130607151641-96e4ba3a7613 // indirect
|
||||
github.com/thales-e-security/pool v0.0.2 // indirect
|
||||
github.com/theupdateframework/go-tuf v0.3.1 // indirect
|
||||
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 // indirect
|
||||
github.com/transparency-dev/merkle v0.0.1 // indirect
|
||||
github.com/urfave/cli v1.22.7 // indirect
|
||||
github.com/vbatts/tar-split v0.11.2 // indirect
|
||||
github.com/xanzy/go-gitlab v0.73.1 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.1 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect
|
||||
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect
|
||||
github.com/yvasiyarov/go-metrics v0.0.0-20150112132944-c25f46c4b940 // indirect
|
||||
github.com/yvasiyarov/gorelic v0.0.7 // indirect
|
||||
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20160601141957-9c099fbc30e9 // indirect
|
||||
github.com/zeebo/errs v1.2.2 // indirect
|
||||
go.etcd.io/bbolt v1.3.6 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.6.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.6.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/client/v2 v2.306.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.6.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/etcdctl/v3 v3.6.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/etcdutl/v3 v3.6.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/pkg/v3 v3.6.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/raft/v3 v3.6.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/server/v3 v3.6.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/tests/v3 v3.6.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/v3 v3.6.0-alpha.0 // indirect
|
||||
go.mongodb.org/mongo-driver v1.10.1 // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.28.0 // indirect
|
||||
go.opentelemetry.io/otel v1.7.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.7.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.7.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.7.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.7.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.7.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v0.16.0 // indirect
|
||||
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
go.uber.org/multierr v1.8.0 // indirect
|
||||
go.uber.org/zap v1.23.0 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094 // indirect
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect
|
||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect
|
||||
golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b // indirect
|
||||
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect
|
||||
golang.org/x/tools v0.1.12 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220720214146-176da50484ac // indirect
|
||||
google.golang.org/genproto v0.0.0-20220805133916-01dd62135a58 // indirect
|
||||
google.golang.org/grpc v1.48.0 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.66.6 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
@ -269,5 +381,6 @@ require (
|
|||
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
|
||||
sigs.k8s.io/kustomize/api v0.11.4 // indirect
|
||||
sigs.k8s.io/kustomize/kyaml v0.13.6 // indirect
|
||||
sigs.k8s.io/release-utils v0.7.3 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
|
||||
)
|
||||
|
|
|
@ -165,3 +165,12 @@ echo "Run HelmChart from OCI registry tests"
|
|||
kubectl -n source-system apply -f "${ROOT_DIR}/config/testdata/helmchart-from-oci/source.yaml"
|
||||
kubectl -n source-system wait helmrepository/podinfo --for=condition=ready --timeout=1m
|
||||
kubectl -n source-system wait helmchart/podinfo --for=condition=ready --timeout=1m
|
||||
|
||||
echo "Run OCIRepository verify tests"
|
||||
kubectl -n source-system apply -f "${ROOT_DIR}/config/testdata/ocirepository/signed-with-key.yaml"
|
||||
kubectl -n source-system apply -f "${ROOT_DIR}/config/testdata/ocirepository/signed-with-keyless.yaml"
|
||||
curl -sSLo cosign.pub https://raw.githubusercontent.com/stefanprodan/podinfo/master/.cosign/cosign.pub
|
||||
kubectl -n source-system create secret generic cosign-key --from-file=cosign.pub --dry-run=client -o yaml | kubectl apply -f -
|
||||
|
||||
kubectl -n source-system wait ocirepository/podinfo-deploy-signed-with-key --for=condition=ready --timeout=1m
|
||||
kubectl -n source-system wait ocirepository/podinfo-deploy-signed-with-keyless --for=condition=ready --timeout=1m
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
Copyright 2022 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package oci
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto"
|
||||
"fmt"
|
||||
"github.com/google/go-containerregistry/pkg/authn"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
"github.com/sigstore/cosign/cmd/cosign/cli/fulcio"
|
||||
"github.com/sigstore/cosign/cmd/cosign/cli/rekor"
|
||||
ociremote "github.com/sigstore/cosign/pkg/oci/remote"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
coptions "github.com/sigstore/cosign/cmd/cosign/cli/options"
|
||||
"github.com/sigstore/cosign/pkg/cosign"
|
||||
"github.com/sigstore/cosign/pkg/oci"
|
||||
"github.com/sigstore/sigstore/pkg/cryptoutils"
|
||||
"github.com/sigstore/sigstore/pkg/signature"
|
||||
)
|
||||
|
||||
// options is a struct that holds options for verifier.
|
||||
type options struct {
|
||||
PublicKey []byte
|
||||
Keychain authn.Keychain
|
||||
Context context.Context
|
||||
}
|
||||
|
||||
// Options is a function that configures the options applied to a Verifier.
|
||||
type Options func(opts *options)
|
||||
|
||||
// WithPublicKey sets the public key.
|
||||
func WithPublicKey(publicKey []byte) Options {
|
||||
return func(opts *options) {
|
||||
opts.PublicKey = publicKey
|
||||
}
|
||||
}
|
||||
|
||||
func WithAuthnKeychain(keychain authn.Keychain) Options {
|
||||
return func(opts *options) {
|
||||
opts.Keychain = keychain
|
||||
}
|
||||
}
|
||||
|
||||
func WithContext(ctx context.Context) Options {
|
||||
return func(opts *options) {
|
||||
opts.Context = ctx
|
||||
}
|
||||
}
|
||||
|
||||
// Verifier is a struct which is responsible for executing verification logic.
|
||||
type Verifier struct {
|
||||
opts *cosign.CheckOpts
|
||||
}
|
||||
|
||||
// New initializes a new Verifier.
|
||||
func New(opts ...Options) (*Verifier, error) {
|
||||
o := options{}
|
||||
for _, opt := range opts {
|
||||
opt(&o)
|
||||
}
|
||||
|
||||
checkOpts := &cosign.CheckOpts{}
|
||||
|
||||
ro := coptions.RegistryOptions{}
|
||||
co, err := ro.ClientOpts(o.Context)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if o.Keychain != nil {
|
||||
co = append(co, ociremote.WithRemoteOptions(remote.WithAuthFromKeychain(o.Keychain)))
|
||||
}
|
||||
|
||||
checkOpts.RegistryClientOpts = co
|
||||
|
||||
// If a public key is provided, it will use it to verify the signature.
|
||||
// If there is no public key provided, it will try keyless verification.
|
||||
// https://github.com/sigstore/cosign/blob/main/KEYLESS.md.
|
||||
if len(o.PublicKey) > 0 {
|
||||
pubKeyRaw, err := cryptoutils.UnmarshalPEMToPublicKey(o.PublicKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
checkOpts.SigVerifier, err = signature.LoadVerifier(pubKeyRaw, crypto.SHA256)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
rcerts, err := fulcio.GetRoots()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get Fulcio root certs: %w", err)
|
||||
}
|
||||
checkOpts.RootCerts = rcerts
|
||||
|
||||
icerts, err := fulcio.GetIntermediates()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get Fulcio intermediate certs: %w", err)
|
||||
}
|
||||
checkOpts.IntermediateCerts = icerts
|
||||
|
||||
rc, err := rekor.NewClient(coptions.DefaultRekorURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to create Rekor client: %w", err)
|
||||
}
|
||||
checkOpts.RekorClient = rc
|
||||
}
|
||||
|
||||
return &Verifier{
|
||||
opts: checkOpts,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// VerifyImageSignatures verify the authenticity of the given ref OCI image.
|
||||
func (v *Verifier) VerifyImageSignatures(ctx context.Context, ref name.Reference) ([]oci.Signature, bool, error) {
|
||||
return cosign.VerifyImageSignatures(ctx, ref, v.opts)
|
||||
}
|
Loading…
Reference in New Issue