0
Fork 0
mirror of https://github.com/project-zot/zot.git synced 2024-12-16 21:56:37 -05:00
zot/pkg/extensions/extension_image_trust.go
Andreea Lupu 5a3fac40db
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>
2023-09-08 10:03:58 +03:00

193 lines
6.1 KiB
Go

//go:build imagetrust
// +build imagetrust
package extensions
import (
"errors"
"io"
"net/http"
"time"
"github.com/gorilla/mux"
zerr "zotregistry.io/zot/errors"
"zotregistry.io/zot/pkg/api/config"
"zotregistry.io/zot/pkg/api/constants"
zcommon "zotregistry.io/zot/pkg/common"
"zotregistry.io/zot/pkg/extensions/imagetrust"
"zotregistry.io/zot/pkg/log"
mTypes "zotregistry.io/zot/pkg/meta/types"
"zotregistry.io/zot/pkg/scheduler"
)
func IsBuiltWithImageTrustExtension() bool {
return true
}
func SetupImageTrustRoutes(conf *config.Config, router *mux.Router, metaDB mTypes.MetaDB, log log.Logger) {
if !conf.IsImageTrustEnabled() || (!conf.IsCosignEnabled() && !conf.IsNotationEnabled()) {
log.Info().Msg("skip enabling the image trust routes as the config prerequisites are not met")
return
}
log.Info().Msg("setting up image trust routes")
imgTrustStore, _ := metaDB.ImageTrustStore().(*imagetrust.ImageTrustStore)
trust := ImageTrust{Conf: conf, ImageTrustStore: imgTrustStore, Log: log}
allowedMethods := zcommon.AllowedMethods(http.MethodPost)
if conf.IsNotationEnabled() {
log.Info().Msg("setting up notation route")
notationRouter := router.PathPrefix(constants.ExtNotation).Subrouter()
notationRouter.Use(zcommon.CORSHeadersMiddleware(conf.HTTP.AllowOrigin))
notationRouter.Use(zcommon.AddExtensionSecurityHeaders())
notationRouter.Use(zcommon.ACHeadersMiddleware(conf, allowedMethods...))
// The endpoints for uploading signatures should be available only to admins
notationRouter.Use(zcommon.AuthzOnlyAdminsMiddleware(conf))
notationRouter.Methods(allowedMethods...).HandlerFunc(trust.HandleNotationCertificateUpload)
}
if conf.IsCosignEnabled() {
log.Info().Msg("setting up cosign route")
cosignRouter := router.PathPrefix(constants.ExtCosign).Subrouter()
cosignRouter.Use(zcommon.CORSHeadersMiddleware(conf.HTTP.AllowOrigin))
cosignRouter.Use(zcommon.AddExtensionSecurityHeaders())
cosignRouter.Use(zcommon.ACHeadersMiddleware(conf, allowedMethods...))
// The endpoints for uploading signatures should be available only to admins
cosignRouter.Use(zcommon.AuthzOnlyAdminsMiddleware(conf))
cosignRouter.Methods(allowedMethods...).HandlerFunc(trust.HandleCosignPublicKeyUpload)
}
log.Info().Msg("finished setting up image trust routes")
}
type ImageTrust struct {
Conf *config.Config
ImageTrustStore *imagetrust.ImageTrustStore
Log log.Logger
}
// Cosign handler godoc
// @Summary Upload cosign public keys for verifying signatures
// @Description Upload cosign public keys for verifying signatures
// @Router /v2/_zot/ext/cosign [post]
// @Accept octet-stream
// @Produce json
// @Param requestBody body string true "Public key content"
// @Success 200 {string} string "ok"
// @Failure 400 {string} string "bad request".
// @Failure 500 {string} string "internal server error".
func (trust *ImageTrust) HandleCosignPublicKeyUpload(response http.ResponseWriter, request *http.Request) {
body, err := io.ReadAll(request.Body)
if err != nil {
trust.Log.Error().Err(err).Msg("image trust: couldn't read cosign key body")
response.WriteHeader(http.StatusInternalServerError)
return
}
err = imagetrust.UploadPublicKey(trust.ImageTrustStore.CosignStorage, body)
if err != nil {
if errors.Is(err, zerr.ErrInvalidPublicKeyContent) {
response.WriteHeader(http.StatusBadRequest)
} else {
trust.Log.Error().Err(err).Msg("image trust: failed to save cosign key")
response.WriteHeader(http.StatusInternalServerError)
}
return
}
response.WriteHeader(http.StatusOK)
}
// Notation handler godoc
// @Summary Upload notation certificates for verifying signatures
// @Description Upload notation certificates for verifying signatures
// @Router /v2/_zot/ext/notation [post]
// @Accept octet-stream
// @Produce json
// @Param truststoreType query string false "truststore type"
// @Param requestBody body string true "Certificate content"
// @Success 200 {string} string "ok"
// @Failure 400 {string} string "bad request".
// @Failure 500 {string} string "internal server error".
func (trust *ImageTrust) HandleNotationCertificateUpload(response http.ResponseWriter, request *http.Request) {
var truststoreType string
if zcommon.QueryHasParams(request.URL.Query(), []string{"truststoreType"}) {
truststoreType = request.URL.Query().Get("truststoreType")
} else {
truststoreType = "ca" // default value of "truststoreType" query param
}
body, err := io.ReadAll(request.Body)
if err != nil {
trust.Log.Error().Err(err).Msg("image trust: couldn't read notation certificate body")
response.WriteHeader(http.StatusInternalServerError)
return
}
err = imagetrust.UploadCertificate(trust.ImageTrustStore.NotationStorage, body, truststoreType)
if err != nil {
if errors.Is(err, zerr.ErrInvalidTruststoreType) ||
errors.Is(err, zerr.ErrInvalidCertificateContent) {
response.WriteHeader(http.StatusBadRequest)
} else {
trust.Log.Error().Err(err).Msg("image trust: failed to save notation certificate")
response.WriteHeader(http.StatusInternalServerError)
}
return
}
response.WriteHeader(http.StatusOK)
}
func EnableImageTrustVerification(conf *config.Config, taskScheduler *scheduler.Scheduler,
metaDB mTypes.MetaDB, log log.Logger,
) {
if !conf.IsImageTrustEnabled() {
return
}
generator := imagetrust.NewTaskGenerator(metaDB, log)
numberOfHours := 2
interval := time.Duration(numberOfHours) * time.Hour
taskScheduler.SubmitGenerator(generator, interval, scheduler.MediumPriority)
}
func SetupImageTrustExtension(conf *config.Config, metaDB mTypes.MetaDB, log log.Logger) error {
if !conf.IsImageTrustEnabled() {
return nil
}
var imgTrustStore mTypes.ImageTrustStore
var err error
if conf.Storage.RemoteCache {
endpoint, _ := conf.Storage.CacheDriver["endpoint"].(string)
region, _ := conf.Storage.CacheDriver["region"].(string)
imgTrustStore, err = imagetrust.NewAWSImageTrustStore(region, endpoint)
if err != nil {
return err
}
} else {
imgTrustStore, err = imagetrust.NewLocalImageTrustStore(conf.Storage.RootDirectory)
if err != nil {
return err
}
}
metaDB.SetImageTrustStore(imgTrustStore)
return nil
}