feat: upload cosign public key and notation certificates to cloud (#1744)

- using secrets manager for storing public keys and certificates
- adding a default truststore for notation verification and upload all certificates to this default truststore
- removig `truststoreName` query param from notation api for uploading certificates


(cherry picked from commit eafcc1a213)

Signed-off-by: Andreea-Lupu <andreealupu1470@yahoo.com>
This commit is contained in:
Andreea Lupu
2023-09-08 10:03:58 +03:00
committed by GitHub
parent 6115eed4ec
commit 5a3fac40db
27 changed files with 1661 additions and 563 deletions
+24 -9
View File
@@ -15,7 +15,6 @@ import (
zerr "zotregistry.io/zot/errors"
"zotregistry.io/zot/pkg/api/constants"
zcommon "zotregistry.io/zot/pkg/common"
"zotregistry.io/zot/pkg/extensions/imagetrust"
"zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/meta/common"
mTypes "zotregistry.io/zot/pkg/meta/types"
@@ -24,9 +23,10 @@ import (
)
type BoltDB struct {
DB *bbolt.DB
Patches []func(DB *bbolt.DB) error
Log log.Logger
DB *bbolt.DB
Patches []func(DB *bbolt.DB) error
imgTrustStore mTypes.ImageTrustStore
Log log.Logger
}
func New(boltDB *bbolt.DB, log log.Logger) (*BoltDB, error) {
@@ -73,12 +73,21 @@ func New(boltDB *bbolt.DB, log log.Logger) (*BoltDB, error) {
}
return &BoltDB{
DB: boltDB,
Patches: version.GetBoltDBPatches(),
Log: log,
DB: boltDB,
Patches: version.GetBoltDBPatches(),
imgTrustStore: nil,
Log: log,
}, nil
}
func (bdw *BoltDB) ImageTrustStore() mTypes.ImageTrustStore {
return bdw.imgTrustStore
}
func (bdw *BoltDB) SetImageTrustStore(imgTrustStore mTypes.ImageTrustStore) {
bdw.imgTrustStore = imgTrustStore
}
func (bdw *BoltDB) SetManifestData(manifestDigest godigest.Digest, manifestData mTypes.ManifestData) error {
err := bdw.DB.Update(func(tx *bbolt.Tx) error {
buck := tx.Bucket([]byte(ManifestDataBucket))
@@ -722,6 +731,12 @@ func (bdw *BoltDB) IncrementImageDownloads(repo string, reference string) error
func (bdw *BoltDB) UpdateSignaturesValidity(repo string, manifestDigest godigest.Digest) error {
err := bdw.DB.Update(func(transaction *bbolt.Tx) error {
imgTrustStore := bdw.ImageTrustStore()
if imgTrustStore == nil {
return nil
}
// get ManifestData of signed manifest
manifestBuck := transaction.Bucket([]byte(ManifestDataBucket))
mdBlob := manifestBuck.Get([]byte(manifestDigest))
@@ -779,8 +794,8 @@ func (bdw *BoltDB) UpdateSignaturesValidity(repo string, manifestDigest godigest
layersInfo := []mTypes.LayerInfo{}
for _, layerInfo := range sigInfo.LayersInfo {
author, date, isTrusted, _ := imagetrust.VerifySignature(sigType, layerInfo.LayerContent, layerInfo.SignatureKey,
manifestDigest, blob, repo)
author, date, isTrusted, _ := imgTrustStore.VerifySignature(sigType, layerInfo.LayerContent,
layerInfo.SignatureKey, manifestDigest, blob, repo)
if isTrusted {
layerInfo.Signer = author
+12
View File
@@ -7,6 +7,7 @@ import (
"encoding/json"
"math"
"testing"
"time"
"github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
@@ -22,6 +23,15 @@ import (
"zotregistry.io/zot/pkg/test"
)
type imgTrustStore struct{}
func (its imgTrustStore) VerifySignature(
signatureType string, rawSignature []byte, sigKey string, manifestDigest digest.Digest, manifestContent []byte,
repo string,
) (string, time.Time, bool, error) {
return "", time.Time{}, false, nil
}
func TestWrapperErrors(t *testing.T) {
Convey("Errors", t, func() {
tmpDir := t.TempDir()
@@ -35,6 +45,8 @@ func TestWrapperErrors(t *testing.T) {
So(boltdbWrapper, ShouldNotBeNil)
So(err, ShouldBeNil)
boltdbWrapper.SetImageTrustStore(imgTrustStore{})
repoMeta := mTypes.RepoMetadata{
Tags: map[string]mTypes.Descriptor{},
Signatures: map[string]mTypes.ManifestSignatures{},
+20 -3
View File
@@ -18,7 +18,6 @@ import (
zerr "zotregistry.io/zot/errors"
"zotregistry.io/zot/pkg/api/constants"
zcommon "zotregistry.io/zot/pkg/common"
"zotregistry.io/zot/pkg/extensions/imagetrust"
"zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/meta/common"
mTypes "zotregistry.io/zot/pkg/meta/types"
@@ -37,10 +36,13 @@ type DynamoDB struct {
UserDataTablename string
VersionTablename string
Patches []func(client *dynamodb.Client, tableNames map[string]string) error
imgTrustStore mTypes.ImageTrustStore
Log log.Logger
}
func New(client *dynamodb.Client, params DBDriverParameters, log log.Logger) (*DynamoDB, error) {
func New(
client *dynamodb.Client, params DBDriverParameters, log log.Logger,
) (*DynamoDB, error) {
dynamoWrapper := DynamoDB{
Client: client,
RepoMetaTablename: params.RepoMetaTablename,
@@ -50,6 +52,7 @@ func New(client *dynamodb.Client, params DBDriverParameters, log log.Logger) (*D
UserDataTablename: params.UserDataTablename,
APIKeyTablename: params.APIKeyTablename,
Patches: version.GetDynamoDBPatches(),
imgTrustStore: nil,
Log: log,
}
@@ -87,6 +90,14 @@ func New(client *dynamodb.Client, params DBDriverParameters, log log.Logger) (*D
return &dynamoWrapper, nil
}
func (dwr *DynamoDB) ImageTrustStore() mTypes.ImageTrustStore {
return dwr.imgTrustStore
}
func (dwr *DynamoDB) SetImageTrustStore(imgTrustStore mTypes.ImageTrustStore) {
dwr.imgTrustStore = imgTrustStore
}
func (dwr *DynamoDB) SetManifestData(manifestDigest godigest.Digest, manifestData mTypes.ManifestData) error {
mdAttributeValue, err := attributevalue.Marshal(manifestData)
if err != nil {
@@ -625,6 +636,12 @@ func (dwr *DynamoDB) IncrementImageDownloads(repo string, reference string) erro
}
func (dwr *DynamoDB) UpdateSignaturesValidity(repo string, manifestDigest godigest.Digest) error {
imgTrustStore := dwr.ImageTrustStore()
if imgTrustStore == nil {
return nil
}
// get ManifestData of signed manifest
var blob []byte
@@ -659,7 +676,7 @@ func (dwr *DynamoDB) UpdateSignaturesValidity(repo string, manifestDigest godige
layersInfo := []mTypes.LayerInfo{}
for _, layerInfo := range sigInfo.LayersInfo {
author, date, isTrusted, _ := imagetrust.VerifySignature(sigType, layerInfo.LayerContent, layerInfo.SignatureKey,
author, date, isTrusted, _ := imgTrustStore.VerifySignature(sigType, layerInfo.LayerContent, layerInfo.SignatureKey,
manifestDigest, blob, repo)
if isTrusted {
+9
View File
@@ -17,6 +17,7 @@ import (
"github.com/rs/zerolog"
. "github.com/smartystreets/goconvey/convey"
"zotregistry.io/zot/pkg/extensions/imagetrust"
"zotregistry.io/zot/pkg/log"
mdynamodb "zotregistry.io/zot/pkg/meta/dynamodb"
mTypes "zotregistry.io/zot/pkg/meta/types"
@@ -164,9 +165,14 @@ func TestWrapperErrors(t *testing.T) {
client, err := mdynamodb.GetDynamoClient(params) //nolint:contextcheck
So(err, ShouldBeNil)
imgTrustStore, err := imagetrust.NewAWSImageTrustStore(params.Region, params.Endpoint)
So(err, ShouldBeNil)
dynamoWrapper, err := mdynamodb.New(client, params, log) //nolint:contextcheck
So(err, ShouldBeNil)
dynamoWrapper.SetImageTrustStore(imgTrustStore)
So(dynamoWrapper.ResetManifestDataTable(), ShouldBeNil) //nolint:contextcheck
So(dynamoWrapper.ResetRepoMetaTable(), ShouldBeNil) //nolint:contextcheck
@@ -697,6 +703,9 @@ func TestWrapperErrors(t *testing.T) {
err = dynamoWrapper.UpdateSignaturesValidity("repo", "dig")
So(err, ShouldNotBeNil)
err = dynamoWrapper.UpdateSignaturesValidity("repo", digest.FromString("dig"))
So(err, ShouldBeNil)
})
Convey("UpdateSignaturesValidity GetRepoMeta error", func() {
-6
View File
@@ -6,7 +6,6 @@ import (
"zotregistry.io/zot/errors"
"zotregistry.io/zot/pkg/api/config"
"zotregistry.io/zot/pkg/extensions/imagetrust"
"zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/meta/boltdb"
mdynamodb "zotregistry.io/zot/pkg/meta/dynamodb"
@@ -33,11 +32,6 @@ func New(storageConfig config.StorageConfig, log log.Logger) (mTypes.MetaDB, err
return nil, err
}
err = imagetrust.InitCosignAndNotationDirs(params.RootDir)
if err != nil {
return nil, err
}
return Create("boltdb", driver, params, log) //nolint:contextcheck
}
+41 -70
View File
@@ -6,6 +6,7 @@ package meta_test
import (
"context"
"encoding/json"
"fmt"
"math/rand"
"os"
"path"
@@ -22,7 +23,6 @@ import (
ispec "github.com/opencontainers/image-spec/specs-go/v1"
. "github.com/smartystreets/goconvey/convey"
"zotregistry.io/zot/pkg/api/config"
"zotregistry.io/zot/pkg/extensions/imagetrust"
"zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/meta"
@@ -43,9 +43,12 @@ const (
func TestBoltDB(t *testing.T) {
Convey("BoltDB creation", t, func() {
boltDBParams := boltdb.DBParameters{}
boltDBParams := boltdb.DBParameters{RootDir: t.TempDir()}
repoDBPath := path.Join(boltDBParams.RootDir, "repo.db")
boltDriver, err := boltdb.GetBoltDriver(boltDBParams)
So(err, ShouldBeNil)
defer os.Remove(repoDBPath)
log := log.NewLogger("debug", "")
@@ -53,27 +56,36 @@ func TestBoltDB(t *testing.T) {
So(metaDB, ShouldNotBeNil)
So(err, ShouldBeNil)
err = os.Chmod("repo.db", 0o200)
err = os.Chmod(repoDBPath, 0o200)
So(err, ShouldBeNil)
_, err = boltdb.GetBoltDriver(boltDBParams)
So(err, ShouldNotBeNil)
err = os.Chmod("repo.db", 0o600)
err = os.Chmod(repoDBPath, 0o600)
So(err, ShouldBeNil)
defer os.Remove("repo.db")
})
Convey("BoltDB Wrapper", t, func() {
boltDBParams := boltdb.DBParameters{}
boltDBParams := boltdb.DBParameters{RootDir: t.TempDir()}
boltDriver, err := boltdb.GetBoltDriver(boltDBParams)
So(err, ShouldBeNil)
log := log.NewLogger("debug", "")
imgTrustStore, err := imagetrust.NewLocalImageTrustStore(boltDBParams.RootDir)
So(err, ShouldBeNil)
boltdbWrapper, err := boltdb.New(boltDriver, log)
defer os.Remove("repo.db")
boltdbWrapper.SetImageTrustStore(imgTrustStore)
defer func() {
os.Remove(path.Join(boltDBParams.RootDir, "repo.db"))
os.RemoveAll(path.Join(boltDBParams.RootDir, "_cosign"))
os.RemoveAll(path.Join(boltDBParams.RootDir, "_notation"))
}()
So(boltdbWrapper, ShouldNotBeNil)
So(err, ShouldBeNil)
@@ -108,6 +120,8 @@ func TestDynamoDBWrapper(t *testing.T) {
Region: "us-east-2",
}
t.Logf("using dynamo driver options: %v", dynamoDBDriverParams)
dynamoClient, err := mdynamodb.GetDynamoClient(dynamoDBDriverParams)
So(err, ShouldBeNil)
@@ -117,6 +131,11 @@ func TestDynamoDBWrapper(t *testing.T) {
So(dynamoDriver, ShouldNotBeNil)
So(err, ShouldBeNil)
imgTrustStore, err := imagetrust.NewAWSImageTrustStore(dynamoDBDriverParams.Region, dynamoDBDriverParams.Endpoint)
So(err, ShouldBeNil)
dynamoDriver.SetImageTrustStore(imgTrustStore)
resetDynamoDBTables := func() error {
err := dynamoDriver.ResetRepoMetaTable()
if err != nil {
@@ -1300,7 +1319,6 @@ func RunMetaDBTests(t *testing.T, metaDB mTypes.MetaDB, preparationFuncs ...func
So(repoData.Signatures[string(manifestDigest1)]["cosign"][0].LayersInfo[0].Date,
ShouldBeZeroValue)
})
Convey("trusted signature", func() {
_, _, manifest, _ := test.GetRandomImageComponents(10) //nolint:staticcheck
manifestContent, _ := json.Marshal(manifest)
@@ -1326,7 +1344,10 @@ func RunMetaDBTests(t *testing.T, metaDB mTypes.MetaDB, preparationFuncs ...func
}
tdir := t.TempDir()
keyName := "notation-sign-test"
uuid, err := guuid.NewV4()
So(err, ShouldBeNil)
keyName := fmt.Sprintf("notation-sign-test-%s", uuid)
test.NotationPathLock.Lock()
defer test.NotationPathLock.Unlock()
@@ -1376,44 +1397,18 @@ func RunMetaDBTests(t *testing.T, metaDB mTypes.MetaDB, preparationFuncs ...func
})
So(err, ShouldBeNil)
err = imagetrust.InitNotationDir(tdir)
certificateContent, err := os.ReadFile(path.Join(
tdir,
"notation/localkeys",
fmt.Sprintf("%s.crt", keyName),
))
So(err, ShouldBeNil)
So(certificateContent, ShouldNotBeNil)
trustpolicyPath := path.Join(tdir, "_notation/trustpolicy.json")
imgTrustStore, ok := metaDB.ImageTrustStore().(*imagetrust.ImageTrustStore)
So(ok, ShouldBeTrue)
trustPolicy := `
{
"version": "1.0",
"trustPolicies": [
{
"name": "notation-sign-test",
"registryScopes": [ "*" ],
"signatureVerification": {
"level" : "strict"
},
"trustStores": ["ca:notation-sign-test"],
"trustedIdentities": [
"*"
]
}
]
}`
file, err := os.Create(trustpolicyPath)
So(err, ShouldBeNil)
defer file.Close()
_, err = file.WriteString(trustPolicy)
So(err, ShouldBeNil)
truststore := "_notation/truststore/x509/ca/notation-sign-test"
truststoreSrc := "notation/truststore/x509/ca/notation-sign-test"
err = os.MkdirAll(path.Join(tdir, truststore), 0o755)
So(err, ShouldBeNil)
err = test.CopyFile(path.Join(tdir, truststoreSrc, "notation-sign-test.crt"),
path.Join(tdir, truststore, "notation-sign-test.crt"))
err = imagetrust.UploadCertificate(imgTrustStore.NotationStorage, certificateContent, "ca")
So(err, ShouldBeNil)
err = metaDB.UpdateSignaturesValidity(repo, manifestDigest) //nolint:contextcheck
@@ -1421,6 +1416,7 @@ func RunMetaDBTests(t *testing.T, metaDB mTypes.MetaDB, preparationFuncs ...func
repoData, err := metaDB.GetRepoMeta(repo)
So(err, ShouldBeNil)
So(repoData.Signatures[string(manifestDigest)]["notation"][0].LayersInfo[0].Signer,
ShouldNotBeEmpty)
So(repoData.Signatures[string(manifestDigest)]["notation"][0].LayersInfo[0].Date,
@@ -2693,31 +2689,6 @@ func TestCreateBoltDB(t *testing.T) {
})
}
func TestNew(t *testing.T) {
Convey("InitCosignAndNotationDirs fails", t, func() {
rootDir := t.TempDir()
var storageConfig config.StorageConfig
storageConfig.RootDirectory = rootDir
storageConfig.RemoteCache = false
log := log.NewLogger("debug", "")
_, err := os.Create(path.Join(rootDir, "repo.db"))
So(err, ShouldBeNil)
err = os.Chmod(rootDir, 0o555)
So(err, ShouldBeNil)
newMetaDB, err := meta.New(storageConfig, log)
So(newMetaDB, ShouldBeNil)
So(err, ShouldNotBeNil)
err = os.Chmod(rootDir, 0o777)
So(err, ShouldBeNil)
})
}
func skipDynamo(t *testing.T) {
t.Helper()
+11
View File
@@ -121,6 +121,10 @@ type MetaDB interface { //nolint:interfacebloat
[]RepoMetadata, map[string]ManifestMetadata, map[string]IndexData, error)
PatchDB() error
ImageTrustStore() ImageTrustStore
SetImageTrustStore(imgTrustStore ImageTrustStore)
}
type UserDB interface { //nolint:interfacebloat
@@ -160,6 +164,13 @@ type UserDB interface { //nolint:interfacebloat
DeleteUserAPIKey(ctx context.Context, id string) error
}
type ImageTrustStore interface {
VerifySignature(
signatureType string, rawSignature []byte, sigKey string, manifestDigest godigest.Digest, manifestContent []byte,
repo string,
) (string, time.Time, bool, error)
}
type ManifestMetadata struct {
ManifestBlob []byte
ConfigBlob []byte
+2 -1
View File
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"os"
"path"
"testing"
"github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue"
@@ -31,7 +32,7 @@ func TestVersioningBoltDB(t *testing.T) {
log := log.NewLogger("debug", "")
boltdbWrapper, err := boltdb.New(boltDriver, log)
defer os.Remove("repo.db")
defer os.Remove(path.Join(boltDBParams.RootDir, "repo.db"))
So(boltdbWrapper, ShouldNotBeNil)
So(err, ShouldBeNil)