feat: add support for oci1.1 cosign signatures(using referrers) (#1963)

- Cosign supports 2 types of signature formats:

	1. Using tag -> each new signature of the same manifest is
	added as a new layer of the signature manifest having that
	specific tag("{alghoritm}-{digest_of_signed_manifest}.sig")

	2. Using referrers -> each new signature of the same manifest is
	added as a new manifest

- For adding these cosign signature to metadb, we reserved index 0 of the
list of cosign signatures for tag-based signatures. When a new tag-based
signature is added for the same manifest, the element on first position
in its list of cosign signatures(in metadb) will be updated/overwritten.
When a new cosign signature(using referrers) will be added for the same
manifest this new signature will be appended to the list of cosign
signatures.

Signed-off-by: Andreea-Lupu <andreealupu1470@yahoo.com>
This commit is contained in:
Andreea Lupu
2023-11-07 00:09:39 +02:00
committed by GitHub
parent 6a66a9b9b4
commit d5065513f5
21 changed files with 511 additions and 85 deletions
+8 -8
View File
@@ -1349,7 +1349,7 @@ func TestExpandedRepoInfo(t *testing.T) {
}
So(found, ShouldEqual, true)
err = signature.SignImageUsingCosign("zot-cve-test:0.0.1", port)
err = signature.SignImageUsingCosign("zot-cve-test:0.0.1", port, false)
So(err, ShouldBeNil)
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(query))
@@ -1421,7 +1421,7 @@ func TestExpandedRepoInfo(t *testing.T) {
}
So(found, ShouldEqual, true)
err = signature.SignImageUsingCosign("zot-test@"+testManifestDigest.String(), port)
err = signature.SignImageUsingCosign("zot-test@"+testManifestDigest.String(), port, false)
So(err, ShouldBeNil)
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "/query?query=" + url.QueryEscape(query))
@@ -3759,7 +3759,7 @@ func TestGlobalSearchFiltering(t *testing.T) {
)
So(err, ShouldBeNil)
err = signature.SignImageUsingCosign("signed-repo:test", port)
err = signature.SignImageUsingCosign("signed-repo:test", port, false)
So(err, ShouldBeNil)
query := `{
@@ -4323,7 +4323,7 @@ func TestMetaDBWhenSigningImages(t *testing.T) {
`
Convey("Sign with cosign", func() {
err = signature.SignImageUsingCosign("repo1:1.0.1", port)
err = signature.SignImageUsingCosign("repo1:1.0.1", port, false)
So(err, ShouldBeNil)
resp, err := resty.R().Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(queryImage1))
@@ -4403,7 +4403,7 @@ func TestMetaDBWhenSigningImages(t *testing.T) {
},
}
err := signature.SignImageUsingCosign("repo1:1.0.1", port)
err := signature.SignImageUsingCosign("repo1:1.0.1", port, false)
So(err, ShouldNotBeNil)
})
})
@@ -4443,7 +4443,7 @@ func TestMetaDBWhenSigningImages(t *testing.T) {
})
Convey("Sign with cosign index", func() {
err = signature.SignImageUsingCosign("repo1:index", port)
err = signature.SignImageUsingCosign("repo1:index", port, false)
So(err, ShouldBeNil)
resp, err := resty.R().Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(queryIndex))
@@ -4572,7 +4572,7 @@ func RunMetaDBIndexTests(baseURL, port string) {
responseImage := responseImages[0]
So(len(responseImage.Manifests), ShouldEqual, 3)
err = signature.SignImageUsingCosign(fmt.Sprintf("repo@%s", multiarchImage.DigestStr()), port)
err = signature.SignImageUsingCosign(fmt.Sprintf("repo@%s", multiarchImage.DigestStr()), port, false)
So(err, ShouldBeNil)
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(query))
@@ -5301,7 +5301,7 @@ func TestMetaDBWhenDeletingImages(t *testing.T) {
Convey("Delete a cosign signature", func() {
repo := "repo1"
err := signature.SignImageUsingCosign("repo1:1.0.1", port)
err := signature.SignImageUsingCosign("repo1:1.0.1", port, false)
So(err, ShouldBeNil)
query := `
+1 -1
View File
@@ -53,7 +53,7 @@ func (ref OciReferences) IsSigned(ctx context.Context, remoteRepo, subjectDigest
return false
}
if len(getNotationManifestsFromOCIRefs(index)) > 0 {
if len(getNotationManifestsFromOCIRefs(index)) > 0 || len(getCosignManifestsFromOCIRefs(index)) > 0 {
return true
}
+7 -14
View File
@@ -17,7 +17,6 @@ import (
"zotregistry.io/zot/pkg/common"
client "zotregistry.io/zot/pkg/extensions/sync/httpclient"
"zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/meta"
mTypes "zotregistry.io/zot/pkg/meta/types"
"zotregistry.io/zot/pkg/storage"
storageTypes "zotregistry.io/zot/pkg/storage/types"
@@ -218,20 +217,14 @@ func getNotationManifestsFromOCIRefs(ociRefs ispec.Index) []ispec.Descriptor {
return notaryManifests
}
func addSigToMeta(
metaDB mTypes.MetaDB, repo, sigType, tag string, signedManifestDig, referenceDigest godigest.Digest,
referenceBuf []byte, imageStore storageTypes.ImageStore, log log.Logger,
) error {
layersInfo, errGetLayers := meta.GetSignatureLayersInfo(repo, tag, referenceDigest.String(),
sigType, referenceBuf, imageStore, log)
func getCosignManifestsFromOCIRefs(ociRefs ispec.Index) []ispec.Descriptor {
cosignManifests := []ispec.Descriptor{}
if errGetLayers != nil {
return errGetLayers
for _, ref := range ociRefs.Manifests {
if ref.ArtifactType == common.ArtifactTypeCosign {
cosignManifests = append(cosignManifests, ref)
}
}
return metaDB.AddManifestSignature(repo, signedManifestDig, mTypes.SignatureMetadata{
SignatureType: sigType,
SignatureDigest: referenceDigest.String(),
LayersInfo: layersInfo,
})
return cosignManifests
}
@@ -440,14 +440,3 @@ func TestCompareArtifactRefs(t *testing.T) {
}
})
}
func TestAddSigToMeta(t *testing.T) {
Convey("Test addSigToMeta", t, func() {
imageStore := mocks.MockedImageStore{}
metaDB := mocks.MetaDBMock{}
err := addSigToMeta(metaDB, "repo", "cosign", "tag", godigest.FromString("signedmanifest"),
godigest.FromString("reference"), []byte("bad"), imageStore, log.Logger{})
So(err, ShouldNotBeNil)
})
}
+100 -3
View File
@@ -746,7 +746,7 @@ func TestOnDemand(t *testing.T) {
So(err, ShouldBeNil)
// sign using cosign
err = signature.SignImageUsingCosign(fmt.Sprintf("remote-repo@%s", manifestDigest.String()), port)
err = signature.SignImageUsingCosign(fmt.Sprintf("remote-repo@%s", manifestDigest.String()), port, false)
So(err, ShouldBeNil)
// add cosign sbom
@@ -4593,6 +4593,100 @@ func TestSignatures(t *testing.T) {
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
})
Convey("Verify sync oci1.1 cosign signatures", t, func() {
updateDuration, _ := time.ParseDuration("30m")
sctlr, srcBaseURL, _, _, _ := makeUpstreamServer(t, false, false)
scm := test.NewControllerManager(sctlr)
scm.StartAndWait(sctlr.Config.HTTP.Port)
defer scm.StopServer()
// create repo, push and sign it
repoName := testSignedImage
var digest godigest.Digest
So(func() { digest = pushRepo(srcBaseURL, repoName) }, ShouldNotPanic)
splittedURL := strings.SplitAfter(srcBaseURL, ":")
srcPort := splittedURL[len(splittedURL)-1]
t.Logf(srcPort)
err := signature.SignImageUsingCosign(fmt.Sprintf("%s@%s", repoName, digest.String()), srcPort, true)
So(err, ShouldBeNil)
regex := ".*"
var semver bool
var tlsVerify bool
onlySigned := true
syncRegistryConfig := syncconf.RegistryConfig{
Content: []syncconf.Content{
{
Prefix: "**",
Tags: &syncconf.Tags{
Regex: &regex,
Semver: &semver,
},
},
},
URLs: []string{srcBaseURL},
PollInterval: updateDuration,
TLSVerify: &tlsVerify,
CertDir: "",
OnlySigned: &onlySigned,
OnDemand: true,
}
defaultVal := true
syncConfig := &syncconf.Config{
Enable: &defaultVal,
Registries: []syncconf.RegistryConfig{syncRegistryConfig},
}
dctlr, destBaseURL, _, destClient := makeDownstreamServer(t, false, syncConfig)
dcm := test.NewControllerManager(dctlr)
dcm.StartAndWait(dctlr.Config.HTTP.Port)
defer dcm.StopServer()
// wait for sync
var destTagsList TagsList
for {
resp, err := destClient.R().Get(destBaseURL + "/v2/" + repoName + "/tags/list")
if err != nil {
panic(err)
}
err = json.Unmarshal(resp.Body(), &destTagsList)
if err != nil {
panic(err)
}
if len(destTagsList.Tags) > 0 {
break
}
time.Sleep(500 * time.Millisecond)
}
time.Sleep(1 * time.Second)
// get oci references from downstream, should be synced
getOCIReferrersURL := destBaseURL + path.Join("/v2", repoName, "referrers", digest.String())
resp, err := resty.R().Get(getOCIReferrersURL)
So(err, ShouldBeNil)
So(resp, ShouldNotBeEmpty)
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
var index ispec.Index
err = json.Unmarshal(resp.Body(), &index)
So(err, ShouldBeNil)
So(len(index.Manifests), ShouldEqual, 3)
})
}
func getPortFromBaseURL(baseURL string) string {
@@ -4626,7 +4720,10 @@ func TestSyncedSignaturesMetaDB(t *testing.T) {
err = signature.SignImageUsingNotary(repoName+":"+tag, srcPort, true)
So(err, ShouldBeNil)
err = signature.SignImageUsingCosign(repoName+":"+tag, srcPort)
err = signature.SignImageUsingCosign(repoName+":"+tag, srcPort, true)
So(err, ShouldBeNil)
err = signature.SignImageUsingCosign(repoName+":"+tag, srcPort, false)
So(err, ShouldBeNil)
// Create destination registry
@@ -4676,7 +4773,7 @@ func TestSyncedSignaturesMetaDB(t *testing.T) {
imageSignatures := repoMeta.Signatures[signedImage.DigestStr()]
So(imageSignatures, ShouldContainKey, zcommon.CosignSignature)
So(len(imageSignatures[zcommon.CosignSignature]), ShouldEqual, 1)
So(len(imageSignatures[zcommon.CosignSignature]), ShouldEqual, 2)
So(imageSignatures, ShouldContainKey, zcommon.NotationSignature)
So(len(imageSignatures[zcommon.NotationSignature]), ShouldEqual, 1)
})