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:
Maxime Bajeux
2020-06-30 07:13:37 +02:00
committed by GitHub
parent e1cc4bc9a1
commit 4c0d8ce732
5 changed files with 122 additions and 21 deletions
@@ -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()