Update registry server to support repository class
Use whitelist of allowed repository classes to enforce. By default all repository classes are allowed. Add authorized resources to context after authorization. Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
This commit is contained in:
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/api/errcode"
|
||||
"github.com/docker/distribution/registry/api/v2"
|
||||
"github.com/docker/distribution/registry/auth"
|
||||
"github.com/gorilla/handlers"
|
||||
)
|
||||
|
||||
@@ -269,6 +270,12 @@ func (imh *imageManifestHandler) PutImageManifest(w http.ResponseWriter, r *http
|
||||
if imh.Tag != "" {
|
||||
options = append(options, distribution.WithTag(imh.Tag))
|
||||
}
|
||||
|
||||
if err := imh.applyResourcePolicy(manifest); err != nil {
|
||||
imh.Errors = append(imh.Errors, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = manifests.Put(imh, manifest, options...)
|
||||
if err != nil {
|
||||
// TODO(stevvooe): These error handling switches really need to be
|
||||
@@ -339,6 +346,73 @@ func (imh *imageManifestHandler) PutImageManifest(w http.ResponseWriter, r *http
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
}
|
||||
|
||||
// applyResourcePolicy checks whether the resource class matches what has
|
||||
// been authorized and allowed by the policy configuration.
|
||||
func (imh *imageManifestHandler) applyResourcePolicy(manifest distribution.Manifest) error {
|
||||
allowedClasses := imh.App.Config.Policy.Repository.Classes
|
||||
if len(allowedClasses) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var class string
|
||||
switch m := manifest.(type) {
|
||||
case *schema1.SignedManifest:
|
||||
class = "image"
|
||||
case *schema2.DeserializedManifest:
|
||||
switch m.Config.MediaType {
|
||||
case schema2.MediaTypeConfig:
|
||||
class = "image"
|
||||
case schema2.MediaTypePluginConfig:
|
||||
class = "plugin"
|
||||
default:
|
||||
message := fmt.Sprintf("unknown manifest class for %s", m.Config.MediaType)
|
||||
return errcode.ErrorCodeDenied.WithMessage(message)
|
||||
}
|
||||
}
|
||||
|
||||
if class == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check to see if class is allowed in registry
|
||||
var allowedClass bool
|
||||
for _, c := range allowedClasses {
|
||||
if class == c {
|
||||
allowedClass = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !allowedClass {
|
||||
message := fmt.Sprintf("registry does not allow %s manifest", class)
|
||||
return errcode.ErrorCodeDenied.WithMessage(message)
|
||||
}
|
||||
|
||||
resources := auth.AuthorizedResources(imh)
|
||||
n := imh.Repository.Named().Name()
|
||||
|
||||
var foundResource bool
|
||||
for _, r := range resources {
|
||||
if r.Name == n {
|
||||
if r.Class == "" {
|
||||
r.Class = "image"
|
||||
}
|
||||
if r.Class == class {
|
||||
return nil
|
||||
}
|
||||
foundResource = true
|
||||
}
|
||||
}
|
||||
|
||||
// resource was found but no matching class was found
|
||||
if foundResource {
|
||||
message := fmt.Sprintf("repository not authorized for %s manifest", class)
|
||||
return errcode.ErrorCodeDenied.WithMessage(message)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// DeleteImageManifest removes the manifest with the given digest from the registry.
|
||||
func (imh *imageManifestHandler) DeleteImageManifest(w http.ResponseWriter, r *http.Request) {
|
||||
ctxu.GetLogger(imh).Debug("DeleteImageManifest")
|
||||
|
Reference in New Issue
Block a user