feat(containers): Ensure users cannot create privileged containers via the API (#3969)
* feat(containers): Ensure users cannot create privileged containers via the API * feat(containers): add rbac check in stack creation
This commit is contained in:
@@ -11,7 +11,7 @@ import (
|
||||
"github.com/asaskevich/govalidator"
|
||||
httperror "github.com/portainer/libhttp/error"
|
||||
"github.com/portainer/libhttp/request"
|
||||
"github.com/portainer/portainer/api"
|
||||
portainer "github.com/portainer/portainer/api"
|
||||
"github.com/portainer/portainer/api/filesystem"
|
||||
"github.com/portainer/portainer/api/http/security"
|
||||
)
|
||||
@@ -283,6 +283,7 @@ type composeStackDeploymentConfig struct {
|
||||
dockerhub *portainer.DockerHub
|
||||
registries []portainer.Registry
|
||||
isAdmin bool
|
||||
user *portainer.User
|
||||
}
|
||||
|
||||
func (handler *Handler) createComposeDeployConfig(r *http.Request, stack *portainer.Stack, endpoint *portainer.Endpoint) (*composeStackDeploymentConfig, *httperror.HandlerError) {
|
||||
@@ -302,12 +303,18 @@ func (handler *Handler) createComposeDeployConfig(r *http.Request, stack *portai
|
||||
}
|
||||
filteredRegistries := security.FilterRegistries(registries, securityContext)
|
||||
|
||||
user, err := handler.UserService.User(securityContext.UserID)
|
||||
if err != nil {
|
||||
return nil, &httperror.HandlerError{http.StatusInternalServerError, "Unable to load user information from the database", err}
|
||||
}
|
||||
|
||||
config := &composeStackDeploymentConfig{
|
||||
stack: stack,
|
||||
endpoint: endpoint,
|
||||
dockerhub: dockerhub,
|
||||
registries: filteredRegistries,
|
||||
isAdmin: securityContext.IsAdmin,
|
||||
user: user,
|
||||
}
|
||||
|
||||
return config, nil
|
||||
@@ -324,7 +331,29 @@ func (handler *Handler) deployComposeStack(config *composeStackDeploymentConfig)
|
||||
return err
|
||||
}
|
||||
|
||||
if !settings.AllowBindMountsForRegularUsers && !config.isAdmin {
|
||||
rbacExtension, err := handler.ExtensionService.Extension(portainer.RBACExtension)
|
||||
if err != nil && err != portainer.ErrObjectNotFound {
|
||||
return errors.New("Unable to verify if RBAC extension is loaded")
|
||||
}
|
||||
|
||||
endpointResourceAccess := false
|
||||
_, ok := config.user.EndpointAuthorizations[portainer.EndpointID(config.endpoint.ID)][portainer.EndpointResourcesAccess]
|
||||
if ok {
|
||||
endpointResourceAccess = true
|
||||
}
|
||||
|
||||
mustBeChecked := false
|
||||
if rbacExtension != nil {
|
||||
if !config.isAdmin && !endpointResourceAccess {
|
||||
mustBeChecked = true
|
||||
}
|
||||
} else {
|
||||
if !config.isAdmin {
|
||||
mustBeChecked = true
|
||||
}
|
||||
}
|
||||
|
||||
if (!settings.AllowBindMountsForRegularUsers || !settings.AllowPrivilegedModeForRegularUsers) && mustBeChecked {
|
||||
composeFilePath := path.Join(config.stack.ProjectPath, config.stack.EntryPoint)
|
||||
|
||||
stackContent, err := handler.FileService.GetFileContent(composeFilePath)
|
||||
@@ -332,13 +361,10 @@ func (handler *Handler) deployComposeStack(config *composeStackDeploymentConfig)
|
||||
return err
|
||||
}
|
||||
|
||||
valid, err := handler.isValidStackFile(stackContent)
|
||||
err = handler.isValidStackFile(stackContent, settings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !valid {
|
||||
return errors.New("bind-mount disabled for non administrator users")
|
||||
}
|
||||
}
|
||||
|
||||
handler.stackCreationMutex.Lock()
|
||||
|
||||
Reference in New Issue
Block a user