fix: metrics should be protected behind authZ (#1895)

Signed-off-by: Alexei Dodon <adodon@cisco.com>
This commit is contained in:
Alexei Dodon
2023-10-20 10:33:26 +03:00
committed by GitHub
parent a44ca578a1
commit a345ba0823
13 changed files with 508 additions and 31 deletions
+2 -2
View File
@@ -57,7 +57,7 @@ func AuthHandler(ctlr *Controller) mux.MiddlewareFunc {
return bearerAuthHandler(ctlr)
}
return authnMiddleware.TryAuthnHandlers(ctlr)
return authnMiddleware.tryAuthnHandlers(ctlr)
}
func (amw *AuthnMiddleware) sessionAuthn(ctlr *Controller, userAc *reqCtx.UserAccessControl,
@@ -247,7 +247,7 @@ func (amw *AuthnMiddleware) basicAuthn(ctlr *Controller, userAc *reqCtx.UserAcce
return false, nil
}
func (amw *AuthnMiddleware) TryAuthnHandlers(ctlr *Controller) mux.MiddlewareFunc { //nolint: gocyclo
func (amw *AuthnMiddleware) tryAuthnHandlers(ctlr *Controller) mux.MiddlewareFunc { //nolint: gocyclo
// no password based authN, if neither LDAP nor HTTP BASIC is enabled
if !ctlr.Config.IsBasicAuthnEnabled() {
return noPasswdAuth(ctlr)
+44 -17
View File
@@ -191,14 +191,10 @@ func (ac *AccessController) getAuthnMiddlewareContext(authnType string, request
func (ac *AccessController) isPermitted(userGroups []string, username, action string,
policyGroup config.PolicyGroup,
) bool {
var result bool
// check repo/system based policies
for _, p := range policyGroup.Policies {
if common.Contains(p.Users, username) && common.Contains(p.Actions, action) {
result = true
return result
return true
}
}
@@ -207,9 +203,7 @@ func (ac *AccessController) isPermitted(userGroups []string, username, action st
if common.Contains(p.Actions, action) {
for _, group := range p.Groups {
if common.Contains(userGroups, group) {
result = true
return result
return true
}
}
}
@@ -217,20 +211,16 @@ func (ac *AccessController) isPermitted(userGroups []string, username, action st
}
// check defaultPolicy
if !result {
if common.Contains(policyGroup.DefaultPolicy, action) && username != "" {
result = true
}
if common.Contains(policyGroup.DefaultPolicy, action) && username != "" {
return true
}
// check anonymousPolicy
if !result {
if common.Contains(policyGroup.AnonymousPolicy, action) && username == "" {
result = true
}
if common.Contains(policyGroup.AnonymousPolicy, action) && username == "" {
return true
}
return result
return false
}
func BaseAuthzHandler(ctlr *Controller) mux.MiddlewareFunc {
@@ -343,3 +333,40 @@ func DistSpecAuthzHandler(ctlr *Controller) mux.MiddlewareFunc {
})
}
}
func MetricsAuthzHandler(ctlr *Controller) mux.MiddlewareFunc {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
if ctlr.Config.HTTP.AccessControl == nil {
// allow access to authenticated user as anonymous policy does not exist
next.ServeHTTP(response, request)
return
}
if len(ctlr.Config.HTTP.AccessControl.Metrics.Users) == 0 {
log := ctlr.Log
log.Warn().Msg("auth is enabled but no metrics users in accessControl: /metrics is unaccesible")
common.AuthzFail(response, request, "", ctlr.Config.HTTP.Realm, ctlr.Config.HTTP.Auth.FailDelay)
return
}
// get access control context made in authn.go
userAc, err := reqCtx.UserAcFromContext(request.Context())
if err != nil { // should never happen
common.AuthzFail(response, request, "", ctlr.Config.HTTP.Realm, ctlr.Config.HTTP.Auth.FailDelay)
return
}
username := userAc.GetUsername()
if !common.Contains(ctlr.Config.HTTP.AccessControl.Metrics.Users, username) {
common.AuthzFail(response, request, username, ctlr.Config.HTTP.Realm, ctlr.Config.HTTP.Auth.FailDelay)
return
}
next.ServeHTTP(response, request) //nolint:contextcheck
})
}
}
+5
View File
@@ -131,6 +131,7 @@ type AccessControlConfig struct {
Repositories Repositories `json:"repositories" mapstructure:"repositories"`
AdminPolicy Policy
Groups Groups
Metrics Metrics
}
func (config *AccessControlConfig) AnonymousPolicyExists() bool {
@@ -168,6 +169,10 @@ type Policy struct {
Groups []string
}
type Metrics struct {
Users []string
}
type Config struct {
DistSpecVersion string `json:"distSpecVersion" mapstructure:"distSpecVersion"`
GoVersion string
+1 -1
View File
@@ -183,7 +183,7 @@ func (rh *RouteHandler) SetupRoutes() {
pprof.SetupPprofRoutes(rh.c.Config, prefixedRouter, authHandler, rh.c.Log)
// Preconditions for enabling the actual extension routes are part of extensions themselves
ext.SetupMetricsRoutes(rh.c.Config, rh.c.Router, authHandler, rh.c.Log, rh.c.Metrics)
ext.SetupMetricsRoutes(rh.c.Config, rh.c.Router, authHandler, MetricsAuthzHandler(rh.c), rh.c.Log, rh.c.Metrics)
ext.SetupSearchRoutes(rh.c.Config, prefixedRouter, rh.c.StoreController, rh.c.MetaDB, rh.c.CveScanner,
rh.c.Log)
ext.SetupImageTrustRoutes(rh.c.Config, prefixedRouter, rh.c.MetaDB, rh.c.Log)