mirror of
https://github.com/distribution/distribution.git
synced 2025-08-28 19:31:53 +00:00
Use selected fields from app in context to avoid secrets
The app struct includes sensitive data that the handlers don't necessarily need access to, so remove it from the context, and don't pass the app in place of contexts. Where handlers do need configuration data from the app, store it in the handler's own struct instead of relying on it being in context. Signed-off-by: James Hewitt <james.hewitt@uk.ibm.com>
This commit is contained in:
parent
f22dd61860
commit
402ac1fcb6
@ -104,7 +104,6 @@ func SetDefaultLogger(logger Logger) {
|
||||
// required.
|
||||
func getLogrusLogger(ctx context.Context, keys ...interface{}) *logrus.Entry {
|
||||
var logger *logrus.Entry
|
||||
|
||||
// Get a logger, if it is present.
|
||||
loggerInterface := ctx.Value(loggerKey{})
|
||||
if loggerInterface != nil {
|
||||
|
@ -59,7 +59,7 @@ const defaultCheckInterval = 10 * time.Second
|
||||
// on this object that will be accessible from all requests. Any writable
|
||||
// fields should be protected.
|
||||
type App struct {
|
||||
context.Context
|
||||
Context context.Context
|
||||
|
||||
Config *configuration.Configuration
|
||||
|
||||
@ -92,6 +92,8 @@ type App struct {
|
||||
// requests. The app only implements ServeHTTP and can be wrapped in other
|
||||
// handlers accordingly.
|
||||
func NewApp(ctx context.Context, config *configuration.Configuration) *App {
|
||||
logger := dcontext.GetLogger(ctx)
|
||||
|
||||
app := &App{
|
||||
Config: config,
|
||||
Context: ctx,
|
||||
@ -100,7 +102,7 @@ func NewApp(ctx context.Context, config *configuration.Configuration) *App {
|
||||
}
|
||||
|
||||
// Register the handler dispatchers.
|
||||
app.register(v2.RouteNameBase, func(ctx *Context, r *http.Request) http.Handler {
|
||||
app.register(v2.RouteNameBase, func(ctx *Context, app *App, r *http.Request) http.Handler {
|
||||
return http.HandlerFunc(apiBase)
|
||||
})
|
||||
app.register(v2.RouteNameManifest, manifestDispatcher)
|
||||
@ -120,7 +122,7 @@ func NewApp(ctx context.Context, config *configuration.Configuration) *App {
|
||||
}
|
||||
|
||||
var err error
|
||||
app.driver, err = factory.Create(app, config.Storage.Type(), storageParams)
|
||||
app.driver, err = factory.Create(ctx, config.Storage.Type(), storageParams)
|
||||
if err != nil {
|
||||
// TODO(stevvooe): Move the creation of a service into a protected
|
||||
// method, where this is created lazily. Its status can be queried via
|
||||
@ -150,9 +152,9 @@ func NewApp(ctx context.Context, config *configuration.Configuration) *App {
|
||||
}
|
||||
}
|
||||
|
||||
startUploadPurger(app, app.driver, dcontext.GetLogger(app), purgeConfig)
|
||||
startUploadPurger(app.Context, app.driver, logger, purgeConfig)
|
||||
|
||||
app.driver, err = applyStorageMiddleware(app, app.driver, config.Middleware["storage"])
|
||||
app.driver, err = applyStorageMiddleware(ctx, app.driver, config.Middleware["storage"])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -217,7 +219,7 @@ func NewApp(ctx context.Context, config *configuration.Configuration) *App {
|
||||
}
|
||||
}
|
||||
if redirectDisabled {
|
||||
dcontext.GetLogger(app).Infof("backend redirection disabled")
|
||||
logger.Infof("backend redirection disabled")
|
||||
} else {
|
||||
options = append(options, storage.EnableRedirect)
|
||||
}
|
||||
@ -288,15 +290,15 @@ func NewApp(ctx context.Context, config *configuration.Configuration) *App {
|
||||
panic("redis configuration required to use for layerinfo cache")
|
||||
}
|
||||
if _, ok := cc["blobdescriptorsize"]; ok {
|
||||
dcontext.GetLogger(app).Warnf("blobdescriptorsize parameter is not supported with redis cache")
|
||||
logger.Warnf("blobdescriptorsize parameter is not supported with redis cache")
|
||||
}
|
||||
cacheProvider := rediscache.NewRedisBlobDescriptorCacheProvider(app.redis)
|
||||
localOptions := append(options, storage.BlobDescriptorCacheProvider(cacheProvider))
|
||||
app.registry, err = storage.NewRegistry(app, app.driver, localOptions...)
|
||||
app.registry, err = storage.NewRegistry(ctx, app.driver, localOptions...)
|
||||
if err != nil {
|
||||
panic("could not create registry: " + err.Error())
|
||||
}
|
||||
dcontext.GetLogger(app).Infof("using redis blob descriptor cache")
|
||||
logger.Infof("using redis blob descriptor cache")
|
||||
case "inmemory":
|
||||
blobDescriptorSize := memorycache.DefaultSize
|
||||
configuredSize, ok := cc["blobdescriptorsize"]
|
||||
@ -310,14 +312,14 @@ func NewApp(ctx context.Context, config *configuration.Configuration) *App {
|
||||
|
||||
cacheProvider := memorycache.NewInMemoryBlobDescriptorCacheProvider(blobDescriptorSize)
|
||||
localOptions := append(options, storage.BlobDescriptorCacheProvider(cacheProvider))
|
||||
app.registry, err = storage.NewRegistry(app, app.driver, localOptions...)
|
||||
app.registry, err = storage.NewRegistry(ctx, app.driver, localOptions...)
|
||||
if err != nil {
|
||||
panic("could not create registry: " + err.Error())
|
||||
}
|
||||
dcontext.GetLogger(app).Infof("using inmemory blob descriptor cache")
|
||||
logger.Infof("using inmemory blob descriptor cache")
|
||||
default:
|
||||
if v != "" {
|
||||
dcontext.GetLogger(app).Warnf("unknown cache type %q, caching disabled", config.Storage["cache"])
|
||||
logger.Warnf("unknown cache type %q, caching disabled", config.Storage["cache"])
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -330,7 +332,7 @@ func NewApp(ctx context.Context, config *configuration.Configuration) *App {
|
||||
}
|
||||
}
|
||||
|
||||
app.registry, err = applyRegistryMiddleware(app, app.registry, app.driver, config.Middleware["registry"])
|
||||
app.registry, err = applyRegistryMiddleware(ctx, app.registry, app.driver, config.Middleware["registry"])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -343,7 +345,7 @@ func NewApp(ctx context.Context, config *configuration.Configuration) *App {
|
||||
panic(fmt.Sprintf("unable to configure authorization (%s): %v", authType, err))
|
||||
}
|
||||
app.accessController = accessController
|
||||
dcontext.GetLogger(app).Debugf("configured %q access controller", authType)
|
||||
logger.Debugf("configured %q access controller", authType)
|
||||
}
|
||||
|
||||
// configure as a pull through cache
|
||||
@ -353,12 +355,12 @@ func NewApp(ctx context.Context, config *configuration.Configuration) *App {
|
||||
panic(err.Error())
|
||||
}
|
||||
app.isCache = true
|
||||
dcontext.GetLogger(app).Info("Registry configured as a proxy cache to ", config.Proxy.RemoteURL)
|
||||
logger.Info("Registry configured as a proxy cache to ", config.Proxy.RemoteURL)
|
||||
}
|
||||
var ok bool
|
||||
app.repoRemover, ok = app.registry.(distribution.RepositoryRemover)
|
||||
if !ok {
|
||||
dcontext.GetLogger(app).Warnf("Registry does not implement RepositoryRemover. Will not be able to delete repos and tags")
|
||||
logger.Warnf("Registry does not implement RepositoryRemover. Will not be able to delete repos and tags")
|
||||
}
|
||||
|
||||
return app
|
||||
@ -399,7 +401,7 @@ func (app *App) RegisterHealthChecks(healthRegistries ...*health.Registry) {
|
||||
|
||||
updater := health.NewThresholdStatusUpdater(app.Config.Health.StorageDriver.Threshold)
|
||||
healthRegistry.Register("storagedriver_"+app.Config.Storage.Type(), updater)
|
||||
go health.Poll(app, updater, storageDriverCheck, interval)
|
||||
go health.Poll(app.Context, updater, storageDriverCheck, interval)
|
||||
}
|
||||
|
||||
for _, fileChecker := range app.Config.Health.FileCheckers {
|
||||
@ -407,10 +409,10 @@ func (app *App) RegisterHealthChecks(healthRegistries ...*health.Registry) {
|
||||
if interval == 0 {
|
||||
interval = defaultCheckInterval
|
||||
}
|
||||
dcontext.GetLogger(app).Infof("configuring file health check path=%s, interval=%d", fileChecker.File, interval/time.Second)
|
||||
dcontext.GetLogger(app.Context).Infof("configuring file health check path=%s, interval=%d", fileChecker.File, interval/time.Second)
|
||||
u := health.NewStatusUpdater()
|
||||
healthRegistry.Register(fileChecker.File, u)
|
||||
go health.Poll(app, u, checks.FileChecker(fileChecker.File), interval)
|
||||
go health.Poll(app.Context, u, checks.FileChecker(fileChecker.File), interval)
|
||||
}
|
||||
|
||||
for _, httpChecker := range app.Config.Health.HTTPCheckers {
|
||||
@ -426,10 +428,10 @@ func (app *App) RegisterHealthChecks(healthRegistries ...*health.Registry) {
|
||||
|
||||
checker := checks.HTTPChecker(httpChecker.URI, statusCode, httpChecker.Timeout, httpChecker.Headers)
|
||||
|
||||
dcontext.GetLogger(app).Infof("configuring HTTP health check uri=%s, interval=%d, threshold=%d", httpChecker.URI, interval/time.Second, httpChecker.Threshold)
|
||||
dcontext.GetLogger(app.Context).Infof("configuring HTTP health check uri=%s, interval=%d, threshold=%d", httpChecker.URI, interval/time.Second, httpChecker.Threshold)
|
||||
updater := health.NewThresholdStatusUpdater(httpChecker.Threshold)
|
||||
healthRegistry.Register(httpChecker.URI, updater)
|
||||
go health.Poll(app, updater, checker, interval)
|
||||
go health.Poll(app.Context, updater, checker, interval)
|
||||
}
|
||||
|
||||
for _, tcpChecker := range app.Config.Health.TCPCheckers {
|
||||
@ -440,10 +442,10 @@ func (app *App) RegisterHealthChecks(healthRegistries ...*health.Registry) {
|
||||
|
||||
checker := checks.TCPChecker(tcpChecker.Addr, tcpChecker.Timeout)
|
||||
|
||||
dcontext.GetLogger(app).Infof("configuring TCP health check addr=%s, interval=%d, threshold=%d", tcpChecker.Addr, interval/time.Second, tcpChecker.Threshold)
|
||||
dcontext.GetLogger(app.Context).Infof("configuring TCP health check addr=%s, interval=%d, threshold=%d", tcpChecker.Addr, interval/time.Second, tcpChecker.Threshold)
|
||||
updater := health.NewThresholdStatusUpdater(tcpChecker.Threshold)
|
||||
healthRegistry.Register(tcpChecker.Addr, updater)
|
||||
go health.Poll(app, updater, checker, interval)
|
||||
go health.Poll(app.Context, updater, checker, interval)
|
||||
}
|
||||
}
|
||||
|
||||
@ -489,11 +491,11 @@ func (app *App) configureEvents(configuration *configuration.Configuration) {
|
||||
var sinks []events.Sink
|
||||
for _, endpoint := range configuration.Notifications.Endpoints {
|
||||
if endpoint.Disabled {
|
||||
dcontext.GetLogger(app).Infof("endpoint %s disabled, skipping", endpoint.Name)
|
||||
dcontext.GetLogger(app.Context).Infof("endpoint %s disabled, skipping", endpoint.Name)
|
||||
continue
|
||||
}
|
||||
|
||||
dcontext.GetLogger(app).Infof("configuring endpoint %v (%v), timeout=%s, headers=%v", endpoint.Name, endpoint.URL, endpoint.Timeout, endpoint.Headers)
|
||||
dcontext.GetLogger(app.Context).Infof("configuring endpoint %v (%v), timeout=%s, headers=%v", endpoint.Name, endpoint.URL, endpoint.Timeout, endpoint.Headers)
|
||||
endpoint := notifications.NewEndpoint(endpoint.Name, endpoint.URL, notifications.EndpointConfig{
|
||||
Timeout: endpoint.Timeout,
|
||||
Threshold: endpoint.Threshold,
|
||||
@ -526,13 +528,13 @@ func (app *App) configureEvents(configuration *configuration.Configuration) {
|
||||
|
||||
app.events.source = notifications.SourceRecord{
|
||||
Addr: hostname,
|
||||
InstanceID: dcontext.GetStringValue(app, "instance.id"),
|
||||
InstanceID: dcontext.GetStringValue(app.Context, "instance.id"),
|
||||
}
|
||||
}
|
||||
|
||||
func (app *App) configureRedis(cfg *configuration.Configuration) {
|
||||
if len(cfg.Redis.Options.Addrs) == 0 {
|
||||
dcontext.GetLogger(app).Infof("redis not configured")
|
||||
dcontext.GetLogger(app.Context).Infof("redis not configured")
|
||||
return
|
||||
}
|
||||
|
||||
@ -569,7 +571,7 @@ func (app *App) configureRedis(cfg *configuration.Configuration) {
|
||||
|
||||
// Enable metrics instrumentation.
|
||||
if err := redisotel.InstrumentMetrics(app.redis); err != nil {
|
||||
dcontext.GetLogger(app).Errorf("failed to instrument metrics on redis: %v", err)
|
||||
dcontext.GetLogger(app.Context).Errorf("failed to instrument metrics on redis: %v", err)
|
||||
}
|
||||
|
||||
// setup expvar
|
||||
@ -597,7 +599,7 @@ func (app *App) createPool(cfg redis.UniversalOptions) redis.UniversalClient {
|
||||
|
||||
// configureLogHook prepares logging hook parameters.
|
||||
func (app *App) configureLogHook(configuration *configuration.Configuration) {
|
||||
entry, ok := dcontext.GetLogger(app).(*logrus.Entry)
|
||||
entry, ok := dcontext.GetLogger(app.Context).(*logrus.Entry)
|
||||
if !ok {
|
||||
// somehow, we are not using logrus
|
||||
return
|
||||
@ -635,7 +637,7 @@ func (app *App) configureSecret(configuration *configuration.Configuration) {
|
||||
panic(fmt.Sprintf("could not generate random bytes for HTTP secret: %v", err))
|
||||
}
|
||||
configuration.HTTP.Secret = string(secretBytes[:])
|
||||
dcontext.GetLogger(app).Warn("No HTTP secret provided - generated random secret. This may cause problems with uploads if multiple registries are behind a load-balancer. To provide a shared secret, fill in http.secret in the configuration file or set the REGISTRY_HTTP_SECRET environment variable.")
|
||||
dcontext.GetLogger(app.Context).Warn("No HTTP secret provided - generated random secret. This may cause problems with uploads if multiple registries are behind a load-balancer. To provide a shared secret, fill in http.secret in the configuration file or set the REGISTRY_HTTP_SECRET environment variable.")
|
||||
}
|
||||
}
|
||||
|
||||
@ -656,7 +658,7 @@ func (app *App) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// for the route. The dispatcher will use this to dynamically create request
|
||||
// specific handlers for each endpoint without creating a new router for each
|
||||
// request.
|
||||
type dispatchFunc func(ctx *Context, r *http.Request) http.Handler
|
||||
type dispatchFunc func(ctx *Context, app *App, r *http.Request) http.Handler
|
||||
|
||||
// TODO(stevvooe): dispatchers should probably have some validation error
|
||||
// chain with proper error reporting.
|
||||
@ -729,12 +731,12 @@ func (app *App) dispatcher(dispatch dispatchFunc) http.Handler {
|
||||
}
|
||||
|
||||
// assign and decorate the authorized repository with an event bridge.
|
||||
context.Repository, context.RepositoryRemover = notifications.Listen(
|
||||
context.Repository, _ = notifications.Listen(
|
||||
repository,
|
||||
context.App.repoRemover,
|
||||
app.repoRemover,
|
||||
app.eventBridge(context, r))
|
||||
|
||||
context.Repository, err = applyRepoMiddleware(app, context.Repository, app.Config.Middleware["repository"])
|
||||
context.Repository, err = applyRepoMiddleware(app.Context, context.Repository, app.Config.Middleware["repository"])
|
||||
if err != nil {
|
||||
dcontext.GetLogger(context).Errorf("error initializing repository middleware: %v", err)
|
||||
context.Errors = append(context.Errors, errcode.ErrorCodeUnknown.WithDetail(err))
|
||||
@ -746,7 +748,7 @@ func (app *App) dispatcher(dispatch dispatchFunc) http.Handler {
|
||||
}
|
||||
}
|
||||
|
||||
dispatch(context, r).ServeHTTP(w, r)
|
||||
dispatch(context, app, r).ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
@ -800,7 +802,6 @@ func (app *App) context(w http.ResponseWriter, r *http.Request) *Context {
|
||||
"vars.uuid"))
|
||||
|
||||
context := &Context{
|
||||
App: app,
|
||||
Context: ctx,
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ func TestAppDispatcher(t *testing.T) {
|
||||
}
|
||||
|
||||
varCheckingDispatcher := func(expectedVars map[string]string) dispatchFunc {
|
||||
return func(ctx *Context, r *http.Request) http.Handler {
|
||||
return func(ctx *Context, app *App, r *http.Request) http.Handler {
|
||||
// Always checks the same name context
|
||||
if ctx.Repository.Named().Name() != getName(ctx) {
|
||||
t.Fatalf("unexpected name: %q != %q", ctx.Repository.Named().Name(), "foo/bar")
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
// blobDispatcher uses the request context to build a blobHandler.
|
||||
func blobDispatcher(ctx *Context, r *http.Request) http.Handler {
|
||||
func blobDispatcher(ctx *Context, app *App, r *http.Request) http.Handler {
|
||||
dgst, err := getDigest(ctx)
|
||||
if err != nil {
|
||||
|
||||
@ -36,7 +36,7 @@ func blobDispatcher(ctx *Context, r *http.Request) http.Handler {
|
||||
http.MethodHead: http.HandlerFunc(blobHandler.GetBlob),
|
||||
}
|
||||
|
||||
if !ctx.readOnly {
|
||||
if !app.readOnly {
|
||||
mhandler[http.MethodDelete] = http.HandlerFunc(blobHandler.DeleteBlob)
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/distribution/distribution/v3"
|
||||
"github.com/distribution/distribution/v3/configuration"
|
||||
"github.com/distribution/distribution/v3/internal/dcontext"
|
||||
"github.com/distribution/distribution/v3/registry/api/errcode"
|
||||
"github.com/distribution/distribution/v3/registry/storage"
|
||||
@ -17,9 +18,10 @@ import (
|
||||
|
||||
// blobUploadDispatcher constructs and returns the blob upload handler for the
|
||||
// given request context.
|
||||
func blobUploadDispatcher(ctx *Context, r *http.Request) http.Handler {
|
||||
func blobUploadDispatcher(ctx *Context, app *App, r *http.Request) http.Handler {
|
||||
buh := &blobUploadHandler{
|
||||
Context: ctx,
|
||||
Config: app.Config,
|
||||
UUID: getUploadUUID(ctx),
|
||||
}
|
||||
|
||||
@ -28,7 +30,7 @@ func blobUploadDispatcher(ctx *Context, r *http.Request) http.Handler {
|
||||
http.MethodHead: http.HandlerFunc(buh.GetUploadStatus),
|
||||
}
|
||||
|
||||
if !ctx.readOnly {
|
||||
if !app.readOnly {
|
||||
handler[http.MethodPost] = http.HandlerFunc(buh.StartBlobUpload)
|
||||
handler[http.MethodPatch] = http.HandlerFunc(buh.PatchBlobData)
|
||||
handler[http.MethodPut] = http.HandlerFunc(buh.PutBlobUploadComplete)
|
||||
@ -52,6 +54,8 @@ func blobUploadDispatcher(ctx *Context, r *http.Request) http.Handler {
|
||||
type blobUploadHandler struct {
|
||||
*Context
|
||||
|
||||
Config *configuration.Configuration
|
||||
|
||||
// UUID identifies the upload instance for the current request. Using UUID
|
||||
// to key blob writers since this implementation uses UUIDs.
|
||||
UUID string
|
||||
@ -270,7 +274,7 @@ func (buh *blobUploadHandler) CancelBlobUpload(w http.ResponseWriter, r *http.Re
|
||||
}
|
||||
|
||||
func (buh *blobUploadHandler) ResumeBlobUpload(ctx *Context, r *http.Request) http.Handler {
|
||||
state, err := hmacKey(ctx.Config.HTTP.Secret).unpackUploadState(r.FormValue("_state"))
|
||||
state, err := hmacKey(buh.Config.HTTP.Secret).unpackUploadState(r.FormValue("_state"))
|
||||
if err != nil {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
dcontext.GetLogger(ctx).Infof("error resolving upload: %v", err)
|
||||
|
@ -8,6 +8,8 @@ import (
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"github.com/distribution/distribution/v3"
|
||||
"github.com/distribution/distribution/v3/configuration"
|
||||
"github.com/distribution/distribution/v3/registry/api/errcode"
|
||||
"github.com/distribution/distribution/v3/registry/storage/driver"
|
||||
"github.com/gorilla/handlers"
|
||||
@ -15,9 +17,11 @@ import (
|
||||
|
||||
const defaultReturnedEntries = 100
|
||||
|
||||
func catalogDispatcher(ctx *Context, r *http.Request) http.Handler {
|
||||
func catalogDispatcher(ctx *Context, app *App, r *http.Request) http.Handler {
|
||||
catalogHandler := &catalogHandler{
|
||||
Context: ctx,
|
||||
Config: app.Config,
|
||||
registry: app.registry,
|
||||
}
|
||||
|
||||
return handlers.MethodHandler{
|
||||
@ -27,6 +31,8 @@ func catalogDispatcher(ctx *Context, r *http.Request) http.Handler {
|
||||
|
||||
type catalogHandler struct {
|
||||
*Context
|
||||
Config *configuration.Configuration
|
||||
registry distribution.Namespace
|
||||
}
|
||||
|
||||
type catalogAPIResponse struct {
|
||||
@ -40,7 +46,7 @@ func (ch *catalogHandler) GetCatalog(w http.ResponseWriter, r *http.Request) {
|
||||
lastEntry := q.Get("last")
|
||||
|
||||
entries := defaultReturnedEntries
|
||||
maximumConfiguredEntries := ch.App.Config.Catalog.MaxEntries
|
||||
maximumConfiguredEntries := ch.Config.Catalog.MaxEntries
|
||||
|
||||
// parse n, if n is negative abort with an error
|
||||
if n := q.Get("n"); n != "" {
|
||||
@ -71,7 +77,7 @@ func (ch *catalogHandler) GetCatalog(w http.ResponseWriter, r *http.Request) {
|
||||
if entries == 0 {
|
||||
moreEntries = false
|
||||
} else {
|
||||
returnedRepositories, err := ch.App.registry.Repositories(ch.Context, repos, lastEntry)
|
||||
returnedRepositories, err := ch.registry.Repositories(ch.Context, repos, lastEntry)
|
||||
if err != nil {
|
||||
_, pathNotFound := err.(driver.PathNotFoundError)
|
||||
if err != io.EOF && !pathNotFound {
|
||||
|
@ -17,17 +17,12 @@ import (
|
||||
// handlers. Resources that don't need to be shared across handlers should not
|
||||
// be on this object.
|
||||
type Context struct {
|
||||
// App points to the application structure that created this context.
|
||||
*App
|
||||
context.Context
|
||||
|
||||
// Repository is the repository for the current request. All requests
|
||||
// should be scoped to a single repository. This field may be nil.
|
||||
Repository distribution.Repository
|
||||
|
||||
// RepositoryRemover provides method to delete a repository
|
||||
RepositoryRemover distribution.RepositoryRemover
|
||||
|
||||
// Errors is a collection of errors encountered during the request to be
|
||||
// returned to the client API. If errors are added to the collection, the
|
||||
// handler *must not* start the response via http.ResponseWriter.
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/distribution/distribution/v3"
|
||||
"github.com/distribution/distribution/v3/configuration"
|
||||
"github.com/distribution/distribution/v3/internal/dcontext"
|
||||
"github.com/distribution/distribution/v3/manifest/manifestlist"
|
||||
"github.com/distribution/distribution/v3/manifest/ocischema"
|
||||
@ -42,9 +43,11 @@ const (
|
||||
|
||||
// manifestDispatcher takes the request context and builds the
|
||||
// appropriate handler for handling manifest requests.
|
||||
func manifestDispatcher(ctx *Context, r *http.Request) http.Handler {
|
||||
func manifestDispatcher(ctx *Context, app *App, r *http.Request) http.Handler {
|
||||
manifestHandler := &manifestHandler{
|
||||
Context: ctx,
|
||||
isCache: app.isCache,
|
||||
Config: app.Config,
|
||||
}
|
||||
ref := getReference(ctx)
|
||||
dgst, err := digest.Parse(ref)
|
||||
@ -60,7 +63,7 @@ func manifestDispatcher(ctx *Context, r *http.Request) http.Handler {
|
||||
http.MethodHead: http.HandlerFunc(manifestHandler.GetManifest),
|
||||
}
|
||||
|
||||
if !ctx.readOnly {
|
||||
if !app.readOnly {
|
||||
mhandler[http.MethodPut] = http.HandlerFunc(manifestHandler.PutManifest)
|
||||
mhandler[http.MethodDelete] = http.HandlerFunc(manifestHandler.DeleteManifest)
|
||||
}
|
||||
@ -72,6 +75,11 @@ func manifestDispatcher(ctx *Context, r *http.Request) http.Handler {
|
||||
type manifestHandler struct {
|
||||
*Context
|
||||
|
||||
Config *configuration.Configuration
|
||||
|
||||
// isCache is true if this registry is configured as a pull through cache
|
||||
isCache bool
|
||||
|
||||
// One of tag or digest gets set, depending on what is present in context.
|
||||
Tag string
|
||||
Digest digest.Digest
|
||||
@ -362,7 +370,7 @@ func (imh *manifestHandler) PutManifest(w http.ResponseWriter, r *http.Request)
|
||||
// applyResourcePolicy checks whether the resource class matches what has
|
||||
// been authorized and allowed by the policy configuration.
|
||||
func (imh *manifestHandler) applyResourcePolicy(manifest distribution.Manifest) error {
|
||||
allowedClasses := imh.App.Config.Policy.Repository.Classes
|
||||
allowedClasses := imh.Config.Policy.Repository.Classes
|
||||
if len(allowedClasses) == 0 {
|
||||
return nil
|
||||
}
|
||||
@ -431,7 +439,7 @@ func (imh *manifestHandler) applyResourcePolicy(manifest distribution.Manifest)
|
||||
func (imh *manifestHandler) DeleteManifest(w http.ResponseWriter, r *http.Request) {
|
||||
dcontext.GetLogger(imh).Debug("DeleteImageManifest")
|
||||
|
||||
if imh.App.isCache {
|
||||
if imh.isCache {
|
||||
imh.Errors = append(imh.Errors, errcode.ErrorCodeUnsupported)
|
||||
return
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
// tagsDispatcher constructs the tags handler api endpoint.
|
||||
func tagsDispatcher(ctx *Context, r *http.Request) http.Handler {
|
||||
func tagsDispatcher(ctx *Context, app *App, r *http.Request) http.Handler {
|
||||
tagsHandler := &tagsHandler{
|
||||
Context: ctx,
|
||||
}
|
||||
|
@ -223,6 +223,7 @@ func setDirectoryURL(directoryurl string) *acme.Client {
|
||||
// ListenAndServe runs the registry's HTTP server.
|
||||
func (registry *Registry) ListenAndServe() error {
|
||||
config := registry.config
|
||||
logger := dcontext.GetLogger(registry.app.Context)
|
||||
|
||||
ln, err := listener.NewListener(config.HTTP.Net, config.HTTP.Addr)
|
||||
if err != nil {
|
||||
@ -237,19 +238,19 @@ func (registry *Registry) ListenAndServe() error {
|
||||
if !ok {
|
||||
return fmt.Errorf("unknown minimum TLS level '%s' specified for http.tls.minimumtls", config.HTTP.TLS.MinimumTLS)
|
||||
}
|
||||
dcontext.GetLogger(registry.app).Infof("restricting TLS version to %s or higher", config.HTTP.TLS.MinimumTLS)
|
||||
logger.Infof("restricting TLS version to %s or higher", config.HTTP.TLS.MinimumTLS)
|
||||
|
||||
var tlsCipherSuites []uint16
|
||||
// configuring cipher suites are no longer supported after the tls1.3.
|
||||
// (https://go.dev/blog/tls-cipher-suites)
|
||||
if tlsMinVersion > tls.VersionTLS12 {
|
||||
dcontext.GetLogger(registry.app).Warnf("restricting TLS cipher suites to empty. Because configuring cipher suites is no longer supported in %s", config.HTTP.TLS.MinimumTLS)
|
||||
logger.Warnf("restricting TLS cipher suites to empty. Because configuring cipher suites is no longer supported in %s", config.HTTP.TLS.MinimumTLS)
|
||||
} else {
|
||||
tlsCipherSuites, err = getCipherSuites(config.HTTP.TLS.CipherSuites)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dcontext.GetLogger(registry.app).Infof("restricting TLS cipher suites to: %s", strings.Join(getCipherSuiteNames(tlsCipherSuites), ","))
|
||||
logger.Infof("restricting TLS cipher suites to: %s", strings.Join(getCipherSuiteNames(tlsCipherSuites), ","))
|
||||
}
|
||||
|
||||
tlsConf := &tls.Config{
|
||||
@ -295,7 +296,7 @@ func (registry *Registry) ListenAndServe() error {
|
||||
}
|
||||
|
||||
for _, subj := range pool.Subjects() { //nolint:staticcheck // FIXME(thaJeztah): ignore SA1019: ac.(*accessController).rootCerts.Subjects has been deprecated since Go 1.18: if s was returned by SystemCertPool, Subjects will not include the system roots. (staticcheck)
|
||||
dcontext.GetLogger(registry.app).Debugf("CA Subject: %s", string(subj))
|
||||
logger.Debugf("CA Subject: %s", string(subj))
|
||||
}
|
||||
|
||||
tlsConf.ClientAuth = tls.RequireAndVerifyClientCert
|
||||
@ -303,9 +304,9 @@ func (registry *Registry) ListenAndServe() error {
|
||||
}
|
||||
|
||||
ln = tls.NewListener(ln, tlsConf)
|
||||
dcontext.GetLogger(registry.app).Infof("listening on %v, tls", ln.Addr())
|
||||
logger.Infof("listening on %v, tls", ln.Addr())
|
||||
} else {
|
||||
dcontext.GetLogger(registry.app).Infof("listening on %v", ln.Addr())
|
||||
logger.Infof("listening on %v", ln.Addr())
|
||||
}
|
||||
|
||||
if config.HTTP.DrainTimeout == 0 {
|
||||
@ -325,7 +326,7 @@ func (registry *Registry) ListenAndServe() error {
|
||||
case err := <-serveErr:
|
||||
return err
|
||||
case <-registry.quit:
|
||||
dcontext.GetLogger(registry.app).Info("stopping server gracefully. Draining connections for ", config.HTTP.DrainTimeout)
|
||||
logger.Info("stopping server gracefully. Draining connections for ", config.HTTP.DrainTimeout)
|
||||
// shutdown the server with a grace period of configured timeout
|
||||
c, cancel := context.WithTimeout(context.Background(), config.HTTP.DrainTimeout)
|
||||
defer cancel()
|
||||
|
Loading…
Reference in New Issue
Block a user