Skip to content

Commit 22aee8d

Browse files
authored
Merge pull request #1096 from fluxcd/cosign-v2
Update cosign to v2
2 parents 7b9c53a + 0ec4978 commit 22aee8d

File tree

8 files changed

+263
-1003
lines changed

8 files changed

+263
-1003
lines changed

go.mod

Lines changed: 54 additions & 98 deletions
Large diffs are not rendered by default.

go.sum

Lines changed: 123 additions & 852 deletions
Large diffs are not rendered by default.

internal/controller/helmchart_controller_test.go

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323
"errors"
2424
"fmt"
2525
"io"
26-
"io/ioutil"
2726
"net/http"
2827
"os"
2928
"path"
@@ -34,9 +33,9 @@ import (
3433
"time"
3534

3635
. "github.com/onsi/gomega"
37-
coptions "github.com/sigstore/cosign/cmd/cosign/cli/options"
38-
"github.com/sigstore/cosign/cmd/cosign/cli/sign"
39-
"github.com/sigstore/cosign/pkg/cosign"
36+
coptions "github.com/sigstore/cosign/v2/cmd/cosign/cli/options"
37+
"github.com/sigstore/cosign/v2/cmd/cosign/cli/sign"
38+
"github.com/sigstore/cosign/v2/pkg/cosign"
4039
hchart "helm.sh/helm/v3/pkg/chart"
4140
"helm.sh/helm/v3/pkg/chart/loader"
4241
helmreg "helm.sh/helm/v3/pkg/registry"
@@ -1058,7 +1057,8 @@ func TestHelmChartReconciler_buildFromOCIHelmRepository(t *testing.T) {
10581057
)
10591058

10601059
// Load a test chart
1061-
chartData, err := ioutil.ReadFile(chartPath)
1060+
chartData, err := os.ReadFile(chartPath)
1061+
g.Expect(err).NotTo(HaveOccurred())
10621062

10631063
// Upload the test chart
10641064
metadata, err := loadTestChartToOCI(chartData, chartPath, testRegistryServer)
@@ -2333,16 +2333,16 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_authStrategy(t *testing.T) {
23332333

23342334
builder := fakeclient.NewClientBuilder().WithScheme(testEnv.GetScheme())
23352335
workspaceDir := t.TempDir()
2336-
server, err := setupRegistryServer(ctx, workspaceDir, tt.registryOpts)
23372336

2337+
server, err := setupRegistryServer(ctx, workspaceDir, tt.registryOpts)
23382338
g.Expect(err).NotTo(HaveOccurred())
23392339

23402340
// Load a test chart
2341-
chartData, err := ioutil.ReadFile(chartPath)
2341+
chartData, err := os.ReadFile(chartPath)
2342+
g.Expect(err).ToNot(HaveOccurred())
23422343

23432344
// Upload the test chart
23442345
metadata, err := loadTestChartToOCI(chartData, chartPath, server)
2345-
g.Expect(err).NotTo(HaveOccurred())
23462346
g.Expect(err).ToNot(HaveOccurred())
23472347

23482348
repo := &helmv1.HelmRepository{
@@ -2452,7 +2452,8 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignature(t *testing.T
24522452
)
24532453

24542454
// Load a test chart
2455-
chartData, err := ioutil.ReadFile(chartPath)
2455+
chartData, err := os.ReadFile(chartPath)
2456+
g.Expect(err).ToNot(HaveOccurred())
24562457

24572458
// Upload the test chart
24582459
metadata, err := loadTestChartToOCI(chartData, chartPath, server)
@@ -2504,10 +2505,10 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignature(t *testing.T
25042505
},
25052506
want: sreconcile.ResultEmpty,
25062507
wantErr: true,
2507-
wantErrMsg: "chart verification error: failed to verify <url>: no matching signatures:",
2508+
wantErrMsg: "chart verification error: failed to verify <url>: no signatures found for image",
25082509
assertConditions: []metav1.Condition{
2509-
*conditions.TrueCondition(sourcev1.BuildFailedCondition, "ChartVerificationError", "chart verification error: failed to verify <url>: no matching signatures:"),
2510-
*conditions.FalseCondition(sourcev1.SourceVerifiedCondition, sourcev1.VerificationError, "chart verification error: failed to verify <url>: no matching signatures:"),
2510+
*conditions.TrueCondition(sourcev1.BuildFailedCondition, "ChartVerificationError", "chart verification error: failed to verify <url>: no signatures found for image"),
2511+
*conditions.FalseCondition(sourcev1.SourceVerifiedCondition, sourcev1.VerificationError, "chart verification error: failed to verify <url>: no signatures found for image"),
25112512
},
25122513
},
25132514
{
@@ -2522,8 +2523,8 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignature(t *testing.T
25222523
want: sreconcile.ResultEmpty,
25232524
wantErr: true,
25242525
assertConditions: []metav1.Condition{
2525-
*conditions.TrueCondition(sourcev1.BuildFailedCondition, "ChartVerificationError", "chart verification error: failed to verify <url>: no matching signatures:"),
2526-
*conditions.FalseCondition(sourcev1.SourceVerifiedCondition, sourcev1.VerificationError, "chart verification error: failed to verify <url>: no matching signatures:"),
2526+
*conditions.TrueCondition(sourcev1.BuildFailedCondition, "ChartVerificationError", "chart verification error: failed to verify <url>: no signatures found for image"),
2527+
*conditions.FalseCondition(sourcev1.SourceVerifiedCondition, sourcev1.VerificationError, "chart verification error: failed to verify <url>: no signatures found for image"),
25272528
},
25282529
},
25292530
{
@@ -2633,11 +2634,13 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignature(t *testing.T
26332634
Timeout: timeout,
26342635
}
26352636

2636-
err = sign.SignCmd(ro, ko, coptions.RegistryOptions{Keychain: oci.Anonymous{}},
2637-
nil, []string{fmt.Sprintf("%s/testrepo/%s:%s", server.registryHost, metadata.Name, metadata.Version)}, "",
2638-
"", true, "",
2639-
"", "", false,
2640-
false, "", false)
2637+
err = sign.SignCmd(ro, ko, coptions.SignOptions{
2638+
Upload: true,
2639+
SkipConfirmation: true,
2640+
TlogUpload: false,
2641+
Registry: coptions.RegistryOptions{Keychain: oci.Anonymous{}, AllowInsecure: true},
2642+
},
2643+
[]string{fmt.Sprintf("%s/testrepo/%s:%s", server.registryHost, metadata.Name, metadata.Version)})
26412644
g.Expect(err).ToNot(HaveOccurred())
26422645
}
26432646

@@ -2694,7 +2697,7 @@ func loadTestChartToOCI(chartData []byte, chartPath string, server *registryClie
26942697
}
26952698

26962699
// Load a test chart
2697-
chartData, err = ioutil.ReadFile(chartPath)
2700+
chartData, err = os.ReadFile(chartPath)
26982701
if err != nil {
26992702
return nil, err
27002703
}

internal/controller/ocirepository_controller.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ import (
3131
"time"
3232

3333
"github.com/Masterminds/semver/v3"
34-
soci "github.com/fluxcd/source-controller/internal/oci"
3534
"github.com/google/go-containerregistry/pkg/authn"
3635
"github.com/google/go-containerregistry/pkg/authn/k8schain"
3736
"github.com/google/go-containerregistry/pkg/crane"
@@ -69,6 +68,7 @@ import (
6968
sourcev1 "github.com/fluxcd/source-controller/api/v1"
7069
ociv1 "github.com/fluxcd/source-controller/api/v1beta2"
7170
serror "github.com/fluxcd/source-controller/internal/error"
71+
soci "github.com/fluxcd/source-controller/internal/oci"
7272
sreconcile "github.com/fluxcd/source-controller/internal/reconcile"
7373
"github.com/fluxcd/source-controller/internal/reconcile/summarize"
7474
"github.com/fluxcd/source-controller/internal/util"

internal/controller/ocirepository_controller_test.go

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ import (
4343
gcrv1 "github.com/google/go-containerregistry/pkg/v1"
4444
"github.com/google/go-containerregistry/pkg/v1/mutate"
4545
. "github.com/onsi/gomega"
46-
coptions "github.com/sigstore/cosign/cmd/cosign/cli/options"
47-
"github.com/sigstore/cosign/cmd/cosign/cli/sign"
48-
"github.com/sigstore/cosign/pkg/cosign"
46+
coptions "github.com/sigstore/cosign/v2/cmd/cosign/cli/options"
47+
"github.com/sigstore/cosign/v2/cmd/cosign/cli/sign"
48+
"github.com/sigstore/cosign/v2/pkg/cosign"
4949
corev1 "k8s.io/api/core/v1"
5050
apierrors "k8s.io/apimachinery/pkg/api/errors"
5151
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -1095,7 +1095,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature(t *testing.T) {
10951095
assertConditions: []metav1.Condition{
10961096
*conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "building artifact: new revision '<revision>' for '<url>'"),
10971097
*conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "building artifact: new revision '<revision>' for '<url>'"),
1098-
*conditions.FalseCondition(sourcev1.SourceVerifiedCondition, sourcev1.VerificationError, "failed to verify the signature using provider '<provider> keyless': no matching signatures"),
1098+
*conditions.FalseCondition(sourcev1.SourceVerifiedCondition, sourcev1.VerificationError, "failed to verify the signature using provider '<provider> keyless': no signatures found for image"),
10991099
},
11001100
},
11011101
{
@@ -1193,6 +1193,8 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature(t *testing.T) {
11931193

11941194
for _, tt := range tests {
11951195
t.Run(tt.name, func(t *testing.T) {
1196+
g := NewWithT(t)
1197+
11961198
obj := &ociv1.OCIRepository{
11971199
ObjectMeta: metav1.ObjectMeta{
11981200
GenerateName: "verify-oci-source-signature-",
@@ -1239,11 +1241,14 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature(t *testing.T) {
12391241
ro := &coptions.RootOptions{
12401242
Timeout: timeout,
12411243
}
1242-
err = sign.SignCmd(ro, ko, coptions.RegistryOptions{Keychain: keychain},
1243-
nil, []string{artifactURL}, "",
1244-
"", true, "",
1245-
"", "", false,
1246-
false, "", true)
1244+
err = sign.SignCmd(ro, ko, coptions.SignOptions{
1245+
Upload: true,
1246+
SkipConfirmation: true,
1247+
TlogUpload: false,
1248+
1249+
Registry: coptions.RegistryOptions{Keychain: keychain, AllowInsecure: true},
1250+
}, []string{artifactURL})
1251+
12471252
g.Expect(err).ToNot(HaveOccurred())
12481253
}
12491254

internal/controller/suite_test.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import (
2121
"context"
2222
"fmt"
2323
"io"
24-
"io/ioutil"
2524
"math/rand"
2625
"os"
2726
"path/filepath"
@@ -164,8 +163,7 @@ func setupRegistryServer(ctx context.Context, workspaceDir string, opts registry
164163
}
165164

166165
htpasswdPath := filepath.Join(workspaceDir, testRegistryHtpasswdFileBasename)
167-
err = ioutil.WriteFile(htpasswdPath, []byte(fmt.Sprintf("%s:%s\n", testRegistryUsername, string(pwBytes))), 0644)
168-
if err != nil {
166+
if err = os.WriteFile(htpasswdPath, []byte(fmt.Sprintf("%s:%s\n", testRegistryUsername, string(pwBytes))), 0644); err != nil {
169167
return nil, fmt.Errorf("failed to create htpasswd file: %s", err)
170168
}
171169

internal/oci/verifier.go

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,14 @@ import (
2121
"crypto"
2222
"fmt"
2323

24-
"github.com/google/go-containerregistry/pkg/v1/remote"
25-
"github.com/sigstore/cosign/cmd/cosign/cli/fulcio"
26-
"github.com/sigstore/cosign/cmd/cosign/cli/rekor"
27-
ociremote "github.com/sigstore/cosign/pkg/oci/remote"
28-
2924
"github.com/google/go-containerregistry/pkg/name"
30-
coptions "github.com/sigstore/cosign/cmd/cosign/cli/options"
31-
"github.com/sigstore/cosign/pkg/cosign"
32-
"github.com/sigstore/cosign/pkg/oci"
25+
"github.com/google/go-containerregistry/pkg/v1/remote"
26+
"github.com/sigstore/cosign/v2/cmd/cosign/cli/fulcio"
27+
coptions "github.com/sigstore/cosign/v2/cmd/cosign/cli/options"
28+
"github.com/sigstore/cosign/v2/cmd/cosign/cli/rekor"
29+
"github.com/sigstore/cosign/v2/pkg/cosign"
30+
"github.com/sigstore/cosign/v2/pkg/oci"
31+
ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote"
3332
"github.com/sigstore/sigstore/pkg/cryptoutils"
3433
"github.com/sigstore/sigstore/pkg/signature"
3534
)
@@ -93,6 +92,11 @@ func NewCosignVerifier(ctx context.Context, opts ...Options) (*CosignVerifier, e
9392
// If there is no public key provided, it will try keyless verification.
9493
// https://github.com/sigstore/cosign/blob/main/KEYLESS.md.
9594
if len(o.PublicKey) > 0 {
95+
checkOpts.Offline = true
96+
// TODO(hidde): this is an oversight in our implementation. As it is
97+
// theoretically possible to have a custom PK, without disabling tlog.
98+
checkOpts.IgnoreTlog = true
99+
96100
pubKeyRaw, err := cryptoutils.UnmarshalPEMToPublicKey(o.PublicKey)
97101
if err != nil {
98102
return nil, err
@@ -103,23 +107,31 @@ func NewCosignVerifier(ctx context.Context, opts ...Options) (*CosignVerifier, e
103107
return nil, err
104108
}
105109
} else {
106-
rcerts, err := fulcio.GetRoots()
110+
checkOpts.RekorClient, err = rekor.NewClient(coptions.DefaultRekorURL)
107111
if err != nil {
108-
return nil, fmt.Errorf("unable to get Fulcio root certs: %w", err)
112+
return nil, fmt.Errorf("unable to create Rekor client: %w", err)
109113
}
110-
checkOpts.RootCerts = rcerts
111114

112-
icerts, err := fulcio.GetIntermediates()
113-
if err != nil {
114-
return nil, fmt.Errorf("unable to get Fulcio intermediate certs: %w", err)
115+
// This performs an online fetch of the Rekor public keys, but this is needed
116+
// for verifying tlog entries (both online and offline).
117+
// TODO(hidde): above note is important to keep in mind when we implement
118+
// "offline" tlog above.
119+
if checkOpts.RekorPubKeys, err = cosign.GetRekorPubs(ctx); err != nil {
120+
return nil, fmt.Errorf("unable to get Rekor public keys: %w", err)
115121
}
116-
checkOpts.IntermediateCerts = icerts
117122

118-
rc, err := rekor.NewClient(coptions.DefaultRekorURL)
123+
checkOpts.CTLogPubKeys, err = cosign.GetCTLogPubs(ctx)
119124
if err != nil {
120-
return nil, fmt.Errorf("unable to create Rekor client: %w", err)
125+
return nil, fmt.Errorf("unable to get CTLog public keys: %w", err)
126+
}
127+
128+
if checkOpts.RootCerts, err = fulcio.GetRoots(); err != nil {
129+
return nil, fmt.Errorf("unable to get Fulcio root certs: %w", err)
130+
}
131+
132+
if checkOpts.IntermediateCerts, err = fulcio.GetIntermediates(); err != nil {
133+
return nil, fmt.Errorf("unable to get Fulcio intermediate certs: %w", err)
121134
}
122-
checkOpts.RekorClient = rc
123135
}
124136

125137
return &CosignVerifier{
@@ -129,7 +141,17 @@ func NewCosignVerifier(ctx context.Context, opts ...Options) (*CosignVerifier, e
129141

130142
// VerifyImageSignatures verify the authenticity of the given ref OCI image.
131143
func (v *CosignVerifier) VerifyImageSignatures(ctx context.Context, ref name.Reference) ([]oci.Signature, bool, error) {
132-
return cosign.VerifyImageSignatures(ctx, ref, v.opts)
144+
opts := v.opts
145+
146+
// TODO: expose the match conditions in the CRD
147+
opts.Identities = []cosign.Identity{
148+
{
149+
IssuerRegExp: ".*",
150+
SubjectRegExp: ".*",
151+
},
152+
}
153+
154+
return cosign.VerifyImageSignatures(ctx, ref, opts)
133155
}
134156

135157
// Verify verifies the authenticity of the given ref OCI image.

pkg/azure/blob.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import (
3838
ctrl "sigs.k8s.io/controller-runtime"
3939

4040
"github.com/fluxcd/pkg/masktoken"
41+
4142
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
4243
)
4344

@@ -422,7 +423,11 @@ func chainCredentialWithSecret(secret *corev1.Secret) (azcore.TokenCredential, e
422423
if file, ok := os.LookupEnv("AZURE_FEDERATED_TOKEN_FILE"); ok {
423424
if _, ok := os.LookupEnv("AZURE_AUTHORITY_HOST"); ok {
424425
if tenantID, ok := os.LookupEnv("AZURE_TENANT_ID"); ok {
425-
if token, _ := azidentity.NewWorkloadIdentityCredential(tenantID, clientID, file, &azidentity.WorkloadIdentityCredentialOptions{}); token != nil {
426+
if token, _ := azidentity.NewWorkloadIdentityCredential(&azidentity.WorkloadIdentityCredentialOptions{
427+
ClientID: clientID,
428+
TenantID: tenantID,
429+
TokenFilePath: file,
430+
}); token != nil {
426431
creds = append(creds, token)
427432
}
428433
}

0 commit comments

Comments
 (0)