From ffdad0f1dc952dab17c53fed5bbe53dde2439db7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 10:04:10 -0700 Subject: [PATCH 1/4] chore: Bump goreleaser/goreleaser-action from 5.1.0 to 6.0.0 (#1544) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2066b02b6..de5ba7e14 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,7 +26,7 @@ jobs: go-version: '1.21' - name: Goreleaser - uses: goreleaser/goreleaser-action@5742e2a039330cbb23ebf35f046f814d4c6ff811 # v5.1.0 + uses: goreleaser/goreleaser-action@286f3b13b1b49da4ac219696163fb8c1c93e1200 # v6.0.0 with: version: '1.18.0' args: release --rm-dist From 86376057d4f9372eba6c19561b0dd3ac73239f32 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 17:30:35 +0000 Subject: [PATCH 2/4] chore: Bump github/codeql-action from 3.25.7 to 3.25.8 (#1545) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 13faa4c48..9cfe0976e 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -33,7 +33,7 @@ jobs: with: go-version: "1.21" - name: Initialize CodeQL - uses: github/codeql-action/init@f079b8493333aace61c81488f8bd40919487bd9f # tag=v3.25.7 + uses: github/codeql-action/init@2e230e8fe0ad3a14a340ad0815ddb96d599d2aff # tag=v3.25.8 with: languages: go - name: Run tidy @@ -41,4 +41,4 @@ jobs: - name: Build CLI run: make build - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@f079b8493333aace61c81488f8bd40919487bd9f # tag=v3.25.7 + uses: github/codeql-action/analyze@2e230e8fe0ad3a14a340ad0815ddb96d599d2aff # tag=v3.25.8 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 75fc86c26..a0f9f0d92 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -48,6 +48,6 @@ jobs: retention-days: 5 - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@f079b8493333aace61c81488f8bd40919487bd9f # tag=v3.25.7 + uses: github/codeql-action/upload-sarif@2e230e8fe0ad3a14a340ad0815ddb96d599d2aff # tag=v3.25.8 with: sarif_file: results.sarif From 70389cf2122d08c6b64141fcb9b4f155d06422c0 Mon Sep 17 00:00:00 2001 From: Akash Singhal Date: Wed, 5 Jun 2024 19:02:54 -0700 Subject: [PATCH 3/4] feat: add cosign keyless support to trust policy (#1503) --- Makefile | 2 + charts/ratify/README.md | 7 + charts/ratify/templates/_helpers.tpl | 16 ++ charts/ratify/templates/verifier.yaml | 12 +- charts/ratify/values.yaml | 9 + .../config_v1beta1_verifier_cosign.yaml | 3 +- ...beta1_verifier_cosign_keyless_legacy.yaml} | 0 .../config_v1beta1_verifier_cosign.yaml | 1 + pkg/verifier/cosign/cosign.go | 164 ++++++++++---- pkg/verifier/cosign/cosign_test.go | 212 +++++++++++++----- pkg/verifier/cosign/trustpolicies_test.go | 76 +++---- pkg/verifier/cosign/trustpolicy.go | 79 +++++-- pkg/verifier/cosign/trustpolicy_test.go | 149 ++++++++++-- test/bats/base-test.bats | 22 +- .../config_v1beta1_verifier_cosign_akv.yaml | 3 +- ...onfig_v1beta1_verifier_cosign_keyless.yaml | 15 ++ 16 files changed, 585 insertions(+), 185 deletions(-) rename config/samples/clustered/verifier/{config_v1beta1_verifier_cosign_keyless.yaml => config_v1beta1_verifier_cosign_keyless_legacy.yaml} (100%) create mode 100644 test/bats/tests/config/config_v1beta1_verifier_cosign_keyless.yaml diff --git a/Makefile b/Makefile index 7c16b2aa9..3801ecd55 100644 --- a/Makefile +++ b/Makefile @@ -592,6 +592,7 @@ e2e-helm-deploy-ratify: --set notationCerts[0]="$$(cat ~/.config/notation/localkeys/ratify-bats-test.crt)" \ --set cosignKeys[0]="$$(cat .staging/cosign/cosign.pub)" \ --set cosign.key="$$(cat .staging/cosign/cosign.pub)" \ + --set cosign.tLogVerify=false \ --set oras.useHttp=true \ --set-file dockerConfig="mount_config.json" \ --set logger.level=debug @@ -611,6 +612,7 @@ e2e-helm-deploy-ratify-without-tls-certs: --set notaryCert="$$(cat ~/.config/notation/localkeys/ratify-bats-test.crt)" \ --set cosign.key="$$(cat .staging/cosign/cosign.pub)" \ --set cosignKeys[0]="$$(cat .staging/cosign/cosign.pub)" \ + --set cosign.tLogVerify=false \ --set oras.useHttp=true \ --set-file dockerConfig="mount_config.json" \ --set logger.level=debug diff --git a/charts/ratify/README.md b/charts/ratify/README.md index 7684e2e0b..e99bb2993 100644 --- a/charts/ratify/README.md +++ b/charts/ratify/README.md @@ -51,6 +51,13 @@ Values marked `# DEPRECATED` in the `values.yaml` as well as **DEPRECATED** in t | cosignKeys | An array of public keys used to create inline key management providers used by Cosign verifier | `[]` | | cosign.enabled | Enables/disables cosign tag-based signature lookup in ORAS store. MUST be set to true for cosign verification. | `true` | | cosign.scopes | An array of scopes relevant to the single trust policy configured in Cosign verifier. A scope of '*' is a global wildcard character to represent all images apply. | `["*"]` | +| cosign.rekorURL | URL string reference to remote rekor server. If not specified, implementation will default to use Rekor public good instance `https://rekor.sigstore.dev`. | `` | +| cosign.tLogVerify | Enables/disables verification of presence of signature in Transparency log. | `true` | +| cosign.keyless.ctLogVerify | Enables/disables verification of presence of Secure Certificate Timestamp (SCT) in transparency log | `true` | +| cosign.keyless.certificateIdentity | String certificate identity used for exact identity match during verification. Either `certificateIdentity` or `certificateIdentityRegExp` MUST be defined, but both cannot be defined at together | `` | +| cosign.keyless.certificateIdentityRegExp | String certificate identity regular expression for identity matching during verification. Accepts the Go regular expression syntax described at https://golang.org/s/re2syntax. Either `certificateIdentity` or `certificateIdentityRegExp` MUST be defined, but both cannot be defined together | `` | +| cosign.keyless.certificateOIDCIssuer | String certificate OIDC issuer for exact issuer matching during verification. Either `certificateOIDCIssuer` or `certificateOIDCIssuerRegExp` MUST be defined, but both cannot be defined together | `` | +| cosign.keyless.certificateOIDCIssuerRegExp | String certificate OIDC issuer regular expression for issuer matching during verification. Accepts the Go regular expression syntax described at https://golang.org/s/re2syntax. Either `certificateOIDCIssuer` or `certificateOIDCIssuerRegExp` MUST be defined, but both cannot be defined together | `` | | vulnerabilityreport.enabled | Enables/disables installation of vulnerability report verifier | `false` | | vulnerabilityreport.passthrough | Enables/disables passthrough. All validation except `maximumAge` are disregarded and report content is added to verifier report | `false` | | vulnerabilityreport.schemaURL | URL for JSON schema to validate report against | `` | diff --git a/charts/ratify/templates/_helpers.tpl b/charts/ratify/templates/_helpers.tpl index e57008c31..cc56acb9e 100644 --- a/charts/ratify/templates/_helpers.tpl +++ b/charts/ratify/templates/_helpers.tpl @@ -146,4 +146,20 @@ Set the namespace exclusions for Assign {{- if and (ne .Release.Namespace $gkNamespace) (ne .Release.Namespace "kube-system") }} - {{ .Release.Namespace | quote}} {{- end }} +{{- end }} + +{{/* +Choose cosign legacy or not. Determined by if cosignKeys are provided or not +OR if azurekeyvault is enabled and keys are provided +OR if keyless is enabled and certificateIdentity, certificateIdentityRegExp, certificateOIDCIssuer, or certificateOIDCIssuerExp are provided +*/}} +{{- define "ratify.cosignLegacy" -}} +{{- $cosignKeysPresent := gt (len .Values.cosignKeys) 0 -}} +{{- $azureKeyVaultEnabled := .Values.azurekeyvault.enabled -}} +{{- $azureKeyVaultKeysPresent := gt (len .Values.azurekeyvault.keys) 0 -}} +{{- if or $cosignKeysPresent (and $azureKeyVaultEnabled $azureKeyVaultKeysPresent) .Values.cosign.keyless.certificateIdentity .Values.cosign.keyless.certificateIdentityRegExp .Values.cosign.keyless.certificateOIDCIssuer .Values.cosign.keyless.certificateOIDCIssuerExp -}} +false +{{- else }} +true +{{- end }} {{- end }} \ No newline at end of file diff --git a/charts/ratify/templates/verifier.yaml b/charts/ratify/templates/verifier.yaml index 367b7a124..2c7556ab1 100644 --- a/charts/ratify/templates/verifier.yaml +++ b/charts/ratify/templates/verifier.yaml @@ -50,7 +50,7 @@ spec: name: cosign artifactTypes: application/vnd.dev.cosign.artifact.sig.v1+json parameters: - {{- if or (gt (len .Values.cosignKeys) 0) (and .Values.azurekeyvault.enabled (gt (len .Values.azurekeyvault.keys) 0)) }} + {{- if (eq (include "ratify.cosignLegacy" .) "false") }} trustPolicies: - name: default version: 1.0.0 @@ -65,6 +65,16 @@ spec: {{- if and .Values.azurekeyvault.enabled (gt (len .Values.azurekeyvault.keys) 0) }} - provider: kmprovider-akv {{- end }} + tLogVerify: {{ .Values.cosign.tLogVerify }} + rekorURL: {{ .Values.cosign.rekorURL }} + {{- if or .Values.cosign.keyless.certificateIdentity .Values.cosign.keyless.certificateIdentityRegExp .Values.cosign.keyless.certificateOIDCIssuer .Values.cosign.keyless.certificateOIDCIssuerRegExp }} + keyless: + ctLogVerify: {{ .Values.cosign.keyless.ctLogVerify }} + certificateIdentity: {{ .Values.cosign.keyless.certificateIdentity }} + certificateIdentityRegExp: {{ .Values.cosign.keyless.certificateIdentityRegExp }} + certificateOIDCIssuer: {{ .Values.cosign.keyless.certificateOIDCIssuer }} + certificateOIDCIssuerRegExp: {{ .Values.cosign.keyless.certificateOIDCIssuerRegExp }} + {{- end }} {{- else }} key: /usr/local/ratify-certs/cosign/cosign.pub {{- end }} diff --git a/charts/ratify/values.yaml b/charts/ratify/values.yaml index 7d97c5489..b1ad2efe4 100644 --- a/charts/ratify/values.yaml +++ b/charts/ratify/values.yaml @@ -16,6 +16,15 @@ cosign: enabled: true scopes: ["*"] # corresponds to a single trust policy key: "" # DEPRECATED: Use cosignKeys instead + rekorURL: "" + tLogVerify: true + keyless: + ctLogVerify: true + certificateIdentity: "" + certificateIdentityRegExp: "" + certificateOIDCIssuer: "" + certificateOIDCIssuerRegExp: "" + vulnerabilityreport: enabled: false passthrough: false diff --git a/config/samples/clustered/verifier/config_v1beta1_verifier_cosign.yaml b/config/samples/clustered/verifier/config_v1beta1_verifier_cosign.yaml index 713f5713e..89719fe6d 100644 --- a/config/samples/clustered/verifier/config_v1beta1_verifier_cosign.yaml +++ b/config/samples/clustered/verifier/config_v1beta1_verifier_cosign.yaml @@ -11,4 +11,5 @@ spec: scopes: - "*" keys: - - provider: ratify-cosign-inline-key-0 \ No newline at end of file + - provider: ratify-cosign-inline-key-0 + tLogVerify: false \ No newline at end of file diff --git a/config/samples/clustered/verifier/config_v1beta1_verifier_cosign_keyless.yaml b/config/samples/clustered/verifier/config_v1beta1_verifier_cosign_keyless_legacy.yaml similarity index 100% rename from config/samples/clustered/verifier/config_v1beta1_verifier_cosign_keyless.yaml rename to config/samples/clustered/verifier/config_v1beta1_verifier_cosign_keyless_legacy.yaml diff --git a/config/samples/namespaced/verifier/config_v1beta1_verifier_cosign.yaml b/config/samples/namespaced/verifier/config_v1beta1_verifier_cosign.yaml index dfb4597c9..44b4bda95 100644 --- a/config/samples/namespaced/verifier/config_v1beta1_verifier_cosign.yaml +++ b/config/samples/namespaced/verifier/config_v1beta1_verifier_cosign.yaml @@ -12,3 +12,4 @@ spec: - "*" keys: - provider: default/ratify-cosign-inline-key-0 + tLogVerify: false diff --git a/pkg/verifier/cosign/cosign.go b/pkg/verifier/cosign/cosign.go index 1f365aa9a..34b0e3cb4 100644 --- a/pkg/verifier/cosign/cosign.go +++ b/pkg/verifier/cosign/cosign.go @@ -79,6 +79,7 @@ type LegacyExtension struct { // where each entry corresponds to a single signature verified type Extension struct { SignatureExtension []cosignExtensionList `json:"signatures,omitempty"` + TrustPolicy string `json:"trustPolicy,omitempty"` } // cosignExtensionList is the structure verifications performed @@ -97,6 +98,7 @@ type cosignExtension struct { BundleVerified bool `json:"bundleVerified"` Err string `json:"error,omitempty"` KeyInformation PKKey `json:"keyInformation,omitempty"` + Summary []string `json:"summary,omitempty"` } type cosignVerifier struct { @@ -117,9 +119,19 @@ var logOpt = logger.Option{ } // used for mocking purposes -var getKeysMaps = getKeysMapsDefault - -const verifierType string = "cosign" +var getKeyMapOpts = getKeyMapOptsDefault + +const ( + verifierType string = "cosign" + // messages for verificationPerformedMessage. source: https://github.com/sigstore/cosign/blob/d275a272ec0cdf5a4c22d01b891a4d7e20164d71/cmd/cosign/cli/verify/verify.go#L318 + annotationMessage string = "The specified annotations were verified." // TODO: check if message has been updated by upstream cosign cli + claimsMessage string = "The cosign claims were validated." // TODO: check if message has been updated by upstream cosign cli + offlineBundleMessage string = "Existence of the claims in the transparency log was verified offline." // TODO: check if message has been updated by upstream cosign cli + rekorClaimsMessage string = "The claims were present in the transparency log." // TODO: check if message has been updated by upstream cosign cli + rekorSigMessage string = "The signatures were integrated into the transparency log when the certificate was valid." // TODO: check if message has been updated by upstream cosign cli + sigVerifierMessage string = "The signatures were verified against the specified public key." // TODO: check if message has been updated by upstream cosign cli + certVerifierMessage string = "The code-signing certificate was verified using trusted certificate authority certificates." // TODO: check if message has been updated by upstream cosign cli +) // init() registers the cosign verifier with the factory func init() { @@ -148,6 +160,7 @@ func (f *cosignVerifierFactory) Create(_ string, verifierConfig config.VerifierC legacy := true // if trustPolicies are provided and non-legacy, create the trust policies if config.KeyRef == "" && config.RekorURL == "" && len(config.TrustPolicies) > 0 { + logger.GetLogger(context.Background(), logOpt).Debugf("legacy cosign verifier configuration not found, creating trust policies") trustPolicies, err = CreateTrustPolicies(config.TrustPolicies, verifierName) if err != nil { return nil, err @@ -195,8 +208,15 @@ func (v *cosignVerifier) Verify(ctx context.Context, subjectReference common.Ref } func (v *cosignVerifier) verifyInternal(ctx context.Context, subjectReference common.Reference, referenceDescriptor ocispecs.ReferenceDescriptor, referrerStore referrerstore.ReferrerStore) (verifier.VerifierResult, error) { + // get the trust policy for the reference + trustPolicy, err := v.trustPolicies.GetScopedPolicy(subjectReference.Original) + if err != nil { + return errorToVerifyResult(v.name, v.verifierType, err), nil + } + logger.GetLogger(ctx, logOpt).Debugf("selected trust policy %s for reference %s", trustPolicy.GetName(), subjectReference.Original) + // get the map of keys and relevant cosign options for that reference - keysMap, cosignOpts, err := getKeysMaps(ctx, v.trustPolicies, subjectReference.Original, v.namespace) + keysMap, cosignOpts, err := getKeyMapOpts(ctx, trustPolicy, v.namespace) if err != nil { return errorToVerifyResult(v.name, v.verifierType, err), nil } @@ -246,41 +266,20 @@ func (v *cosignVerifier) verifyInternal(ctx context.Context, subjectReference co if err != nil { return errorToVerifyResult(v.name, v.verifierType, fmt.Errorf("failed to generate static signature: %w", err)), nil } - // check each key in the map of keys returned by the trust policy - for mapKey, pubKey := range keysMap { - hashType := crypto.SHA256 - // default hash type is SHA256 but for AKV scenarios, the hash type is determined by the key size - // TODO: investigate if it's possible to extract hash type from sig directly. This is a workaround for now - if pubKey.ProviderType == azurekeyvault.ProviderName { - hashType, sig, err = processAKVSignature(blob.Annotations[static.SignatureAnnotationKey], sig, pubKey.Key, blobBytes, staticOpts) - if err != nil { - return errorToVerifyResult(v.name, v.verifierType, fmt.Errorf("failed to process AKV signature: %w", err)), nil - } - } - - // return the correct verifier based on public key type and bytes - verifier, err := signature.LoadVerifier(pubKey.Key, hashType) - if err != nil { - return errorToVerifyResult(v.name, v.verifierType, fmt.Errorf("failed to load public key from provider [%s] name [%s] version [%s]: %w", mapKey.Provider, mapKey.Name, mapKey.Version, err)), nil - } - cosignOpts.SigVerifier = verifier - // verify signature with cosign options + perform bundle verification - bundleVerified, err := cosign.VerifyImageSignature(ctx, sig, subjectDescHash, &cosignOpts) - extension := cosignExtension{ - IsSuccess: true, - BundleVerified: bundleVerified, - KeyInformation: mapKey, - } + if len(keysMap) > 0 { + // if keys are found, perform verification with keys + var verifications []cosignExtension + verifications, hasValidSignature, err = verifyWithKeys(ctx, keysMap, sig, blob.Annotations[static.SignatureAnnotationKey], blobBytes, staticOpts, &cosignOpts, subjectDescHash) if err != nil { - extension.IsSuccess = false - extension.Err = err.Error() - } else { - hasValidSignature = true + return errorToVerifyResult(v.name, v.verifierType, fmt.Errorf("failed to verify with keys: %w", err)), nil } + extensionListEntry.Verifications = append(extensionListEntry.Verifications, verifications...) + } else { + // if no keys are found, perform keyless verification + var extension cosignExtension + extension, hasValidSignature = verifyKeyless(ctx, sig, &cosignOpts, subjectDescHash) extensionListEntry.Verifications = append(extensionListEntry.Verifications, extension) } - - // TODO: perform keyless verification instead if no keys are found sigExtensions = append(sigExtensions, extensionListEntry) } @@ -290,12 +289,12 @@ func (v *cosignVerifier) verifyInternal(ctx context.Context, subjectReference co Type: v.verifierType, IsSuccess: true, Message: "cosign verification success. valid signatures found. please refer to extensions field for verifications performed.", - Extensions: Extension{SignatureExtension: sigExtensions}, + Extensions: Extension{SignatureExtension: sigExtensions, TrustPolicy: trustPolicy.GetName()}, }, nil } errorResult := errorToVerifyResult(v.name, v.verifierType, fmt.Errorf("no valid signatures found")) - errorResult.Extensions = Extension{SignatureExtension: sigExtensions} + errorResult.Extensions = Extension{SignatureExtension: sigExtensions, TrustPolicy: trustPolicy.GetName()} return errorResult, nil } @@ -520,15 +519,69 @@ func decodeASN1Signature(sig []byte) ([]byte, error) { return rawSigBytes, nil } -// getKeysMapsDefault returns the map of keys and cosign options for the reference -func getKeysMapsDefault(ctx context.Context, trustPolicies *TrustPolicies, reference string, namespace string) (map[PKKey]keymanagementprovider.PublicKey, cosign.CheckOpts, error) { - // get the trust policy for the reference - trustPolicy, err := trustPolicies.GetScopedPolicy(reference) +// verifyWithKeys verifies the signature with the keys map and returns the verification results +func verifyWithKeys(ctx context.Context, keysMap map[PKKey]keymanagementprovider.PublicKey, sig oci.Signature, sigEncoded string, payload []byte, staticOpts []static.Option, cosignOpts *cosign.CheckOpts, subjectDescHash v1.Hash) ([]cosignExtension, bool, error) { + // check each key in the map of keys returned by the trust policy + var err error + verifications := make([]cosignExtension, 0) + hasValidSignature := false + for mapKey, pubKey := range keysMap { + hashType := crypto.SHA256 + // default hash type is SHA256 but for AKV scenarios, the hash type is determined by the key size + // TODO: investigate if it's possible to extract hash type from sig directly. This is a workaround for now + if pubKey.ProviderType == azurekeyvault.ProviderName { + hashType, sig, err = processAKVSignature(sigEncoded, sig, pubKey.Key, payload, staticOpts) + if err != nil { + return verifications, false, fmt.Errorf("failed to process AKV signature: %w", err) + } + } + + // return the correct verifier based on public key type and bytes + verifier, err := signature.LoadVerifier(pubKey.Key, hashType) + if err != nil { + return verifications, false, fmt.Errorf("failed to load public key from provider [%s] name [%s] version [%s]: %w", mapKey.Provider, mapKey.Name, mapKey.Version, err) + } + cosignOpts.SigVerifier = verifier + // verify signature with cosign options + perform bundle verification + bundleVerified, err := cosign.VerifyImageSignature(ctx, sig, subjectDescHash, cosignOpts) + extension := cosignExtension{ + IsSuccess: true, + BundleVerified: bundleVerified, + KeyInformation: mapKey, + } + if err != nil { + extension.IsSuccess = false + extension.Err = err.Error() + } else { + extension.Summary = verificationPerformedMessage(bundleVerified, cosignOpts) + hasValidSignature = true + } + verifications = append(verifications, extension) + } + return verifications, hasValidSignature, nil +} + +// verifyKeyless performs keyless verification and returns the verification results +func verifyKeyless(ctx context.Context, sig oci.Signature, cosignOpts *cosign.CheckOpts, subjectDescHash v1.Hash) (cosignExtension, bool) { + // verify signature with cosign options + perform bundle verification + hasValidSignature := false + bundleVerified, err := cosign.VerifyImageSignature(ctx, sig, subjectDescHash, cosignOpts) + extension := cosignExtension{ + IsSuccess: true, + BundleVerified: bundleVerified, + } if err != nil { - return nil, cosign.CheckOpts{}, err + extension.IsSuccess = false + extension.Err = err.Error() + } else { + extension.Summary = verificationPerformedMessage(bundleVerified, cosignOpts) + hasValidSignature = true } - logger.GetLogger(ctx, logOpt).Debugf("selected trust policy %s for reference %s", trustPolicy.GetName(), reference) + return extension, hasValidSignature +} +// getKeyMapOptsDefault returns the map of keys and cosign options for the reference +func getKeyMapOptsDefault(ctx context.Context, trustPolicy TrustPolicy, namespace string) (map[PKKey]keymanagementprovider.PublicKey, cosign.CheckOpts, error) { // get the map of keys for that reference keysMap, err := trustPolicy.GetKeys(ctx, namespace) if err != nil { @@ -594,3 +647,28 @@ func processAKVSignature(sigEncoded string, staticSig oci.Signature, publicKey c } return hashType, staticSig, nil } + +// verificationPerformedMessage returns a string list of all verifications performed +// based on https://github.com/sigstore/cosign/blob/5ae2e31c30ee87e035cc57ebbbe2ecf3b6549ff5/cmd/cosign/cli/verify/verify.go#L318 +func verificationPerformedMessage(bundleVerified bool, co *cosign.CheckOpts) []string { + var messages []string + if co.ClaimVerifier != nil { + if co.Annotations != nil { + messages = append(messages, annotationMessage) + } + messages = append(messages, claimsMessage) + } + if bundleVerified { + messages = append(messages, offlineBundleMessage) + } else if co.RekorClient != nil { + messages = append(messages, rekorClaimsMessage) + messages = append(messages, rekorSigMessage) + } + // if no SigVerifier is provided, fulcio root certs are assumed to be used (keyless) + if co.SigVerifier != nil { + messages = append(messages, sigVerifierMessage) + } else { + messages = append(messages, certVerifierMessage) + } + return messages +} diff --git a/pkg/verifier/cosign/cosign_test.go b/pkg/verifier/cosign/cosign_test.go index eef2f3db3..0b6bf260d 100644 --- a/pkg/verifier/cosign/cosign_test.go +++ b/pkg/verifier/cosign/cosign_test.go @@ -17,12 +17,14 @@ package cosign import ( "context" + "crypto" "crypto/ecdh" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/rsa" "fmt" + "io" "slices" "strings" "testing" @@ -37,10 +39,26 @@ import ( imgspec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/sigstore/cosign/v2/pkg/cosign" "github.com/sigstore/cosign/v2/pkg/oci/static" + "github.com/sigstore/rekor/pkg/generated/client" "github.com/sigstore/sigstore/pkg/cryptoutils" + "github.com/sigstore/sigstore/pkg/signature" ) -const ratifySampleImageRef string = "ghcr.io/deislabs/ratify:v1" +const ( + ratifySampleImageRef string = "ghcr.io/deislabs/ratify:v1" + testIdentity string = "sozercan@gmail.com" + testIssuer string = "https://github.com/login/oauth" +) + +type mockNoOpVerifier struct{} + +func (m *mockNoOpVerifier) PublicKey(_ ...signature.PublicKeyOption) (crypto.PublicKey, error) { + return nil, nil +} + +func (m *mockNoOpVerifier) VerifySignature(_, _ io.Reader, _ ...signature.VerifyOption) error { + return nil +} // TestCreate tests the Create function of the cosign verifier func TestCreate(t *testing.T) { @@ -57,7 +75,7 @@ func TestCreate(t *testing.T) { "trustPolicies": []TrustPolicyConfig{ { Name: "test", - Keyless: KeylessConfig{RekorURL: DefaultRekorURL}, + Keyless: KeylessConfig{CertificateIdentity: testIdentity, CertificateOIDCIssuer: testIssuer}, Scopes: []string{"*"}, }, }, @@ -104,7 +122,7 @@ func TestCreate(t *testing.T) { "trustPolicies": []TrustPolicyConfig{ { Name: "test", - Keyless: KeylessConfig{RekorURL: DefaultRekorURL}, + Keyless: KeylessConfig{CertificateIdentity: testIdentity, CertificateOIDCIssuer: testIssuer}, Scopes: []string{"*"}, }, }, @@ -135,7 +153,7 @@ func TestName(t *testing.T) { "trustPolicies": []TrustPolicyConfig{ { Name: "test", - Keyless: KeylessConfig{RekorURL: DefaultRekorURL}, + Keyless: KeylessConfig{CertificateIdentity: testIdentity, CertificateOIDCIssuer: testIssuer}, Scopes: []string{"*"}, }, }, @@ -159,7 +177,7 @@ func TestType(t *testing.T) { "trustPolicies": []TrustPolicyConfig{ { Name: "test", - Keyless: KeylessConfig{RekorURL: DefaultRekorURL}, + Keyless: KeylessConfig{CertificateIdentity: testIdentity, CertificateOIDCIssuer: testIssuer}, Scopes: []string{"*"}, }, }, @@ -212,7 +230,7 @@ func TestCanVerify(t *testing.T) { "trustPolicies": []TrustPolicyConfig{ { Name: "test", - Keyless: KeylessConfig{RekorURL: DefaultRekorURL}, + Keyless: KeylessConfig{CertificateIdentity: testIdentity, CertificateOIDCIssuer: testIssuer}, Scopes: []string{"*"}, }, }, @@ -238,7 +256,7 @@ func TestGetNestedReferences(t *testing.T) { "trustPolicies": []TrustPolicyConfig{ { Name: "test", - Keyless: KeylessConfig{RekorURL: DefaultRekorURL}, + Keyless: KeylessConfig{CertificateIdentity: testIdentity, CertificateOIDCIssuer: testIssuer}, Scopes: []string{"*"}, }, }, @@ -442,61 +460,24 @@ func TestDecodeASN1Signature(t *testing.T) { } func TestGetKeysMaps_Success(t *testing.T) { - trustPolciesConfig := []TrustPolicyConfig{ - { - Name: "test-policy", - Keyless: KeylessConfig{RekorURL: DefaultRekorURL}, - Scopes: []string{"ghcr.io/*"}, - }, - } - - trustPolicies, err := CreateTrustPolicies(trustPolciesConfig, "test") - if err != nil { - t.Fatalf("CreateTrustPolicies() error = %v", err) - } - _, _, err = getKeysMapsDefault(context.Background(), trustPolicies, ratifySampleImageRef, "gatekeeper-system") + trustPolicy := &mockTrustPolicy{} + _, _, err := getKeyMapOptsDefault(context.Background(), trustPolicy, "gatekeeper-system") if err != nil { t.Errorf("getKeysMaps() error = %v, wantErr %v", err, false) } } -func TestGetKeysMaps_FailingTrustPolicies(t *testing.T) { - trustPolciesConfig := []TrustPolicyConfig{ - { - Name: "test-policy", - Keyless: KeylessConfig{RekorURL: DefaultRekorURL}, - Scopes: []string{"myregistry.io/*"}, - }, - } - - trustPolicies, err := CreateTrustPolicies(trustPolciesConfig, "test") - if err != nil { - t.Fatalf("CreateTrustPolicies() error = %v", err) - } - _, _, err = getKeysMapsDefault(context.Background(), trustPolicies, ratifySampleImageRef, "gatekeeper-system") +func TestGetKeysMaps_FailingCosignOpts(t *testing.T) { + trustPolicy := &mockTrustPolicy{shouldErrCosignOpts: true} + _, _, err := getKeyMapOptsDefault(context.Background(), trustPolicy, "gatekeeper-system") if err == nil { t.Errorf("getKeysMaps() error = %v, wantErr %v", err, true) } } func TestGetKeysMaps_FailingGetKeys(t *testing.T) { - trustPolciesConfig := []TrustPolicyConfig{ - { - Name: "test-policy", - Keys: []KeyConfig{ - { - Provider: "non-existent", - }, - }, - Scopes: []string{"*"}, - }, - } - - trustPolicies, err := CreateTrustPolicies(trustPolciesConfig, "test") - if err != nil { - t.Fatalf("CreateTrustPolicies() error = %v", err) - } - _, _, err = getKeysMapsDefault(context.Background(), trustPolicies, ratifySampleImageRef, "gatekeeper-system") + trustPolicy := &mockTrustPolicy{shouldErrKeys: true} + _, _, err := getKeyMapOptsDefault(context.Background(), trustPolicy, "gatekeeper-system") if err == nil { t.Errorf("getKeysMaps() error = %v, wantErr %v", err, true) } @@ -581,6 +562,7 @@ mmBwUAwwW0Uc+Nt3bDOCiB1nUsICv1ry cosignOpts cosign.CheckOpts store *mocks.MemoryTestStore expectedResultMessagePrefix string + defaultCosignOpts bool }{ { name: "get keys error", @@ -677,7 +659,7 @@ mmBwUAwwW0Uc+Nt3bDOCiB1nUsICv1ry blobDigest: validSignatureBlob, }, }, - expectedResultMessagePrefix: "cosign verification failed: failed to process AKV signature: unsupported public key type", + expectedResultMessagePrefix: "cosign verification failed: failed to verify with keys: failed to process AKV signature: unsupported public key type", }, { name: "invalid RSA key size for AKV", @@ -708,7 +690,7 @@ mmBwUAwwW0Uc+Nt3bDOCiB1nUsICv1ry blobDigest: validSignatureBlob, }, }, - expectedResultMessagePrefix: "cosign verification failed: failed to process AKV signature: RSA key check: unsupported key size", + expectedResultMessagePrefix: "cosign verification failed: failed to verify with keys: failed to process AKV signature: RSA key check: unsupported key size", }, { name: "invalid ECDSA curve type for AKV", @@ -739,7 +721,7 @@ mmBwUAwwW0Uc+Nt3bDOCiB1nUsICv1ry blobDigest: validSignatureBlob, }, }, - expectedResultMessagePrefix: "cosign verification failed: failed to process AKV signature: ECDSA key check: unsupported key curve", + expectedResultMessagePrefix: "cosign verification failed: failed to verify with keys: failed to process AKV signature: ECDSA key check: unsupported key curve", }, { name: "valid hash: 256 keysize: 2048 RSA key AKV", @@ -901,22 +883,99 @@ mmBwUAwwW0Uc+Nt3bDOCiB1nUsICv1ry }, expectedResultMessagePrefix: "cosign verification success", }, + { + name: "successful keyless verification", + keys: map[PKKey]keymanagementprovider.PublicKey{}, + defaultCosignOpts: true, + getKeysError: false, + store: &mocks.MemoryTestStore{ + Manifests: map[digest.Digest]ocispecs.ReferenceManifest{ + testRefDigest: { + MediaType: refDescriptor.MediaType, + Blobs: []imgspec.Descriptor{ + { + Digest: digest.NewDigestFromEncoded(digest.SHA256, "d1226e36bc8502978324cb2cb2116c6aa48edb2ea8f15b1c6f6f256ed43388f6"), + Annotations: map[string]string{ + "dev.cosignproject.cosign/signature": "MEUCIFBlKbxxg1Ni++g99jeWO8Of3g5L0Xd+qMzdqCZySQ8DAiEA3lcOJPJ1FQOahtWaRU0hG0XxFEsbcVx6SIyzYQMMR0A=", + "dev.sigstore.cosign/bundle": "{\"SignedEntryTimestamp\":\"MEUCIAIZfWhm9x2F7wil5dkWX+0+njT+FWXFr8AskDkiHpzoAiEApDk9STKcBJTkQ4qy9/8gn6ea2wduh3UjbLRnzZQa9gU=\",\"Payload\":{\"body\":\"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiJkMTIyNmUzNmJjODUwMjk3ODMyNGNiMmNiMjExNmM2YWE0OGVkYjJlYThmMTViMWM2ZjZmMjU2ZWQ0MzM4OGY2In19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJRkJsS2J4eGcxTmkrK2c5OWplV084T2YzZzVMMFhkK3FNemRxQ1p5U1E4REFpRUEzbGNPSlBKMUZRT2FodFdhUlUwaEcwWHhGRXNiY1Z4NlNJeXpZUU1NUjBBPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVTnZSRU5EUVdsaFowRjNTVUpCWjBsVlVsWjFTa3A2T1VneWJGUldWMDgyTjFCdWMyZDBUWFJUYld4TmQwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcE5kMDFxUlRKTlJGVjVUWHBCTUZkb1kwNU5hazEzVFdwRk1rMUVWWHBOZWtFd1YycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVUzWlV0MU9IQnJOMmN5TDBsU2FGSjVNbEF2TWtoamMxTkNZMWcyUWxwb1QwTkpjMndLU0RBMVFWaHhTelZsUzBKR1R6QmxUU3RvU0hGeGFXbHRZVFJVYm5kNll6RnpUMjkwT0hSVVJuYzVlVVJFYlhod1RrdFBRMEZWVlhkblowWkNUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXUkNaMDVXU0ZFMFJVWm5VVlZNYVZWRUNub3hSRzV2YURsVlRXZHBiMDh4ZEZsdU1IYzFTVUpWZDBoM1dVUldVakJxUWtKbmQwWnZRVlV6T1ZCd2VqRlphMFZhWWpWeFRtcHdTMFpYYVhocE5Ga0tXa1E0ZDBsQldVUldVakJTUVZGSUwwSkNXWGRHU1VWVFl6STVObHBZU21wWlZ6VkJXakl4YUdGWGQzVlpNamwwVFVOM1IwTnBjMGRCVVZGQ1p6YzRkd3BCVVVWRlNHMW9NR1JJUW5wUGFUaDJXakpzTUdGSVZtbE1iVTUyWWxNNWMySXlaSEJpYVRsMldWaFdNR0ZFUTBKcFVWbExTM2RaUWtKQlNGZGxVVWxGQ2tGblVqZENTR3RCWkhkQ01VRk9NRGxOUjNKSGVIaEZlVmw0YTJWSVNteHVUbmRMYVZOc05qUXphbmwwTHpSbFMyTnZRWFpMWlRaUFFVRkJRbWhzYVhRS1IweFZRVUZCVVVSQlJWbDNVa0ZKWjA5T2EyUndTSGx1Ykc4eWRFOXZZbkJ1Y2tSWFQwSTJTM2x3Y1d0V2RuUlZiVVpLSzFKVFZVZ3JTREJEU1VWTlNBcDBURFp0Y25nemVUTmxWV3R3ZGpJM2JsRk1VbFJhZDFkeVJuSTROR2QxUXpCNFVYZHdkVmxxVFVGdlIwTkRjVWRUVFRRNVFrRk5SRUV5WjBGTlIxVkRDazFCYTB4eVRuaHJWMlUwVHpGV2JFNDFPRTlqTkcxMlpGQjRjRFJhYUZGMFYwdFNNM0pGUmxCS2FXOXFOMWM1YkV3d1VIYzFiVlp5T1VaQ2VrZzJjMW9LY0dkSmVFRlFhamhKVUZaUFZWVlRVM1JUV0dnM1VsZHFkQ3RKVkVsNVYzQjNTWG8zVUd0MWFVOUZNSEJEUnpaSWRrZERkbXdyWmxScE1FMVFkbkpUVUFwb2NuSmxaV2M5UFFvdExTMHRMVVZPUkNCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2c9PSJ9fX19\",\"integratedTime\":1676524985,\"logIndex\":13452680,\"logID\":\"c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d\"}}", + "dev.sigstore.cosign/certificate": "-----BEGIN CERTIFICATE-----\nMIICoDCCAiagAwIBAgIURVuJJz9H2lTVWO67PnsgtMtSmlMwCgYIKoZIzj0EAwMw\nNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl\ncm1lZGlhdGUwHhcNMjMwMjE2MDUyMzA0WhcNMjMwMjE2MDUzMzA0WjAAMFkwEwYH\nKoZIzj0CAQYIKoZIzj0DAQcDQgAE7eKu8pk7g2/IRhRy2P/2HcsSBcX6BZhOCIsl\nH05AXqK5eKBFO0eM+hHqqiima4Tnwzc1sOot8tTFw9yDDmxpNKOCAUUwggFBMA4G\nA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQULiUD\nz1Dnoh9UMgioO1tYn0w5IBUwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4Y\nZD8wIAYDVR0RAQH/BBYwFIESc296ZXJjYW5AZ21haWwuY29tMCwGCisGAQQBg78w\nAQEEHmh0dHBzOi8vZ2l0aHViLmNvbS9sb2dpbi9vYXV0aDCBiQYKKwYBBAHWeQIE\nAgR7BHkAdwB1AN09MGrGxxEyYxkeHJlnNwKiSl643jyt/4eKcoAvKe6OAAABhlit\nGLUAAAQDAEYwRAIgONkdpHynlo2tOobpnrDWOB6KypqkVvtUmFJ+RSUH+H0CIEMH\ntL6mrx3y3eUkpv27nQLRTZwWrFr84guC0xQwpuYjMAoGCCqGSM49BAMDA2gAMGUC\nMAkLrNxkWe4O1VlN58Oc4mvdPxp4ZhQtWKR3rEFPJioj7W9lL0Pw5mVr9FBzH6sZ\npgIxAPj8IPVOUUSStSXh7RWjt+ITIyWpwIz7PkuiOE0pCG6HvGCvl+fTi0MPvrSP\nhrreeg==\n-----END CERTIFICATE-----\n", + "dev.sigstore.cosign/chain": "-----BEGIN CERTIFICATE-----\nMIICGjCCAaGgAwIBAgIUALnViVfnU0brJasmRkHrn/UnfaQwCgYIKoZIzj0EAwMw\nKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y\nMjA0MTMyMDA2MTVaFw0zMTEwMDUxMzU2NThaMDcxFTATBgNVBAoTDHNpZ3N0b3Jl\nLmRldjEeMBwGA1UEAxMVc2lnc3RvcmUtaW50ZXJtZWRpYXRlMHYwEAYHKoZIzj0C\nAQYFK4EEACIDYgAE8RVS/ysH+NOvuDZyPIZtilgUF9NlarYpAd9HP1vBBH1U5CV7\n7LSS7s0ZiH4nE7Hv7ptS6LvvR/STk798LVgMzLlJ4HeIfF3tHSaexLcYpSASr1kS\n0N/RgBJz/9jWCiXno3sweTAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0lBAwwCgYIKwYB\nBQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU39Ppz1YkEZb5qNjp\nKFWixi4YZD8wHwYDVR0jBBgwFoAUWMAeX5FFpWapesyQoZMi0CrFxfowCgYIKoZI\nzj0EAwMDZwAwZAIwPCsQK4DYiZYDPIaDi5HFKnfxXx6ASSVmERfsynYBiX2X6SJR\nnZU84/9DZdnFvvxmAjBOt6QpBlc4J/0DxvkTCqpclvziL6BCCPnjdlIB3Pu3BxsP\nmygUY7Ii2zbdCdliiow=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIB9zCCAXygAwIBAgIUALZNAPFdxHPwjeDloDwyYChAO/4wCgYIKoZIzj0EAwMw\nKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y\nMTEwMDcxMzU2NTlaFw0zMTEwMDUxMzU2NThaMCoxFTATBgNVBAoTDHNpZ3N0b3Jl\nLmRldjERMA8GA1UEAxMIc2lnc3RvcmUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAT7\nXeFT4rb3PQGwS4IajtLk3/OlnpgangaBclYpsYBr5i+4ynB07ceb3LP0OIOZdxex\nX69c5iVuyJRQ+Hz05yi+UF3uBWAlHpiS5sh0+H2GHE7SXrk1EC5m1Tr19L9gg92j\nYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRY\nwB5fkUWlZql6zJChkyLQKsXF+jAfBgNVHSMEGDAWgBRYwB5fkUWlZql6zJChkyLQ\nKsXF+jAKBggqhkjOPQQDAwNpADBmAjEAj1nHeXZp+13NWBNa+EDsDP8G1WWg1tCM\nWP/WHPqpaVo0jhsweNFZgSs0eE7wYI4qAjEA2WB9ot98sIkoF3vZYdd3/VtWB5b9\nTNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ\n-----END CERTIFICATE-----", + }, + }, + }, + }, + }, + Subjects: map[digest.Digest]*ocispecs.SubjectDescriptor{ + subjectDigest: { + Descriptor: imgspec.Descriptor{ + Digest: digest.NewDigestFromEncoded(digest.SHA256, "623621b56649b5e0c2c7cf3ffd987932f8f9a5a01036e00d6f3ae9480087621c"), + MediaType: imgspec.MediaTypeImageManifest, + }, + }, + }, + Blobs: map[digest.Digest][]byte{ + "sha256:d1226e36bc8502978324cb2cb2116c6aa48edb2ea8f15b1c6f6f256ed43388f6": []byte(`{"critical":{"identity":{"docker-reference":"wabbitnetworks.azurecr.io/test/cosign-image"},"image":{"docker-manifest-digest":"sha256:623621b56649b5e0c2c7cf3ffd987932f8f9a5a01036e00d6f3ae9480087621c"},"type":"cosign container image signature"},"optional":null}`), + }, + }, + expectedResultMessagePrefix: "cosign verification success", + }, + { + name: "failed keyless verification", + keys: map[PKKey]keymanagementprovider.PublicKey{}, + defaultCosignOpts: true, + getKeysError: false, + store: &mocks.MemoryTestStore{ + Manifests: map[digest.Digest]ocispecs.ReferenceManifest{ + testRefDigest: { + MediaType: refDescriptor.MediaType, + Blobs: []imgspec.Descriptor{ + { + Digest: digest.NewDigestFromEncoded(digest.SHA256, "d1226e36bc8502978324cb2cb2116c6aa48edb2ea8f15b1c6f6f256ed43388f6"), + Annotations: map[string]string{ + "dev.cosignproject.cosign/signature": "MEUCIFBlKbxxg1Ni++g99jeWO8Of3g5L0Xd+qMzdqCZySQ8DAiEA3lcOJPJ1FQOahtWaRU0hG0XxFEsbcVx6SIyzYQMMR0A=", + "dev.sigstore.cosign/bundle": "{\"SignedEntryTimestamp\":\"AIZfWhm9x2F7wil5dkWX+0+njT+FWXFr8AskDkiHpzoAiEApDk9STKcBJTkQ4qy9/8gn6ea2wduh3UjbLRnzZQa9gU=\",\"Payload\":{\"body\":\"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiJkMTIyNmUzNmJjODUwMjk3ODMyNGNiMmNiMjExNmM2YWE0OGVkYjJlYThmMTViMWM2ZjZmMjU2ZWQ0MzM4OGY2In19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJRkJsS2J4eGcxTmkrK2c5OWplV084T2YzZzVMMFhkK3FNemRxQ1p5U1E4REFpRUEzbGNPSlBKMUZRT2FodFdhUlUwaEcwWHhGRXNiY1Z4NlNJeXpZUU1NUjBBPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVTnZSRU5EUVdsaFowRjNTVUpCWjBsVlVsWjFTa3A2T1VneWJGUldWMDgyTjFCdWMyZDBUWFJUYld4TmQwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcE5kMDFxUlRKTlJGVjVUWHBCTUZkb1kwNU5hazEzVFdwRk1rMUVWWHBOZWtFd1YycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVUzWlV0MU9IQnJOMmN5TDBsU2FGSjVNbEF2TWtoamMxTkNZMWcyUWxwb1QwTkpjMndLU0RBMVFWaHhTelZsUzBKR1R6QmxUU3RvU0hGeGFXbHRZVFJVYm5kNll6RnpUMjkwT0hSVVJuYzVlVVJFYlhod1RrdFBRMEZWVlhkblowWkNUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXUkNaMDVXU0ZFMFJVWm5VVlZNYVZWRUNub3hSRzV2YURsVlRXZHBiMDh4ZEZsdU1IYzFTVUpWZDBoM1dVUldVakJxUWtKbmQwWnZRVlV6T1ZCd2VqRlphMFZhWWpWeFRtcHdTMFpYYVhocE5Ga0tXa1E0ZDBsQldVUldVakJTUVZGSUwwSkNXWGRHU1VWVFl6STVObHBZU21wWlZ6VkJXakl4YUdGWGQzVlpNamwwVFVOM1IwTnBjMGRCVVZGQ1p6YzRkd3BCVVVWRlNHMW9NR1JJUW5wUGFUaDJXakpzTUdGSVZtbE1iVTUyWWxNNWMySXlaSEJpYVRsMldWaFdNR0ZFUTBKcFVWbExTM2RaUWtKQlNGZGxVVWxGQ2tGblVqZENTR3RCWkhkQ01VRk9NRGxOUjNKSGVIaEZlVmw0YTJWSVNteHVUbmRMYVZOc05qUXphbmwwTHpSbFMyTnZRWFpMWlRaUFFVRkJRbWhzYVhRS1IweFZRVUZCVVVSQlJWbDNVa0ZKWjA5T2EyUndTSGx1Ykc4eWRFOXZZbkJ1Y2tSWFQwSTJTM2x3Y1d0V2RuUlZiVVpLSzFKVFZVZ3JTREJEU1VWTlNBcDBURFp0Y25nemVUTmxWV3R3ZGpJM2JsRk1VbFJhZDFkeVJuSTROR2QxUXpCNFVYZHdkVmxxVFVGdlIwTkRjVWRUVFRRNVFrRk5SRUV5WjBGTlIxVkRDazFCYTB4eVRuaHJWMlUwVHpGV2JFNDFPRTlqTkcxMlpGQjRjRFJhYUZGMFYwdFNNM0pGUmxCS2FXOXFOMWM1YkV3d1VIYzFiVlp5T1VaQ2VrZzJjMW9LY0dkSmVFRlFhamhKVUZaUFZWVlRVM1JUV0dnM1VsZHFkQ3RKVkVsNVYzQjNTWG8zVUd0MWFVOUZNSEJEUnpaSWRrZERkbXdyWmxScE1FMVFkbkpUVUFwb2NuSmxaV2M5UFFvdExTMHRMVVZPUkNCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2c9PSJ9fX19\",\"integratedTime\":1676524985,\"logIndex\":13452680,\"logID\":\"c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d\"}}", + "dev.sigstore.cosign/certificate": "-----BEGIN CERTIFICATE-----\nMIICoDCCAiagAwIBAgIURVuJJz9H2lTVWO67PnsgtMtSmlMwCgYIKoZIzj0EAwMw\nNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl\ncm1lZGlhdGUwHhcNMjMwMjE2MDUyMzA0WhcNMjMwMjE2MDUzMzA0WjAAMFkwEwYH\nKoZIzj0CAQYIKoZIzj0DAQcDQgAE7eKu8pk7g2/IRhRy2P/2HcsSBcX6BZhOCIsl\nH05AXqK5eKBFO0eM+hHqqiima4Tnwzc1sOot8tTFw9yDDmxpNKOCAUUwggFBMA4G\nA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQULiUD\nz1Dnoh9UMgioO1tYn0w5IBUwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4Y\nZD8wIAYDVR0RAQH/BBYwFIESc296ZXJjYW5AZ21haWwuY29tMCwGCisGAQQBg78w\nAQEEHmh0dHBzOi8vZ2l0aHViLmNvbS9sb2dpbi9vYXV0aDCBiQYKKwYBBAHWeQIE\nAgR7BHkAdwB1AN09MGrGxxEyYxkeHJlnNwKiSl643jyt/4eKcoAvKe6OAAABhlit\nGLUAAAQDAEYwRAIgONkdpHynlo2tOobpnrDWOB6KypqkVvtUmFJ+RSUH+H0CIEMH\ntL6mrx3y3eUkpv27nQLRTZwWrFr84guC0xQwpuYjMAoGCCqGSM49BAMDA2gAMGUC\nMAkLrNxkWe4O1VlN58Oc4mvdPxp4ZhQtWKR3rEFPJioj7W9lL0Pw5mVr9FBzH6sZ\npgIxAPj8IPVOUUSStSXh7RWjt+ITIyWpwIz7PkuiOE0pCG6HvGCvl+fTi0MPvrSP\nhrreeg==\n-----END CERTIFICATE-----\n", + "dev.sigstore.cosign/chain": "-----BEGIN CERTIFICATE-----\nMIICGjCCAaGgAwIBAgIUALnViVfnU0brJasmRkHrn/UnfaQwCgYIKoZIzj0EAwMw\nKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y\nMjA0MTMyMDA2MTVaFw0zMTEwMDUxMzU2NThaMDcxFTATBgNVBAoTDHNpZ3N0b3Jl\nLmRldjEeMBwGA1UEAxMVc2lnc3RvcmUtaW50ZXJtZWRpYXRlMHYwEAYHKoZIzj0C\nAQYFK4EEACIDYgAE8RVS/ysH+NOvuDZyPIZtilgUF9NlarYpAd9HP1vBBH1U5CV7\n7LSS7s0ZiH4nE7Hv7ptS6LvvR/STk798LVgMzLlJ4HeIfF3tHSaexLcYpSASr1kS\n0N/RgBJz/9jWCiXno3sweTAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0lBAwwCgYIKwYB\nBQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU39Ppz1YkEZb5qNjp\nKFWixi4YZD8wHwYDVR0jBBgwFoAUWMAeX5FFpWapesyQoZMi0CrFxfowCgYIKoZI\nzj0EAwMDZwAwZAIwPCsQK4DYiZYDPIaDi5HFKnfxXx6ASSVmERfsynYBiX2X6SJR\nnZU84/9DZdnFvvxmAjBOt6QpBlc4J/0DxvkTCqpclvziL6BCCPnjdlIB3Pu3BxsP\nmygUY7Ii2zbdCdliiow=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIB9zCCAXygAwIBAgIUALZNAPFdxHPwjeDloDwyYChAO/4wCgYIKoZIzj0EAwMw\nKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y\nMTEwMDcxMzU2NTlaFw0zMTEwMDUxMzU2NThaMCoxFTATBgNVBAoTDHNpZ3N0b3Jl\nLmRldjERMA8GA1UEAxMIc2lnc3RvcmUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAT7\nXeFT4rb3PQGwS4IajtLk3/OlnpgangaBclYpsYBr5i+4ynB07ceb3LP0OIOZdxex\nX69c5iVuyJRQ+Hz05yi+UF3uBWAlHpiS5sh0+H2GHE7SXrk1EC5m1Tr19L9gg92j\nYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRY\nwB5fkUWlZql6zJChkyLQKsXF+jAfBgNVHSMEGDAWgBRYwB5fkUWlZql6zJChkyLQ\nKsXF+jAKBggqhkjOPQQDAwNpADBmAjEAj1nHeXZp+13NWBNa+EDsDP8G1WWg1tCM\nWP/WHPqpaVo0jhsweNFZgSs0eE7wYI4qAjEA2WB9ot98sIkoF3vZYdd3/VtWB5b9\nTNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ\n-----END CERTIFICATE-----", + }, + }, + }, + }, + }, + Subjects: map[digest.Digest]*ocispecs.SubjectDescriptor{ + subjectDigest: { + Descriptor: imgspec.Descriptor{ + Digest: digest.NewDigestFromEncoded(digest.SHA256, "623621b56649b5e0c2c7cf3ffd987932f8f9a5a01036e00d6f3ae9480087621c"), + MediaType: imgspec.MediaTypeImageManifest, + }, + }, + }, + Blobs: map[digest.Digest][]byte{ + "sha256:d1226e36bc8502978324cb2cb2116c6aa48edb2ea8f15b1c6f6f256ed43388f6": []byte(`{"critical":{"identity":{"docker-reference":"wabbitnetworks.azurecr.io/test/cosign-image"},"image":{"docker-manifest-digest":"sha256:623621b56649b5e0c2c7cf3ffd987932f8f9a5a01036e00d6f3ae9480087621c"},"type":"cosign container image signature"},"optional":null}`), + }, + }, + expectedResultMessagePrefix: "cosign verification failed", + }, } for _, tt := range tc { t.Run(tt.name, func(t *testing.T) { - getKeysMaps = func(_ context.Context, _ *TrustPolicies, _ string, _ string) (map[PKKey]keymanagementprovider.PublicKey, cosign.CheckOpts, error) { + getKeyMapOpts = func(ctx context.Context, trustPolicy TrustPolicy, _ string) (map[PKKey]keymanagementprovider.PublicKey, cosign.CheckOpts, error) { + co := tt.cosignOpts if tt.getKeysError { return nil, cosign.CheckOpts{}, fmt.Errorf("error") } - return tt.keys, tt.cosignOpts, nil + if tt.defaultCosignOpts { + co, _ = trustPolicy.GetCosignOpts(ctx) + } + + return tt.keys, co, nil } verifierFactory := cosignVerifierFactory{} trustPoliciesConfig := []TrustPolicyConfig{ { Name: "test-policy", - Keyless: KeylessConfig{RekorURL: DefaultRekorURL}, + Keyless: KeylessConfig{CertificateIdentity: testIdentity, CertificateOIDCIssuer: testIssuer}, Scopes: []string{"*"}, }, } @@ -937,3 +996,42 @@ mmBwUAwwW0Uc+Nt3bDOCiB1nUsICv1ry }) } } + +// TestVerificationMessage tests the verificationMessage function +func TestVerificationMessage(t *testing.T) { + tc := []struct { + name string + expectedMessages []string + bundleVerified bool + checkOpts cosign.CheckOpts + }{ + { + name: "keyed, offline bundle, claims with annotations", + expectedMessages: []string{annotationMessage, claimsMessage, offlineBundleMessage, sigVerifierMessage}, + bundleVerified: true, + checkOpts: cosign.CheckOpts{ + ClaimVerifier: cosign.SimpleClaimVerifier, + Annotations: map[string]interface{}{ + "test": "test", + }, + SigVerifier: &mockNoOpVerifier{}, + }, + }, + { + name: "keyless, rekor, fulcio", + expectedMessages: []string{rekorClaimsMessage, rekorSigMessage, certVerifierMessage}, + bundleVerified: false, + checkOpts: cosign.CheckOpts{ + RekorClient: &client.Rekor{}, + }, + }, + } + for i, tt := range tc { + t.Run(tt.name, func(t *testing.T) { + result := verificationPerformedMessage(tt.bundleVerified, &tc[i].checkOpts) + if !slices.Equal(result, tt.expectedMessages) { + t.Errorf("verificationMessage() = %v, want %v", result, tt.expectedMessages) + } + }) + } +} diff --git a/pkg/verifier/cosign/trustpolicies_test.go b/pkg/verifier/cosign/trustpolicies_test.go index cdea65b8a..2d7d29208 100644 --- a/pkg/verifier/cosign/trustpolicies_test.go +++ b/pkg/verifier/cosign/trustpolicies_test.go @@ -32,7 +32,7 @@ func TestCreateTrustPolicies(t *testing.T) { { Name: "test", Scopes: []string{"ghcr.io/deislabs/ratify:v1"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, }, wantErr: false, @@ -53,12 +53,12 @@ func TestCreateTrustPolicies(t *testing.T) { { Name: "test", Scopes: []string{"ghcr.io/deislabs/ratify:v1"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, { Name: "test-2", Scopes: []string{"ghcr.io/deislabs/ratify:v2"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, }, wantErr: false, @@ -69,12 +69,12 @@ func TestCreateTrustPolicies(t *testing.T) { { Name: "test", Scopes: []string{"ghcr.io/deislabs/ratify:v1"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, { Name: "test-2", Scopes: []string{"ghcr.io/deislabs/ratify:v1"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, }, wantErr: true, @@ -85,12 +85,12 @@ func TestCreateTrustPolicies(t *testing.T) { { Name: "test", Scopes: []string{"ghcr.io/deislabs/ratify:v1"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, { Name: "test", Scopes: []string{"ghcr.io/deislabs/ratify:v1"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, }, wantErr: true, @@ -100,12 +100,12 @@ func TestCreateTrustPolicies(t *testing.T) { policyConfigs: []TrustPolicyConfig{ { Scopes: []string{"ghcr.io/deislabs/ratify:v1"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, { Name: "test", Scopes: []string{"ghcr.io/deislabs/ratify:v1"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, }, wantErr: true, @@ -136,12 +136,12 @@ func TestGetScopedPolicy(t *testing.T) { { Name: "test", Scopes: []string{"ghcr.io/deislabs/ratify:v1"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, { Name: "test-2", Scopes: []string{"ghcr.io/deislabs/ratify:v2"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, }, reference: "ghcr.io/deislabs/ratify:v1", @@ -154,12 +154,12 @@ func TestGetScopedPolicy(t *testing.T) { { Name: "test", Scopes: []string{"ghcr.io/deislabs/ratify:*"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, { Name: "test-2", Scopes: []string{"ghcr.io/deislabs/ratify2:v1"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, }, reference: "ghcr.io/deislabs/ratify:v1", @@ -172,12 +172,12 @@ func TestGetScopedPolicy(t *testing.T) { { Name: "test", Scopes: []string{"ghcr.io/deislabs/ratify:*"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, { Name: "test-2", Scopes: []string{"ghcr.io/deislabs/ratify2:v1"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, }, reference: "ghcr.io/deislabs/ratify3:v1", @@ -190,12 +190,12 @@ func TestGetScopedPolicy(t *testing.T) { { Name: "global", Scopes: []string{"*"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, { Name: "test-2", Scopes: []string{"ghcr.io/deislabs/ratify2:v1"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, }, reference: "ghcr.io/deislabs/ratify3:v1", @@ -234,7 +234,7 @@ func TestValidateScopes(t *testing.T) { { Name: "test", Scopes: []string{"ghcr.io/deislabs/ratify:v1"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, }, wantErr: false, @@ -245,7 +245,7 @@ func TestValidateScopes(t *testing.T) { { Name: "test", Scopes: []string{"ghcr.io/deislabs/ratify:v1", "ghcr.io/deislabs/ratify:v2"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, }, wantErr: false, @@ -256,7 +256,7 @@ func TestValidateScopes(t *testing.T) { { Name: "test", Scopes: []string{"ghcr.io/deislabs/ratify:*"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, }, wantErr: false, @@ -267,7 +267,7 @@ func TestValidateScopes(t *testing.T) { { Name: "test", Scopes: []string{"ghcr.io/deislabs/ratify:*"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, }, wantErr: false, @@ -278,7 +278,7 @@ func TestValidateScopes(t *testing.T) { { Name: "test", Scopes: []string{"*"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, }, wantErr: false, @@ -289,7 +289,7 @@ func TestValidateScopes(t *testing.T) { { Name: "test", Scopes: []string{"*", "somescope"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, }, wantErr: true, @@ -300,7 +300,7 @@ func TestValidateScopes(t *testing.T) { { Name: "test", Scopes: []string{"ghcr.io/deislabs/ratify:v1", "ghcr.io/deislabs/ratify:v1"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, }, wantErr: true, @@ -311,12 +311,12 @@ func TestValidateScopes(t *testing.T) { { Name: "test", Scopes: []string{"ghcr.io/deislabs/ratify:v1"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, { Name: "test-2", Scopes: []string{"ghcr.io/deislabs/ratify:v1"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, }, wantErr: true, @@ -327,12 +327,12 @@ func TestValidateScopes(t *testing.T) { { Name: "test", Scopes: []string{"*"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, { Name: "test-2", Scopes: []string{"*"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, }, wantErr: true, @@ -343,7 +343,7 @@ func TestValidateScopes(t *testing.T) { { Name: "test", Scopes: []string{"ghcr.io/deislabs/ratify:*", "ghcr.io/deislabs/ratify:*"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, }, wantErr: true, @@ -354,7 +354,7 @@ func TestValidateScopes(t *testing.T) { { Name: "test", Scopes: []string{"*.azurecr.io"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, }, wantErr: true, @@ -365,7 +365,7 @@ func TestValidateScopes(t *testing.T) { { Name: "test", Scopes: []string{"ghcr.io/*/ratify:v1"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, }, wantErr: true, @@ -376,7 +376,7 @@ func TestValidateScopes(t *testing.T) { { Name: "test", Scopes: []string{"ghcr.io/*", "ghcr.io/deislabs/*"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, }, wantErr: true, @@ -387,12 +387,12 @@ func TestValidateScopes(t *testing.T) { { Name: "test", Scopes: []string{"ghcr.io/deislabs/*"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, { Name: "test-2", Scopes: []string{"ghcr.io/test/*"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, }, wantErr: false, @@ -403,12 +403,12 @@ func TestValidateScopes(t *testing.T) { { Name: "test", Scopes: []string{"ghcr.io/deislabs/*"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, { Name: "test-2", Scopes: []string{"ghcr.io/deislabs/ratify:v1"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, }, wantErr: true, @@ -419,12 +419,12 @@ func TestValidateScopes(t *testing.T) { { Name: "test", Scopes: []string{"ghcr.io/deislabs/ratify:v1"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, { Name: "test-2", Scopes: []string{"ghcr.io/deislabs/ratify:*"}, - Keyless: KeylessConfig{RekorURL: "https://rekor.sigstore.dev"}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, }, wantErr: true, diff --git a/pkg/verifier/cosign/trustpolicy.go b/pkg/verifier/cosign/trustpolicy.go index 08410ae9d..7efe26949 100644 --- a/pkg/verifier/cosign/trustpolicy.go +++ b/pkg/verifier/cosign/trustpolicy.go @@ -39,8 +39,11 @@ type KeyConfig struct { } type KeylessConfig struct { - RekorURL string `json:"rekorURL,omitempty"` - CTLogVerify *bool `json:"ctLogVerify,omitempty"` + CTLogVerify *bool `json:"ctLogVerify,omitempty"` + CertificateIdentity string `json:"certificateIdentity,omitempty"` + CertificateIdentityRegExp string `json:"certificateIdentityRegExp,omitempty"` + CertificateOIDCIssuer string `json:"certificateOIDCIssuer,omitempty"` + CertificateOIDCIssuerRegExp string `json:"certificateOIDCIssuerRegExp,omitempty"` } type TrustPolicyConfig struct { @@ -50,10 +53,11 @@ type TrustPolicyConfig struct { Keys []KeyConfig `json:"keys,omitempty"` Keyless KeylessConfig `json:"keyless,omitempty"` TLogVerify *bool `json:"tLogVerify,omitempty"` + RekorURL string `json:"rekorURL,omitempty"` } type PKKey struct { - Provider string `json:"provider"` + Provider string `json:"provider,omitempty"` Name string `json:"name,omitempty"` Version string `json:"version,omitempty"` } @@ -109,8 +113,8 @@ func CreateTrustPolicy(config TrustPolicyConfig, verifierName string) (TrustPoli } } - if config.Keyless.RekorURL == "" { - config.Keyless.RekorURL = DefaultRekorURL + if config.RekorURL == "" { + config.RekorURL = DefaultRekorURL } if config.TLogVerify == nil { @@ -177,16 +181,31 @@ func (tp *trustPolicy) GetScopes() []string { func (tp *trustPolicy) GetCosignOpts(ctx context.Context) (cosign.CheckOpts, error) { cosignOpts := cosign.CheckOpts{} + var err error + // if tlog verification is enabled, set the rekor client and public keys + if tp.config.TLogVerify != nil && *tp.config.TLogVerify { + cosignOpts.IgnoreTlog = false + // create the rekor client + cosignOpts.RekorClient, err = rekor.NewClient(tp.config.RekorURL) + if err != nil { + return cosignOpts, fmt.Errorf("failed to create Rekor client from URL %s: %w", tp.config.RekorURL, err) + } + // Fetches the Rekor public keys from the Rekor server + cosignOpts.RekorPubKeys, err = cosign.GetRekorPubs(ctx) + if err != nil { + return cosignOpts, fmt.Errorf("failed to fetch Rekor public keys: %w", err) + } + } else { + cosignOpts.IgnoreTlog = true + } + + // if keyless verification is enabled, set the root certificates, intermediate certificates, and certificate transparency log public keys if tp.isKeyless { roots, err := fulcio.GetRoots() if err != nil || roots == nil { return cosignOpts, fmt.Errorf("failed to get fulcio roots: %w", err) } cosignOpts.RootCerts = roots - cosignOpts.RekorClient, err = rekor.NewClient(tp.config.Keyless.RekorURL) - if err != nil { - return cosignOpts, fmt.Errorf("failed to create Rekor client from URL %s: %w", tp.config.Keyless.RekorURL, err) - } if tp.config.Keyless.CTLogVerify != nil && *tp.config.Keyless.CTLogVerify { cosignOpts.CTLogPubKeys, err = cosign.GetCTLogPubs(ctx) if err != nil { @@ -195,19 +214,21 @@ func (tp *trustPolicy) GetCosignOpts(ctx context.Context) (cosign.CheckOpts, err } else { cosignOpts.IgnoreSCT = true } - // Fetches the Rekor public keys from the Rekor server - cosignOpts.RekorPubKeys, err = cosign.GetRekorPubs(ctx) - if err != nil { - return cosignOpts, fmt.Errorf("failed to fetch Rekor public keys: %w", err) - } cosignOpts.IntermediateCerts, err = fulcio.GetIntermediates() if err != nil { return cosignOpts, fmt.Errorf("failed to get fulcio intermediate certificates: %w", err) } + // Set the certificate identity and issuer for keyless verification + cosignOpts.Identities = []cosign.Identity{ + { + IssuerRegExp: tp.config.Keyless.CertificateOIDCIssuerRegExp, + Issuer: tp.config.Keyless.CertificateOIDCIssuer, + SubjectRegExp: tp.config.Keyless.CertificateIdentityRegExp, + Subject: tp.config.Keyless.CertificateIdentity, + }, + } } - if tp.config.TLogVerify != nil && *tp.config.TLogVerify { - cosignOpts.IgnoreTlog = true - } + return cosignOpts, nil } @@ -246,16 +267,32 @@ func validate(config TrustPolicyConfig, verifierName string) error { if keyConfig.File != "" && keyConfig.Provider != "" { return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: 'name' and 'file' cannot be configured together", config.Name)) } - // key management provider is required when specific keys are configured - if keyConfig.Name != "" && keyConfig.Provider == "" { - return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: key management provider name is required when key name is defined", config.Name)) - } // key name is required when key version is defined if keyConfig.Version != "" && keyConfig.Name == "" { return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: key name is required when key version is defined", config.Name)) } } + // validate keyless configuration + if config.Keyless != (KeylessConfig{}) { + // validate certificate identity specified + if config.Keyless.CertificateIdentity == "" && config.Keyless.CertificateIdentityRegExp == "" { + return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: certificate identity or identity regex pattern is required", config.Name)) + } + // validate certificate OIDC issuer specified + if config.Keyless.CertificateOIDCIssuer == "" && config.Keyless.CertificateOIDCIssuerRegExp == "" { + return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: certificate OIDC issuer or issuer regex pattern is required", config.Name)) + } + // validate only expression or value is specified for certificate identity + if config.Keyless.CertificateIdentity != "" && config.Keyless.CertificateIdentityRegExp != "" { + return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: only one of certificate identity or identity regex pattern should be specified", config.Name)) + } + // validate only expression or value is specified for certificate OIDC issuer + if config.Keyless.CertificateOIDCIssuer != "" && config.Keyless.CertificateOIDCIssuerRegExp != "" { + return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: only one of certificate OIDC issuer or issuer regex pattern should be specified", config.Name)) + } + } + return nil } diff --git a/pkg/verifier/cosign/trustpolicy_test.go b/pkg/verifier/cosign/trustpolicy_test.go index c8d5964ab..c55a91d49 100644 --- a/pkg/verifier/cosign/trustpolicy_test.go +++ b/pkg/verifier/cosign/trustpolicy_test.go @@ -19,12 +19,45 @@ import ( "context" "crypto" "crypto/ecdsa" + "fmt" "testing" ctxUtils "github.com/deislabs/ratify/internal/context" "github.com/deislabs/ratify/pkg/keymanagementprovider" + "github.com/sigstore/cosign/v2/pkg/cosign" ) +type mockTrustPolicy struct { + name string + scopes []string + keysMap map[PKKey]keymanagementprovider.PublicKey + shouldErrKeys bool + shouldErrCosignOpts bool +} + +func (m *mockTrustPolicy) GetName() string { + return m.name +} + +func (m *mockTrustPolicy) GetScopes() []string { + return m.scopes +} + +func (m *mockTrustPolicy) GetKeys(_ context.Context, _ string) (map[PKKey]keymanagementprovider.PublicKey, error) { + if m.shouldErrKeys { + return nil, fmt.Errorf("error getting keys") + } + return m.keysMap, nil +} + +func (m *mockTrustPolicy) GetCosignOpts(_ context.Context) (cosign.CheckOpts, error) { + if m.shouldErrCosignOpts { + return cosign.CheckOpts{}, fmt.Errorf("error getting cosign opts") + } + + return cosign.CheckOpts{}, nil +} + func TestCreateTrustPolicy(t *testing.T) { tc := []struct { name string @@ -68,7 +101,8 @@ func TestCreateTrustPolicy(t *testing.T) { Name: "test", Scopes: []string{"*"}, Keyless: KeylessConfig{ - RekorURL: DefaultRekorURL, + CertificateIdentity: "test-identity", + CertificateOIDCIssuer: "https://test-issuer.com", }, }, wantErr: false, @@ -80,7 +114,8 @@ func TestCreateTrustPolicy(t *testing.T) { Name: "test", Scopes: []string{"*"}, Keyless: KeylessConfig{ - RekorURL: DefaultRekorURL, + CertificateIdentity: "test-identity", + CertificateOIDCIssuer: "https://test-issuer.com", }, }, wantErr: true, @@ -101,7 +136,7 @@ func TestGetName(t *testing.T) { trustPolicyConfig := TrustPolicyConfig{ Name: "test", Scopes: []string{"*"}, - Keyless: KeylessConfig{RekorURL: DefaultRekorURL}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, } trustPolicy, err := CreateTrustPolicy(trustPolicyConfig, "test-verifier") if err != nil { @@ -117,7 +152,7 @@ func TestGetScopes(t *testing.T) { trustPolicyConfig := TrustPolicyConfig{ Name: "test", Scopes: []string{"*"}, - Keyless: KeylessConfig{RekorURL: DefaultRekorURL}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, } trustPolicy, err := CreateTrustPolicy(trustPolicyConfig, "test-verifier") if err != nil { @@ -210,53 +245,65 @@ func TestValidate(t *testing.T) { wantErr bool }{ { - name: "no name", + name: "no version", policyConfig: TrustPolicyConfig{}, wantErr: true, }, + { + name: "no name", + policyConfig: TrustPolicyConfig{ + Version: "1.0.0", + }, + wantErr: true, + }, { name: "no scopes", policyConfig: TrustPolicyConfig{ - Name: "test", + Version: "1.0.0", + Name: "test", }, wantErr: true, }, { name: "no keys or keyless defined", policyConfig: TrustPolicyConfig{ - Name: "test", - Scopes: []string{"*"}, + Version: "1.0.0", + Name: "test", + Scopes: []string{"*"}, }, wantErr: true, }, { name: "keys and keyless defined", policyConfig: TrustPolicyConfig{ - Name: "test", - Scopes: []string{"*"}, + Version: "1.0.0", + Name: "test", + Scopes: []string{"*"}, Keys: []KeyConfig{ { Provider: "kmp", }, }, - Keyless: KeylessConfig{RekorURL: DefaultRekorURL}, + Keyless: KeylessConfig{CertificateIdentity: "test-identity", CertificateOIDCIssuer: "https://test-issuer.com"}, }, wantErr: true, }, { name: "key provider and key path not defined", policyConfig: TrustPolicyConfig{ - Name: "test", - Scopes: []string{"*"}, - Keys: []KeyConfig{{}}, + Version: "1.0.0", + Name: "test", + Scopes: []string{"*"}, + Keys: []KeyConfig{{}}, }, wantErr: true, }, { name: "key provider and key path both defined", policyConfig: TrustPolicyConfig{ - Name: "test", - Scopes: []string{"*"}, + Version: "1.0.0", + Name: "test", + Scopes: []string{"*"}, Keys: []KeyConfig{ { Provider: "kmp", @@ -269,8 +316,9 @@ func TestValidate(t *testing.T) { { name: "key provider not defined but name defined", policyConfig: TrustPolicyConfig{ - Name: "test", - Scopes: []string{"*"}, + Version: "1.0.0", + Name: "test", + Scopes: []string{"*"}, Keys: []KeyConfig{ { Name: "key name", @@ -282,8 +330,9 @@ func TestValidate(t *testing.T) { { name: "key provider name not defined but version defined", policyConfig: TrustPolicyConfig{ - Name: "test", - Scopes: []string{"*"}, + Version: "1.0.0", + Name: "test", + Scopes: []string{"*"}, Keys: []KeyConfig{ { Provider: "kmp", @@ -309,6 +358,66 @@ func TestValidate(t *testing.T) { }, wantErr: false, }, + { + name: "keyless but no certificate identity specified", + policyConfig: TrustPolicyConfig{ + Version: "1.0.0", + Name: "test", + Scopes: []string{"*"}, + Keyless: KeylessConfig{CertificateOIDCIssuer: "test"}, + }, + wantErr: true, + }, + { + name: "keyless but both certificate identity and expression specified", + policyConfig: TrustPolicyConfig{ + Version: "1.0.0", + Name: "test", + Scopes: []string{"*"}, + Keyless: KeylessConfig{CertificateIdentity: "test", CertificateIdentityRegExp: "test"}, + }, + wantErr: true, + }, + { + name: "keyless but no certificate oidc issuer specified", + policyConfig: TrustPolicyConfig{ + Version: "1.0.0", + Name: "test", + Scopes: []string{"*"}, + Keyless: KeylessConfig{CertificateIdentity: "test"}, + }, + wantErr: true, + }, + { + name: "keyless but both certificate oidc issuer and expression specified", + policyConfig: TrustPolicyConfig{ + Version: "1.0.0", + Name: "test", + Scopes: []string{"*"}, + Keyless: KeylessConfig{CertificateIdentity: "test", CertificateOIDCIssuer: "test", CertificateOIDCIssuerRegExp: "test"}, + }, + wantErr: true, + }, + { + name: "keyless but both certificate identity and expression specified", + policyConfig: TrustPolicyConfig{ + Version: "1.0.0", + Name: "test", + Scopes: []string{"*"}, + Keyless: KeylessConfig{CertificateOIDCIssuer: "test", CertificateIdentity: "test", CertificateIdentityRegExp: "test"}, + }, + wantErr: true, + }, + { + name: "valid keyless", + policyConfig: TrustPolicyConfig{ + Version: "1.0.0", + Name: "test", + Scopes: []string{"*"}, + Keyless: KeylessConfig{CertificateIdentity: "test", CertificateOIDCIssuer: "test"}, + }, + wantErr: false, + }, } for _, tt := range tc { diff --git a/test/bats/base-test.bats b/test/bats/base-test.bats index bd08de0d2..ca54ef361 100644 --- a/test/bats/base-test.bats +++ b/test/bats/base-test.bats @@ -170,7 +170,7 @@ RATIFY_NAMESPACE=gatekeeper-system assert_failure } -@test "cosign legacy test" { +@test "cosign legacy keyed test" { teardown() { echo "cleaning up" wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete pod cosign-demo-key --namespace default --force --ignore-not-found=true' @@ -203,8 +203,7 @@ RATIFY_NAMESPACE=gatekeeper-system wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl replace -f ./config/samples/clustered/store/config_v1beta1_store_oras_http.yaml' } - # use imperative command to guarantee useHttp is updated - run kubectl replace -f ./config/samples/clustered/verifier/config_v1beta1_verifier_cosign_keyless.yaml + run kubectl replace -f ./test/bats/tests/config/config_v1beta1_verifier_cosign_keyless.yaml sleep 5 run kubectl replace -f ./config/samples/clustered/store/config_v1beta1_store_oras.yaml @@ -213,6 +212,23 @@ RATIFY_NAMESPACE=gatekeeper-system wait_for_process 20 10 'kubectl run cosign-demo-keyless --namespace default --image=wabbitnetworks.azurecr.io/test/cosign-image:signed-keyless' } +@test "cosign legacy keyless test" { + teardown() { + echo "cleaning up" + wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete pod cosign-demo-keyless --namespace default --force --ignore-not-found=true' + wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl replace -f ./config/samples/clustered/verifier/config_v1beta1_verifier_cosign.yaml' + wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl replace -f ./config/samples/clustered/store/config_v1beta1_store_oras_http.yaml' + } + + # use imperative command to guarantee useHttp is updated + run kubectl replace -f ./config/samples/clustered/verifier/config_v1beta1_verifier_cosign_keyless_legacy.yaml + sleep 5 + + run kubectl replace -f ./config/samples/clustered/store/config_v1beta1_store_oras.yaml + sleep 5 + + wait_for_process 20 10 'kubectl run cosign-demo-keyless --namespace default --image=wabbitnetworks.azurecr.io/test/cosign-image:signed-keyless' +} @test "validate crd add, replace and delete" { teardown() { echo "cleaning up" diff --git a/test/bats/tests/config/config_v1beta1_verifier_cosign_akv.yaml b/test/bats/tests/config/config_v1beta1_verifier_cosign_akv.yaml index a2ca0bd81..69fb99605 100644 --- a/test/bats/tests/config/config_v1beta1_verifier_cosign_akv.yaml +++ b/test/bats/tests/config/config_v1beta1_verifier_cosign_akv.yaml @@ -15,4 +15,5 @@ spec: scopes: - "*" keys: - - provider: kmprovider-akv \ No newline at end of file + - provider: kmprovider-akv + tLogVerify: false \ No newline at end of file diff --git a/test/bats/tests/config/config_v1beta1_verifier_cosign_keyless.yaml b/test/bats/tests/config/config_v1beta1_verifier_cosign_keyless.yaml new file mode 100644 index 000000000..6e5d134c0 --- /dev/null +++ b/test/bats/tests/config/config_v1beta1_verifier_cosign_keyless.yaml @@ -0,0 +1,15 @@ +apiVersion: config.ratify.deislabs.io/v1beta1 +kind: Verifier +metadata: + name: verifier-cosign +spec: + name: cosign + artifactTypes: application/vnd.dev.cosign.artifact.sig.v1+json + parameters: + trustPolicies: + - name: default + scopes: + - '*' + keyless: + certificateIdentity: sozercan@gmail.com + certificateOIDCIssuer: https://github.com/login/oauth \ No newline at end of file From a3424b1409da1ad71dcc2ffbc59c0f8df9d56dbe Mon Sep 17 00:00:00 2001 From: Binbin Li Date: Thu, 6 Jun 2024 11:20:27 +0800 Subject: [PATCH 4/4] chore: update deislabs.github.io to ratify-project.github.io (#1548) --- .../ratify-weekly-notes-2023-Jan-2023-Jun.md | 2 +- charts/ratify/README.md | 2 +- dev.helmfile.yaml | 10 +++++----- dev.high-availability.helmfile.yaml | 10 +++++----- helmfile.yaml | 8 ++++---- high-availability.helmfile.yaml | 8 ++++---- library/default/customazurepolicy.json | 2 +- scripts/azure-ci-test.sh | 4 ++-- 8 files changed, 23 insertions(+), 23 deletions(-) diff --git a/archive/meeting-notes/ratify-weekly-notes-2023-Jan-2023-Jun.md b/archive/meeting-notes/ratify-weekly-notes-2023-Jan-2023-Jun.md index b328afce6..c70e59ca7 100644 --- a/archive/meeting-notes/ratify-weekly-notes-2023-Jan-2023-Jun.md +++ b/archive/meeting-notes/ratify-weekly-notes-2023-Jan-2023-Jun.md @@ -785,7 +785,7 @@ Recording: https://youtu.be/vn_GOUXZGhw ### Presentation/Discussion Agenda Items: - [Akash]How do we handle breaking changes that require a change to the README? (Akash) From last week - [Susan] Maybe link to github page something like https://deislabs.github.io/ratify/getting-started.html? how does csi driver maintain its docs ? https://secrets-store-csi-driver.sigs.k8s.io/getting-started/getting-started.html + [Susan] Maybe link to github page something like https://ratify-project.github.io/ratify/getting-started.html? how does csi driver maintain its docs ? https://secrets-store-csi-driver.sigs.k8s.io/getting-started/getting-started.html [Sajay] Not sure if external doc will have maintainance overhead. We can add a link to the quickstart that is pinned to a released version for now. - [Akash] Cosign auth support: https://hackmd.io/@akashsinghal/rks7vlOps diff --git a/charts/ratify/README.md b/charts/ratify/README.md index e99bb2993..862ae8ca9 100644 --- a/charts/ratify/README.md +++ b/charts/ratify/README.md @@ -3,7 +3,7 @@ ## Get Repo Info ```console -helm repo add ratify https://deislabs.github.io/ratify +helm repo add ratify https://ratify-project.github.io/ratify helm repo update ``` diff --git a/dev.helmfile.yaml b/dev.helmfile.yaml index e90fef2cc..ac8f79d25 100644 --- a/dev.helmfile.yaml +++ b/dev.helmfile.yaml @@ -2,9 +2,9 @@ repositories: - name: gatekeeper url: https://open-policy-agent.github.io/gatekeeper/charts - name: ratify - url: ghcr.io/deislabs/ratify-chart-dev # PRERELEASE: Change to 'https://deislabs.github.io/ratify' before copying to helmfile.yaml + url: ghcr.io/deislabs/ratify-chart-dev # PRERELEASE: Change to 'https://ratify-project.github.io/ratify' before copying to helmfile.yaml oci: true # PRERELEASE: Remove before copying to helmfile.yaml - + releases: - name: gatekeeper namespace: gatekeeper-system @@ -34,14 +34,14 @@ releases: command: "bash" args: - "-c" - - "kubectl apply -f https://deislabs.github.io/ratify/library/default/template.yaml && kubectl apply -f https://deislabs.github.io/ratify/library/default/samples/constraint.yaml" + - "kubectl apply -f https://ratify-project.github.io/ratify/library/default/template.yaml && kubectl apply -f https://ratify-project.github.io/ratify/library/default/samples/constraint.yaml" - events: ["postuninstall"] showlogs: true command: "kubectl" args: - "delete" - "-f" - - "https://deislabs.github.io/ratify/library/default/template.yaml" + - "https://ratify-project.github.io/ratify/library/default/template.yaml" - "--ignore-not-found=true" - events: ["postuninstall"] showlogs: true @@ -49,7 +49,7 @@ releases: args: - "delete" - "-f" - - "https://deislabs.github.io/ratify/library/default/samples/constraint.yaml" + - "https://ratify-project.github.io/ratify/library/default/samples/constraint.yaml" - "--ignore-not-found=true" - events: ["postuninstall"] showlogs: true diff --git a/dev.high-availability.helmfile.yaml b/dev.high-availability.helmfile.yaml index c26fb318d..20f1fd408 100644 --- a/dev.high-availability.helmfile.yaml +++ b/dev.high-availability.helmfile.yaml @@ -6,9 +6,9 @@ repositories: - name: bitnami url: https://charts.bitnami.com/bitnami - name: ratify - url: ghcr.io/deislabs/ratify-chart-dev # PRERELEASE: Change to 'https://deislabs.github.io/ratify' before copying to helmfile.yaml + url: ghcr.io/deislabs/ratify-chart-dev # PRERELEASE: Change to 'https://ratify-project.github.io/ratify' before copying to helmfile.yaml oci: true # PRERELEASE: Remove before copying to helmfile.yaml - + releases: - name: dapr namespace: dapr-system @@ -78,7 +78,7 @@ releases: command: "bash" args: - "-c" - - "kubectl apply -f https://deislabs.github.io/ratify/library/default/template.yaml && kubectl apply -f https://deislabs.github.io/ratify/library/default/samples/constraint.yaml" + - "kubectl apply -f https://ratify-project.github.io/ratify/library/default/template.yaml && kubectl apply -f https://ratify-project.github.io/ratify/library/default/samples/constraint.yaml" - events: ["postuninstall"] showlogs: true command: "kubectl" @@ -105,7 +105,7 @@ releases: args: - "delete" - "-f" - - "https://deislabs.github.io/ratify/library/default/template.yaml" + - "https://ratify-project.github.io/ratify/library/default/template.yaml" - "--ignore-not-found=true" - events: ["postuninstall"] showlogs: true @@ -113,7 +113,7 @@ releases: args: - "delete" - "-f" - - "https://deislabs.github.io/ratify/library/default/samples/constraint.yaml" + - "https://ratify-project.github.io/ratify/library/default/samples/constraint.yaml" - "--ignore-not-found=true" - events: ["postuninstall"] showlogs: true diff --git a/helmfile.yaml b/helmfile.yaml index ef854c134..be9cecf7c 100644 --- a/helmfile.yaml +++ b/helmfile.yaml @@ -2,7 +2,7 @@ repositories: - name: gatekeeper url: https://open-policy-agent.github.io/gatekeeper/charts - name: ratify - url: https://deislabs.github.io/ratify + url: https://ratify-project.github.io/ratify releases: - name: gatekeeper @@ -33,14 +33,14 @@ releases: command: "bash" args: - "-c" - - "kubectl apply -f https://deislabs.github.io/ratify/library/default/template.yaml && kubectl apply -f https://deislabs.github.io/ratify/library/default/samples/constraint.yaml" + - "kubectl apply -f https://ratify-project.github.io/ratify/library/default/template.yaml && kubectl apply -f https://ratify-project.github.io/ratify/library/default/samples/constraint.yaml" - events: ["postuninstall"] showlogs: true command: "kubectl" args: - "delete" - "-f" - - "https://deislabs.github.io/ratify/library/default/template.yaml" + - "https://ratify-project.github.io/ratify/library/default/template.yaml" - "--ignore-not-found=true" - events: ["postuninstall"] showlogs: true @@ -48,7 +48,7 @@ releases: args: - "delete" - "-f" - - "https://deislabs.github.io/ratify/library/default/samples/constraint.yaml" + - "https://ratify-project.github.io/ratify/library/default/samples/constraint.yaml" - "--ignore-not-found=true" - events: ["postuninstall"] showlogs: true diff --git a/high-availability.helmfile.yaml b/high-availability.helmfile.yaml index bc2a2f952..331d88af9 100644 --- a/high-availability.helmfile.yaml +++ b/high-availability.helmfile.yaml @@ -6,7 +6,7 @@ repositories: - name: bitnami url: https://charts.bitnami.com/bitnami - name: ratify - url: https://deislabs.github.io/ratify + url: https://ratify-project.github.io/ratify releases: - name: dapr @@ -77,7 +77,7 @@ releases: command: "bash" args: - "-c" - - "kubectl apply -f https://deislabs.github.io/ratify/library/default/template.yaml && kubectl apply -f https://deislabs.github.io/ratify/library/default/samples/constraint.yaml" + - "kubectl apply -f https://ratify-project.github.io/ratify/library/default/template.yaml && kubectl apply -f https://ratify-project.github.io/ratify/library/default/samples/constraint.yaml" - events: ["postuninstall"] showlogs: true command: "kubectl" @@ -104,7 +104,7 @@ releases: args: - "delete" - "-f" - - "https://deislabs.github.io/ratify/library/default/template.yaml" + - "https://ratify-project.github.io/ratify/library/default/template.yaml" - "--ignore-not-found=true" - events: ["postuninstall"] showlogs: true @@ -112,7 +112,7 @@ releases: args: - "delete" - "-f" - - "https://deislabs.github.io/ratify/library/default/samples/constraint.yaml" + - "https://ratify-project.github.io/ratify/library/default/samples/constraint.yaml" - "--ignore-not-found=true" - events: ["postuninstall"] showlogs: true diff --git a/library/default/customazurepolicy.json b/library/default/customazurepolicy.json index 52b16c5c4..6572fffe8 100644 --- a/library/default/customazurepolicy.json +++ b/library/default/customazurepolicy.json @@ -106,7 +106,7 @@ "details": { "templateInfo": { "sourceType": "PublicURL", - "url": "https://deislabs.github.io/ratify/library/default/template.yaml" + "url": "https://ratify-project.github.io/ratify/library/default/template.yaml" }, "apiGroups": [ "" diff --git a/scripts/azure-ci-test.sh b/scripts/azure-ci-test.sh index 9489182d9..0289c684f 100755 --- a/scripts/azure-ci-test.sh +++ b/scripts/azure-ci-test.sh @@ -79,8 +79,8 @@ deploy_ratify() { kubectl delete verifiers.config.ratify.deislabs.io/verifier-cosign - kubectl apply -f https://deislabs.github.io/ratify/library/default/template.yaml - kubectl apply -f https://deislabs.github.io/ratify/library/default/samples/constraint.yaml + kubectl apply -f https://ratify-project.github.io/ratify/library/default/template.yaml + kubectl apply -f https://ratify-project.github.io/ratify/library/default/samples/constraint.yaml } upload_cert_to_akv() {